summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Raghavan <arun@asymptotic.io>2020-10-12 18:08:02 -0400
committerArun Raghavan <arun@asymptotic.io>2020-10-23 13:30:23 -0400
commitbcec8b0b211ef3e7d5ca865f618b198029d67715 (patch)
tree78bf6de3df102f5e1a2d68586c580700e6e36f5f
parentb1b02581d3120733f3de7975654a930bbd8c5210 (diff)
Update to current webrtc library
This is from the upstream library commit id 3326535126e435f1ba647885ce43a8f0f3d317eb, corresponding to Chromium 88.0.4290.1.
-rw-r--r--README.md9
-rw-r--r--UPDATING.md4
-rw-r--r--meson.build62
-rw-r--r--meson_options.txt3
-rw-r--r--webrtc/BUILD.gn718
-rw-r--r--webrtc/LICENSE29
-rw-r--r--webrtc/LICENSE_THIRD_PARTY419
-rw-r--r--webrtc/api/array_view.h315
-rw-r--r--webrtc/api/audio/audio_frame.cc164
-rw-r--r--webrtc/api/audio/audio_frame.h177
-rw-r--r--webrtc/api/audio/channel_layout.cc282
-rw-r--r--webrtc/api/audio/channel_layout.h165
-rw-r--r--webrtc/api/audio/echo_canceller3_config.cc270
-rw-r--r--webrtc/api/audio/echo_canceller3_config.h228
-rw-r--r--webrtc/api/audio/echo_control.h68
-rw-r--r--webrtc/api/audio_codecs/audio_decoder.cc170
-rw-r--r--webrtc/api/audio_codecs/audio_decoder.h193
-rw-r--r--webrtc/api/audio_codecs/audio_encoder.cc113
-rw-r--r--webrtc/api/audio_codecs/audio_encoder.h257
-rw-r--r--webrtc/api/call/bitrate_allocation.h45
-rw-r--r--webrtc/api/function_view.h130
-rw-r--r--webrtc/api/meson.build46
-rw-r--r--webrtc/api/ref_counted_base.h43
-rw-r--r--webrtc/api/rtp_headers.cc (renamed from webrtc/common_types.cc)33
-rw-r--r--webrtc/api/rtp_headers.h190
-rw-r--r--webrtc/api/rtp_packet_info.cc60
-rw-r--r--webrtc/api/rtp_packet_info.h97
-rw-r--r--webrtc/api/rtp_packet_infos.h130
-rw-r--r--webrtc/api/scoped_refptr.h164
-rw-r--r--webrtc/api/task_queue/queued_task.h32
-rw-r--r--webrtc/api/task_queue/task_queue_base.cc79
-rw-r--r--webrtc/api/task_queue/task_queue_base.h83
-rw-r--r--webrtc/api/units/data_rate.cc34
-rw-r--r--webrtc/api/units/data_rate.h155
-rw-r--r--webrtc/api/units/data_size.cc30
-rw-r--r--webrtc/api/units/data_size.h66
-rw-r--r--webrtc/api/units/frequency.cc29
-rw-r--r--webrtc/api/units/frequency.h101
-rw-r--r--webrtc/api/units/time_delta.cc36
-rw-r--r--webrtc/api/units/time_delta.h105
-rw-r--r--webrtc/api/units/timestamp.cc34
-rw-r--r--webrtc/api/units/timestamp.h138
-rw-r--r--webrtc/api/video/color_space.cc187
-rw-r--r--webrtc/api/video/color_space.h178
-rw-r--r--webrtc/api/video/hdr_metadata.cc21
-rw-r--r--webrtc/api/video/hdr_metadata.h105
-rw-r--r--webrtc/api/video/video_content_type.cc93
-rw-r--r--webrtc/api/video/video_content_type.h39
-rw-r--r--webrtc/api/video/video_rotation.h26
-rw-r--r--webrtc/api/video/video_timing.cc92
-rw-r--r--webrtc/api/video/video_timing.h129
-rw-r--r--webrtc/audio/utility/BUILD.gn53
-rw-r--r--webrtc/audio/utility/audio_frame_operations.cc294
-rw-r--r--webrtc/audio/utility/audio_frame_operations.h105
-rw-r--r--webrtc/base/BUILD.gn596
-rw-r--r--webrtc/base/basictypes.h74
-rw-r--r--webrtc/base/checks.cc127
-rw-r--r--webrtc/base/checks.h229
-rw-r--r--webrtc/base/constructormagic.h34
-rw-r--r--webrtc/base/criticalsection.cc169
-rw-r--r--webrtc/base/criticalsection.h129
-rw-r--r--webrtc/base/event.cc135
-rw-r--r--webrtc/base/event.h53
-rw-r--r--webrtc/base/maybe.h110
-rw-r--r--webrtc/base/meson.build34
-rw-r--r--webrtc/base/platform_file.cc49
-rw-r--r--webrtc/base/platform_file.h44
-rw-r--r--webrtc/base/platform_thread.cc86
-rw-r--r--webrtc/base/scoped_ptr.h636
-rw-r--r--webrtc/base/stringutils.cc133
-rw-r--r--webrtc/base/stringutils.h318
-rw-r--r--webrtc/base/template_util.h127
-rw-r--r--webrtc/base/thread_annotations.h99
-rw-r--r--webrtc/base/thread_checker.h91
-rw-r--r--webrtc/base/thread_checker_impl.cc36
-rw-r--r--webrtc/base/thread_checker_impl.h48
-rw-r--r--webrtc/base/win32.h103
-rw-r--r--webrtc/common_audio/BUILD.gn361
-rw-r--r--webrtc/common_audio/audio_converter.cc153
-rw-r--r--webrtc/common_audio/audio_converter.h37
-rw-r--r--webrtc/common_audio/audio_ring_buffer.cc75
-rw-r--r--webrtc/common_audio/audio_ring_buffer.h56
-rw-r--r--webrtc/common_audio/audio_util.cc9
-rw-r--r--webrtc/common_audio/blocker.cc236
-rw-r--r--webrtc/common_audio/blocker.h123
-rw-r--r--webrtc/common_audio/channel_buffer.cc25
-rw-r--r--webrtc/common_audio/channel_buffer.h134
-rw-r--r--webrtc/common_audio/fft4g.c1332
-rw-r--r--webrtc/common_audio/fft4g.h25
-rw-r--r--webrtc/common_audio/fir_filter.cc116
-rw-r--r--webrtc/common_audio/fir_filter.h16
-rw-r--r--webrtc/common_audio/fir_filter_avx2.cc88
-rw-r--r--webrtc/common_audio/fir_filter_avx2.h41
-rw-r--r--webrtc/common_audio/fir_filter_c.cc61
-rw-r--r--webrtc/common_audio/fir_filter_c.h38
-rw-r--r--webrtc/common_audio/fir_filter_factory.cc58
-rw-r--r--webrtc/common_audio/fir_filter_factory.h32
-rw-r--r--webrtc/common_audio/fir_filter_neon.cc17
-rw-r--r--webrtc/common_audio/fir_filter_neon.h18
-rw-r--r--webrtc/common_audio/fir_filter_sse.cc14
-rw-r--r--webrtc/common_audio/fir_filter_sse.h20
-rw-r--r--webrtc/common_audio/include/audio_util.h98
-rw-r--r--webrtc/common_audio/lapped_transform.cc101
-rw-r--r--webrtc/common_audio/lapped_transform.h123
-rw-r--r--webrtc/common_audio/meson.build89
-rw-r--r--webrtc/common_audio/real_fourier.cc22
-rw-r--r--webrtc/common_audio/real_fourier.h23
-rw-r--r--webrtc/common_audio/real_fourier_ooura.cc26
-rw-r--r--webrtc/common_audio/real_fourier_ooura.h24
-rw-r--r--webrtc/common_audio/resampler/include/push_resampler.h37
-rw-r--r--webrtc/common_audio/resampler/include/resampler.h146
-rw-r--r--webrtc/common_audio/resampler/push_resampler.cc139
-rw-r--r--webrtc/common_audio/resampler/push_sinc_resampler.cc9
-rw-r--r--webrtc/common_audio/resampler/push_sinc_resampler.h27
-rw-r--r--webrtc/common_audio/resampler/resampler.cc1755
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler.cc120
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler.h67
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler_avx2.cc66
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler_neon.cc9
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler_sse.cc22
-rw-r--r--webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc7
-rw-r--r--webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h22
-rw-r--r--webrtc/common_audio/ring_buffer.c19
-rw-r--r--webrtc/common_audio/ring_buffer.h39
-rw-r--r--webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c2
-rw-r--r--webrtc/common_audio/signal_processing/auto_correlation.c6
-rw-r--r--webrtc/common_audio/signal_processing/complex_bit_reverse.c2
-rw-r--r--webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S2
-rw-r--r--webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c2
-rw-r--r--webrtc/common_audio/signal_processing/complex_fft.c15
-rw-r--r--webrtc/common_audio/signal_processing/complex_fft_mips.c4
-rw-r--r--webrtc/common_audio/signal_processing/complex_fft_tables.h252
-rw-r--r--webrtc/common_audio/signal_processing/copy_set_operations.c2
-rw-r--r--webrtc/common_audio/signal_processing/cross_correlation.c2
-rw-r--r--webrtc/common_audio/signal_processing/cross_correlation_mips.c2
-rw-r--r--webrtc/common_audio/signal_processing/cross_correlation_neon.c3
-rw-r--r--webrtc/common_audio/signal_processing/division_operations.c7
-rw-r--r--webrtc/common_audio/signal_processing/dot_product_with_scale.cc (renamed from webrtc/common_audio/signal_processing/dot_product_with_scale.c)8
-rw-r--r--webrtc/common_audio/signal_processing/dot_product_with_scale.h40
-rw-r--r--webrtc/common_audio/signal_processing/downsample_fast.c21
-rw-r--r--webrtc/common_audio/signal_processing/downsample_fast_mips.c2
-rw-r--r--webrtc/common_audio/signal_processing/downsample_fast_neon.c2
-rw-r--r--webrtc/common_audio/signal_processing/energy.c2
-rw-r--r--webrtc/common_audio/signal_processing/filter_ar.c26
-rw-r--r--webrtc/common_audio/signal_processing/filter_ar_fast_q12.c19
-rw-r--r--webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S2
-rw-r--r--webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c8
-rw-r--r--webrtc/common_audio/signal_processing/filter_ma_fast_q12.c14
-rw-r--r--webrtc/common_audio/signal_processing/get_hanning_window.c2
-rw-r--r--webrtc/common_audio/signal_processing/get_scaling_square.c2
-rw-r--r--webrtc/common_audio/signal_processing/ilbc_specific_functions.c6
-rw-r--r--webrtc/common_audio/signal_processing/include/real_fft.h15
-rw-r--r--webrtc/common_audio/signal_processing/include/signal_processing_library.h234
-rw-r--r--webrtc/common_audio/signal_processing/include/spl_inl.h194
-rw-r--r--webrtc/common_audio/signal_processing/include/spl_inl_armv7.h44
-rw-r--r--webrtc/common_audio/signal_processing/include/spl_inl_mips.h205
-rw-r--r--webrtc/common_audio/signal_processing/levinson_durbin.c51
-rw-r--r--webrtc/common_audio/signal_processing/lpc_to_refl_coef.c2
-rw-r--r--webrtc/common_audio/signal_processing/min_max_operations.c26
-rw-r--r--webrtc/common_audio/signal_processing/min_max_operations_mips.c17
-rw-r--r--webrtc/common_audio/signal_processing/min_max_operations_neon.c16
-rw-r--r--webrtc/common_audio/signal_processing/randomization_functions.c2
-rw-r--r--webrtc/common_audio/signal_processing/real_fft.c4
-rw-r--r--webrtc/common_audio/signal_processing/refl_coef_to_lpc.c2
-rw-r--r--webrtc/common_audio/signal_processing/resample.c4
-rw-r--r--webrtc/common_audio/signal_processing/resample_48khz.c4
-rw-r--r--webrtc/common_audio/signal_processing/resample_by_2.c8
-rw-r--r--webrtc/common_audio/signal_processing/resample_by_2_internal.c28
-rw-r--r--webrtc/common_audio/signal_processing/resample_by_2_internal.h55
-rw-r--r--webrtc/common_audio/signal_processing/resample_by_2_mips.c4
-rw-r--r--webrtc/common_audio/signal_processing/resample_fractional.c2
-rw-r--r--webrtc/common_audio/signal_processing/spl_init.c165
-rw-r--r--webrtc/common_audio/signal_processing/spl_inl.c24
-rw-r--r--webrtc/common_audio/signal_processing/spl_sqrt.c22
-rw-r--r--webrtc/common_audio/signal_processing/splitting_filter.c19
-rw-r--r--webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c2
-rw-r--r--webrtc/common_audio/signal_processing/vector_scaling_operations.c4
-rw-r--r--webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c2
-rw-r--r--webrtc/common_audio/smoothing_filter.cc147
-rw-r--r--webrtc/common_audio/smoothing_filter.h75
-rw-r--r--webrtc/common_audio/sparse_fir_filter.cc60
-rw-r--r--webrtc/common_audio/sparse_fir_filter.h52
-rw-r--r--webrtc/common_audio/third_party/ooura/BUILD.gn58
-rw-r--r--webrtc/common_audio/third_party/ooura/LICENSE8
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.cc (renamed from webrtc/modules/audio_processing/aec/aec_rdft.c)487
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.h64
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc1245
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc (renamed from webrtc/modules/audio_processing/aec/aec_rdft_neon.c)38
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc (renamed from webrtc/modules/audio_processing/aec/aec_rdft_sse2.c)116
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h54
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h98
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.cc866
-rw-r--r--webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.h21
-rw-r--r--webrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn24
-rw-r--r--webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE27
-rw-r--r--webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c (renamed from webrtc/common_audio/signal_processing/spl_sqrt_floor.c)2
-rw-r--r--webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h29
-rw-r--r--webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S (renamed from webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S)2
-rw-r--r--webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c (renamed from webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c)2
-rw-r--r--webrtc/common_audio/vad/include/vad.h16
-rw-r--r--webrtc/common_audio/vad/include/webrtc_vad.h23
-rw-r--r--webrtc/common_audio/vad/vad.cc13
-rw-r--r--webrtc/common_audio/vad/vad_core.c25
-rw-r--r--webrtc/common_audio/vad/vad_core.h79
-rw-r--r--webrtc/common_audio/vad/vad_filterbank.c22
-rw-r--r--webrtc/common_audio/vad/vad_filterbank.h15
-rw-r--r--webrtc/common_audio/vad/vad_gmm.c5
-rw-r--r--webrtc/common_audio/vad/vad_gmm.h8
-rw-r--r--webrtc/common_audio/vad/vad_sp.c14
-rw-r--r--webrtc/common_audio/vad/vad_sp.h10
-rw-r--r--webrtc/common_audio/vad/webrtc_vad.c8
-rw-r--r--webrtc/common_audio/wav_file.cc344
-rw-r--r--webrtc/common_audio/wav_file.h109
-rw-r--r--webrtc/common_audio/wav_header.cc447
-rw-r--r--webrtc/common_audio/wav_header.h80
-rw-r--r--webrtc/common_audio/window_generator.cc23
-rw-r--r--webrtc/common_audio/window_generator.h16
-rw-r--r--webrtc/common_types.h911
-rw-r--r--webrtc/meson.build34
-rw-r--r--webrtc/modules/BUILD.gn247
-rw-r--r--webrtc/modules/audio_coding/BUILD.gn1996
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_decoder.cc106
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_decoder.h117
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_encoder.cc55
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_encoder.h139
-rw-r--r--webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h (renamed from webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h)0
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h30
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h54
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h67
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h157
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h8
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h12
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h12
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/include/isac.h1293
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.c4
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.h60
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c18
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c11
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc4
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc4
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c40
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h239
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/codec.h78
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/crc.c5
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/crc.h15
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/decode.c15
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c8
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/encode.c30
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c12
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h98
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c46
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h66
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.c110
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.h23
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c37
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.h46
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/filterbanks.c238
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/intialize.c107
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/isac.c122
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h25
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.c409
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.h45
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c5
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c65
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h62
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c5
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h11
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c5
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h35
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c5
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h35
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c4
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.h45
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h15
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c88
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h65
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.c11
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.h42
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c5
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h17
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c4
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h26
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/settings.h237
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c4
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h21
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/structs.h397
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/transform.c9
-rw-r--r--webrtc/modules/audio_coding/meson.build33
-rw-r--r--webrtc/modules/audio_processing/BUILD.gn767
-rw-r--r--webrtc/modules/audio_processing/aec/aec_common.h32
-rw-r--r--webrtc/modules/audio_processing/aec/aec_core.c1929
-rw-r--r--webrtc/modules/audio_processing/aec/aec_core.h129
-rw-r--r--webrtc/modules/audio_processing/aec/aec_core_internal.h202
-rw-r--r--webrtc/modules/audio_processing/aec/aec_core_mips.c774
-rw-r--r--webrtc/modules/audio_processing/aec/aec_core_neon.c736
-rw-r--r--webrtc/modules/audio_processing/aec/aec_core_sse2.c731
-rw-r--r--webrtc/modules/audio_processing/aec/aec_rdft.h61
-rw-r--r--webrtc/modules/audio_processing/aec/aec_rdft_mips.c1187
-rw-r--r--webrtc/modules/audio_processing/aec/aec_resampler.c209
-rw-r--r--webrtc/modules/audio_processing/aec/aec_resampler.h39
-rw-r--r--webrtc/modules/audio_processing/aec/echo_cancellation.c923
-rw-r--r--webrtc/modules/audio_processing/aec/echo_cancellation_internal.h67
-rw-r--r--webrtc/modules/audio_processing/aec/include/echo_cancellation.h245
-rw-r--r--webrtc/modules/audio_processing/aec3/BUILD.gn367
-rw-r--r--webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc740
-rw-r--r--webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h191
-rw-r--r--webrtc/modules/audio_processing/aec3/adaptive_fir_filter_avx2.cc187
-rw-r--r--webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc102
-rw-r--r--webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.h54
-rw-r--r--webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl_avx2.cc37
-rw-r--r--webrtc/modules/audio_processing/aec3/aec3_common.cc58
-rw-r--r--webrtc/modules/audio_processing/aec3/aec3_common.h114
-rw-r--r--webrtc/modules/audio_processing/aec3/aec3_fft.cc144
-rw-r--r--webrtc/modules/audio_processing/aec3/aec3_fft.h75
-rw-r--r--webrtc/modules/audio_processing/aec3/aec_state.cc477
-rw-r--r--webrtc/modules/audio_processing/aec3/aec_state.h294
-rw-r--r--webrtc/modules/audio_processing/aec3/alignment_mixer.cc160
-rw-r--r--webrtc/modules/audio_processing/aec3/alignment_mixer.h58
-rw-r--r--webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.cc121
-rw-r--r--webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.h60
-rw-r--r--webrtc/modules/audio_processing/aec3/block_buffer.cc39
-rw-r--r--webrtc/modules/audio_processing/aec3/block_buffer.h62
-rw-r--r--webrtc/modules/audio_processing/aec3/block_delay_buffer.cc62
-rw-r--r--webrtc/modules/audio_processing/aec3/block_delay_buffer.h43
-rw-r--r--webrtc/modules/audio_processing/aec3/block_framer.cc86
-rw-r--r--webrtc/modules/audio_processing/aec3/block_framer.h48
-rw-r--r--webrtc/modules/audio_processing/aec3/block_processor.cc292
-rw-r--r--webrtc/modules/audio_processing/aec3/block_processor.h76
-rw-r--r--webrtc/modules/audio_processing/aec3/block_processor_metrics.cc104
-rw-r--r--webrtc/modules/audio_processing/aec3/block_processor_metrics.h47
-rw-r--r--webrtc/modules/audio_processing/aec3/clockdrift_detector.cc61
-rw-r--r--webrtc/modules/audio_processing/aec3/clockdrift_detector.h40
-rw-r--r--webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.cc103
-rw-r--r--webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.h74
-rw-r--r--webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc186
-rw-r--r--webrtc/modules/audio_processing/aec3/comfort_noise_generator.h78
-rw-r--r--webrtc/modules/audio_processing/aec3/decimator.cc91
-rw-r--r--webrtc/modules/audio_processing/aec3/decimator.h41
-rw-r--r--webrtc/modules/audio_processing/aec3/delay_estimate.h31
-rw-r--r--webrtc/modules/audio_processing/aec3/dominant_nearend_detector.cc75
-rw-r--r--webrtc/modules/audio_processing/aec3/dominant_nearend_detector.h56
-rw-r--r--webrtc/modules/audio_processing/aec3/downsampled_render_buffer.cc25
-rw-r--r--webrtc/modules/audio_processing/aec3/downsampled_render_buffer.h58
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_audibility.cc118
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_audibility.h86
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_canceller3.cc868
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_canceller3.h196
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.cc125
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.h79
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_path_variability.cc22
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_path_variability.h37
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_remover.cc500
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_remover.h55
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc246
-rw-r--r--webrtc/modules/audio_processing/aec3/echo_remover_metrics.h81
-rw-r--r--webrtc/modules/audio_processing/aec3/erl_estimator.cc146
-rw-r--r--webrtc/modules/audio_processing/aec3/erl_estimator.h57
-rw-r--r--webrtc/modules/audio_processing/aec3/erle_estimator.cc86
-rw-r--r--webrtc/modules/audio_processing/aec3/erle_estimator.h99
-rw-r--r--webrtc/modules/audio_processing/aec3/fft_buffer.cc27
-rw-r--r--webrtc/modules/audio_processing/aec3/fft_buffer.h60
-rw-r--r--webrtc/modules/audio_processing/aec3/fft_data.h104
-rw-r--r--webrtc/modules/audio_processing/aec3/fft_data_avx2.cc33
-rw-r--r--webrtc/modules/audio_processing/aec3/filter_analyzer.cc280
-rw-r--r--webrtc/modules/audio_processing/aec3/filter_analyzer.h149
-rw-r--r--webrtc/modules/audio_processing/aec3/frame_blocker.cc88
-rw-r--r--webrtc/modules/audio_processing/aec3/frame_blocker.h50
-rw-r--r--webrtc/modules/audio_processing/aec3/fullband_erle_estimator.cc200
-rw-r--r--webrtc/modules/audio_processing/aec3/fullband_erle_estimator.h118
-rw-r--r--webrtc/modules/audio_processing/aec3/matched_filter.cc464
-rw-r--r--webrtc/modules/audio_processing/aec3/matched_filter.h149
-rw-r--r--webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc132
-rw-r--r--webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc97
-rw-r--r--webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.h58
-rw-r--r--webrtc/modules/audio_processing/aec3/moving_average.cc60
-rw-r--r--webrtc/modules/audio_processing/aec3/moving_average.h45
-rw-r--r--webrtc/modules/audio_processing/aec3/nearend_detector.h42
-rw-r--r--webrtc/modules/audio_processing/aec3/refined_filter_update_gain.cc174
-rw-r--r--webrtc/modules/audio_processing/aec3/refined_filter_update_gain.h89
-rw-r--r--webrtc/modules/audio_processing/aec3/render_buffer.cc80
-rw-r--r--webrtc/modules/audio_processing/aec3/render_buffer.h116
-rw-r--r--webrtc/modules/audio_processing/aec3/render_delay_buffer.cc523
-rw-r--r--webrtc/modules/audio_processing/aec3/render_delay_buffer.h86
-rw-r--r--webrtc/modules/audio_processing/aec3/render_delay_controller.cc196
-rw-r--r--webrtc/modules/audio_processing/aec3/render_delay_controller.h50
-rw-r--r--webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.cc145
-rw-r--r--webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.h55
-rw-r--r--webrtc/modules/audio_processing/aec3/render_signal_analyzer.cc156
-rw-r--r--webrtc/modules/audio_processing/aec3/render_signal_analyzer.h62
-rw-r--r--webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc379
-rw-r--r--webrtc/modules/audio_processing/aec3/residual_echo_estimator.h78
-rw-r--r--webrtc/modules/audio_processing/aec3/reverb_decay_estimator.cc409
-rw-r--r--webrtc/modules/audio_processing/aec3/reverb_decay_estimator.h112
-rw-r--r--webrtc/modules/audio_processing/aec3/reverb_frequency_response.cc98
-rw-r--r--webrtc/modules/audio_processing/aec3/reverb_frequency_response.h53
-rw-r--r--webrtc/modules/audio_processing/aec3/reverb_model.cc59
-rw-r--r--webrtc/modules/audio_processing/aec3/reverb_model.h58
-rw-r--r--webrtc/modules/audio_processing/aec3/reverb_model_estimator.cc54
-rw-r--r--webrtc/modules/audio_processing/aec3/reverb_model_estimator.h67
-rw-r--r--webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc406
-rw-r--r--webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.h98
-rw-r--r--webrtc/modules/audio_processing/aec3/spectrum_buffer.cc30
-rw-r--r--webrtc/modules/audio_processing/aec3/spectrum_buffer.h62
-rw-r--r--webrtc/modules/audio_processing/aec3/stationarity_estimator.cc243
-rw-r--r--webrtc/modules/audio_processing/aec3/stationarity_estimator.h122
-rw-r--r--webrtc/modules/audio_processing/aec3/subband_erle_estimator.cc216
-rw-r--r--webrtc/modules/audio_processing/aec3/subband_erle_estimator.h93
-rw-r--r--webrtc/modules/audio_processing/aec3/subband_nearend_detector.cc70
-rw-r--r--webrtc/modules/audio_processing/aec3/subband_nearend_detector.h52
-rw-r--r--webrtc/modules/audio_processing/aec3/subtractor.cc325
-rw-r--r--webrtc/modules/audio_processing/aec3/subtractor.h137
-rw-r--r--webrtc/modules/audio_processing/aec3/subtractor_output.cc58
-rw-r--r--webrtc/modules/audio_processing/aec3/subtractor_output.h52
-rw-r--r--webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.cc57
-rw-r--r--webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.h44
-rw-r--r--webrtc/modules/audio_processing/aec3/suppression_filter.cc179
-rw-r--r--webrtc/modules/audio_processing/aec3/suppression_filter.h48
-rw-r--r--webrtc/modules/audio_processing/aec3/suppression_gain.cc438
-rw-r--r--webrtc/modules/audio_processing/aec3/suppression_gain.h130
-rw-r--r--webrtc/modules/audio_processing/aec3/transparent_mode.cc237
-rw-r--r--webrtc/modules/audio_processing/aec3/transparent_mode.h46
-rw-r--r--webrtc/modules/audio_processing/aec3/vector_math.h229
-rw-r--r--webrtc/modules/audio_processing/aec3/vector_math_avx2.cc82
-rw-r--r--webrtc/modules/audio_processing/aec_dump/BUILD.gn110
-rw-r--r--webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h48
-rw-r--r--webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc33
-rw-r--r--webrtc/modules/audio_processing/aecm/BUILD.gn44
-rw-r--r--webrtc/modules/audio_processing/aecm/aecm_core.c1233
-rw-r--r--webrtc/modules/audio_processing/aecm/aecm_core.cc1125
-rw-r--r--webrtc/modules/audio_processing/aecm/aecm_core.h217
-rw-r--r--webrtc/modules/audio_processing/aecm/aecm_core_c.cc (renamed from webrtc/modules/audio_processing/aecm/aecm_core_c.c)610
-rw-r--r--webrtc/modules/audio_processing/aecm/aecm_core_mips.c1566
-rw-r--r--webrtc/modules/audio_processing/aecm/aecm_core_mips.cc1656
-rw-r--r--webrtc/modules/audio_processing/aecm/aecm_core_neon.cc (renamed from webrtc/modules/audio_processing/aecm/aecm_core_neon.c)52
-rw-r--r--webrtc/modules/audio_processing/aecm/aecm_defines.h108
-rw-r--r--webrtc/modules/audio_processing/aecm/echo_control_mobile.c702
-rw-r--r--webrtc/modules/audio_processing/aecm/echo_control_mobile.cc599
-rw-r--r--webrtc/modules/audio_processing/aecm/echo_control_mobile.h (renamed from webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h)95
-rw-r--r--webrtc/modules/audio_processing/agc/BUILD.gn116
-rw-r--r--webrtc/modules/audio_processing/agc/agc.cc41
-rw-r--r--webrtc/modules/audio_processing/agc/agc.h31
-rw-r--r--webrtc/modules/audio_processing/agc/agc_manager_direct.cc597
-rw-r--r--webrtc/modules/audio_processing/agc/agc_manager_direct.h162
-rw-r--r--webrtc/modules/audio_processing/agc/gain_control.h105
-rw-r--r--webrtc/modules/audio_processing/agc/gain_map_internal.h285
-rw-r--r--webrtc/modules/audio_processing/agc/legacy/analog_agc.c1519
-rw-r--r--webrtc/modules/audio_processing/agc/legacy/analog_agc.cc1238
-rw-r--r--webrtc/modules/audio_processing/agc/legacy/analog_agc.h185
-rw-r--r--webrtc/modules/audio_processing/agc/legacy/digital_agc.c772
-rw-r--r--webrtc/modules/audio_processing/agc/legacy/digital_agc.cc714
-rw-r--r--webrtc/modules/audio_processing/agc/legacy/digital_agc.h95
-rw-r--r--webrtc/modules/audio_processing/agc/legacy/gain_control.h121
-rw-r--r--webrtc/modules/audio_processing/agc/loudness_histogram.cc (renamed from webrtc/modules/audio_processing/agc/histogram.cc)115
-rw-r--r--webrtc/modules/audio_processing/agc/loudness_histogram.h (renamed from webrtc/modules/audio_processing/agc/histogram.h)37
-rw-r--r--webrtc/modules/audio_processing/agc/mock_agc.h34
-rw-r--r--webrtc/modules/audio_processing/agc/utility.cc6
-rw-r--r--webrtc/modules/audio_processing/agc/utility.h10
-rw-r--r--webrtc/modules/audio_processing/agc2/BUILD.gn290
-rw-r--r--webrtc/modules/audio_processing/agc2/adaptive_agc.cc90
-rw-r--r--webrtc/modules/audio_processing/agc2/adaptive_agc.h50
-rw-r--r--webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc179
-rw-r--r--webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.h69
-rw-r--r--webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc198
-rw-r--r--webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.h86
-rw-r--r--webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc65
-rw-r--r--webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h51
-rw-r--r--webrtc/modules/audio_processing/agc2/agc2_common.h86
-rw-r--r--webrtc/modules/audio_processing/agc2/agc2_testing_common.cc33
-rw-r--r--webrtc/modules/audio_processing/agc2/agc2_testing_common.h78
-rw-r--r--webrtc/modules/audio_processing/agc2/biquad_filter.cc36
-rw-r--r--webrtc/modules/audio_processing/agc2/biquad_filter.h66
-rw-r--r--webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc229
-rw-r--r--webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.h48
-rw-r--r--webrtc/modules/audio_processing/agc2/down_sampler.cc99
-rw-r--r--webrtc/modules/audio_processing/agc2/down_sampler.h42
-rw-r--r--webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.cc112
-rw-r--r--webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.h65
-rw-r--r--webrtc/modules/audio_processing/agc2/fixed_gain_controller.cc101
-rw-r--r--webrtc/modules/audio_processing/agc2/gain_applier.cc102
-rw-r--r--webrtc/modules/audio_processing/agc2/gain_applier.h44
-rw-r--r--webrtc/modules/audio_processing/agc2/interpolated_gain_curve.cc195
-rw-r--r--webrtc/modules/audio_processing/agc2/interpolated_gain_curve.h152
-rw-r--r--webrtc/modules/audio_processing/agc2/limiter.cc150
-rw-r--r--webrtc/modules/audio_processing/agc2/limiter.h64
-rw-r--r--webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.cc138
-rw-r--r--webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.h76
-rw-r--r--webrtc/modules/audio_processing/agc2/noise_level_estimator.cc114
-rw-r--r--webrtc/modules/audio_processing/agc2/noise_level_estimator.h43
-rw-r--r--webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.cc70
-rw-r--r--webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.h42
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/BUILD.gn233
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.cc92
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.h49
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/common.cc34
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/common.h76
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.cc90
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.h62
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.cc138
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.h41
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/pitch_info.h29
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.cc56
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.h49
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc403
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h77
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/ring_buffer.h66
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/rnn.cc425
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/rnn.h126
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/rnn_vad_tool.cc120
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h79
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.cc213
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.h79
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc187
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h100
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h94
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.cc129
-rw-r--r--webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.h161
-rw-r--r--webrtc/modules/audio_processing/agc2/saturation_protector.cc121
-rw-r--r--webrtc/modules/audio_processing/agc2/saturation_protector.h82
-rw-r--r--webrtc/modules/audio_processing/agc2/signal_classifier.cc177
-rw-r--r--webrtc/modules/audio_processing/agc2/signal_classifier.h73
-rw-r--r--webrtc/modules/audio_processing/agc2/vad_with_level.cc114
-rw-r--r--webrtc/modules/audio_processing/agc2/vad_with_level.h58
-rw-r--r--webrtc/modules/audio_processing/agc2/vector_float_frame.cc39
-rw-r--r--webrtc/modules/audio_processing/agc2/vector_float_frame.h42
-rw-r--r--webrtc/modules/audio_processing/audio_buffer.cc689
-rw-r--r--webrtc/modules/audio_processing/audio_buffer.h235
-rw-r--r--webrtc/modules/audio_processing/audio_processing_builder_impl.cc45
-rw-r--r--webrtc/modules/audio_processing/audio_processing_impl.cc2648
-rw-r--r--webrtc/modules/audio_processing/audio_processing_impl.h654
-rw-r--r--webrtc/modules/audio_processing/beamformer/array_util.cc118
-rw-r--r--webrtc/modules/audio_processing/beamformer/array_util.h116
-rw-r--r--webrtc/modules/audio_processing/beamformer/beamformer.h48
-rw-r--r--webrtc/modules/audio_processing/beamformer/complex_matrix.h97
-rw-r--r--webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.cc114
-rw-r--r--webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h54
-rw-r--r--webrtc/modules/audio_processing/beamformer/matrix.h368
-rw-r--r--webrtc/modules/audio_processing/beamformer/matrix_test_helpers.h102
-rw-r--r--webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.cc570
-rw-r--r--webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h202
-rw-r--r--webrtc/modules/audio_processing/common.h17
-rw-r--r--webrtc/modules/audio_processing/debug.proto33
-rw-r--r--webrtc/modules/audio_processing/echo_cancellation_impl.cc389
-rw-r--r--webrtc/modules/audio_processing/echo_cancellation_impl.h86
-rw-r--r--webrtc/modules/audio_processing/echo_control_mobile_impl.cc364
-rw-r--r--webrtc/modules/audio_processing/echo_control_mobile_impl.h96
-rw-r--r--webrtc/modules/audio_processing/echo_detector/circular_buffer.cc49
-rw-r--r--webrtc/modules/audio_processing/echo_detector/circular_buffer.h44
-rw-r--r--webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.cc47
-rw-r--r--webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.h33
-rw-r--r--webrtc/modules/audio_processing/echo_detector/moving_max.cc52
-rw-r--r--webrtc/modules/audio_processing/echo_detector/moving_max.h36
-rw-r--r--webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.cc43
-rw-r--r--webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.h43
-rw-r--r--webrtc/modules/audio_processing/gain_control_impl.cc462
-rw-r--r--webrtc/modules/audio_processing/gain_control_impl.h98
-rw-r--r--webrtc/modules/audio_processing/gain_controller2.cc138
-rw-r--r--webrtc/modules/audio_processing/gain_controller2.h58
-rw-r--r--webrtc/modules/audio_processing/high_pass_filter.cc115
-rw-r--r--webrtc/modules/audio_processing/high_pass_filter.h45
-rw-r--r--webrtc/modules/audio_processing/high_pass_filter_impl.cc168
-rw-r--r--webrtc/modules/audio_processing/high_pass_filter_impl.h50
-rw-r--r--webrtc/modules/audio_processing/include/aec_dump.cc41
-rw-r--r--webrtc/modules/audio_processing/include/aec_dump.h114
-rw-r--r--webrtc/modules/audio_processing/include/audio_frame_proxies.cc70
-rw-r--r--webrtc/modules/audio_processing/include/audio_frame_proxies.h41
-rw-r--r--webrtc/modules/audio_processing/include/audio_frame_view.h67
-rw-r--r--webrtc/modules/audio_processing/include/audio_processing.cc124
-rw-r--r--webrtc/modules/audio_processing/include/audio_processing.h1197
-rw-r--r--webrtc/modules/audio_processing/include/audio_processing_statistics.cc22
-rw-r--r--webrtc/modules/audio_processing/include/audio_processing_statistics.h73
-rw-r--r--webrtc/modules/audio_processing/include/config.cc23
-rw-r--r--webrtc/modules/audio_processing/include/config.h (renamed from webrtc/common.h)81
-rw-r--r--webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc381
-rw-r--r--webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h184
-rw-r--r--webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc314
-rw-r--r--webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h160
-rw-r--r--webrtc/modules/audio_processing/level_estimator.cc29
-rw-r--r--webrtc/modules/audio_processing/level_estimator.h47
-rw-r--r--webrtc/modules/audio_processing/level_estimator_impl.cc86
-rw-r--r--webrtc/modules/audio_processing/level_estimator_impl.h53
-rw-r--r--webrtc/modules/audio_processing/logging/aec_logging.h86
-rw-r--r--webrtc/modules/audio_processing/logging/aec_logging_file_handling.cc57
-rw-r--r--webrtc/modules/audio_processing/logging/aec_logging_file_handling.h41
-rw-r--r--webrtc/modules/audio_processing/logging/apm_data_dumper.cc92
-rw-r--r--webrtc/modules/audio_processing/logging/apm_data_dumper.h287
-rw-r--r--webrtc/modules/audio_processing/meson.build235
-rw-r--r--webrtc/modules/audio_processing/noise_suppression_impl.cc181
-rw-r--r--webrtc/modules/audio_processing/noise_suppression_impl.h57
-rw-r--r--webrtc/modules/audio_processing/ns/BUILD.gn102
-rw-r--r--webrtc/modules/audio_processing/ns/defines.h49
-rw-r--r--webrtc/modules/audio_processing/ns/fast_math.cc84
-rw-r--r--webrtc/modules/audio_processing/ns/fast_math.h38
-rw-r--r--webrtc/modules/audio_processing/ns/histograms.cc47
-rw-r--r--webrtc/modules/audio_processing/ns/histograms.h55
-rw-r--r--webrtc/modules/audio_processing/ns/include/noise_suppression.h116
-rw-r--r--webrtc/modules/audio_processing/ns/include/noise_suppression_x.h88
-rw-r--r--webrtc/modules/audio_processing/ns/noise_estimator.cc195
-rw-r--r--webrtc/modules/audio_processing/ns/noise_estimator.h77
-rw-r--r--webrtc/modules/audio_processing/ns/noise_suppression.c59
-rw-r--r--webrtc/modules/audio_processing/ns/noise_suppression_x.c46
-rw-r--r--webrtc/modules/audio_processing/ns/noise_suppressor.cc549
-rw-r--r--webrtc/modules/audio_processing/ns/noise_suppressor.h83
-rw-r--r--webrtc/modules/audio_processing/ns/ns_common.h34
-rw-r--r--webrtc/modules/audio_processing/ns/ns_config.h24
-rw-r--r--webrtc/modules/audio_processing/ns/ns_core.c1416
-rw-r--r--webrtc/modules/audio_processing/ns/ns_core.h190
-rw-r--r--webrtc/modules/audio_processing/ns/ns_fft.cc64
-rw-r--r--webrtc/modules/audio_processing/ns/ns_fft.h45
-rw-r--r--webrtc/modules/audio_processing/ns/nsx_core.c2112
-rw-r--r--webrtc/modules/audio_processing/ns/nsx_core.h263
-rw-r--r--webrtc/modules/audio_processing/ns/nsx_core_c.c261
-rw-r--r--webrtc/modules/audio_processing/ns/nsx_core_mips.c1002
-rw-r--r--webrtc/modules/audio_processing/ns/nsx_core_neon.c598
-rw-r--r--webrtc/modules/audio_processing/ns/nsx_defines.h64
-rw-r--r--webrtc/modules/audio_processing/ns/prior_signal_model.cc18
-rw-r--r--webrtc/modules/audio_processing/ns/prior_signal_model.h32
-rw-r--r--webrtc/modules/audio_processing/ns/prior_signal_model_estimator.cc170
-rw-r--r--webrtc/modules/audio_processing/ns/prior_signal_model_estimator.h39
-rw-r--r--webrtc/modules/audio_processing/ns/quantile_noise_estimator.cc88
-rw-r--r--webrtc/modules/audio_processing/ns/quantile_noise_estimator.h45
-rw-r--r--webrtc/modules/audio_processing/ns/signal_model.cc24
-rw-r--r--webrtc/modules/audio_processing/ns/signal_model.h34
-rw-r--r--webrtc/modules/audio_processing/ns/signal_model_estimator.cc175
-rw-r--r--webrtc/modules/audio_processing/ns/signal_model_estimator.h58
-rw-r--r--webrtc/modules/audio_processing/ns/speech_probability_estimator.cc103
-rw-r--r--webrtc/modules/audio_processing/ns/speech_probability_estimator.h51
-rw-r--r--webrtc/modules/audio_processing/ns/suppression_params.cc49
-rw-r--r--webrtc/modules/audio_processing/ns/suppression_params.h30
-rw-r--r--webrtc/modules/audio_processing/ns/wiener_filter.cc120
-rw-r--r--webrtc/modules/audio_processing/ns/wiener_filter.h57
-rw-r--r--webrtc/modules/audio_processing/ns/windows_private.h574
-rw-r--r--webrtc/modules/audio_processing/optionally_built_submodule_creators.cc31
-rw-r--r--webrtc/modules/audio_processing/optionally_built_submodule_creators.h38
-rw-r--r--webrtc/modules/audio_processing/processing_component.cc111
-rw-r--r--webrtc/modules/audio_processing/processing_component.h53
-rw-r--r--webrtc/modules/audio_processing/render_queue_item_verifier.h36
-rw-r--r--webrtc/modules/audio_processing/residual_echo_detector.cc215
-rw-r--r--webrtc/modules/audio_processing/residual_echo_detector.h90
-rw-r--r--webrtc/modules/audio_processing/rms_level.cc127
-rw-r--r--webrtc/modules/audio_processing/rms_level.h56
-rw-r--r--webrtc/modules/audio_processing/splitting_filter.cc133
-rw-r--r--webrtc/modules/audio_processing/splitting_filter.h36
-rw-r--r--webrtc/modules/audio_processing/three_band_filter_bank.cc308
-rw-r--r--webrtc/modules/audio_processing/three_band_filter_bank.h65
-rw-r--r--webrtc/modules/audio_processing/transient/BUILD.gn112
-rw-r--r--webrtc/modules/audio_processing/transient/click_annotate.cc39
-rw-r--r--webrtc/modules/audio_processing/transient/common.h10
-rw-r--r--webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h59
-rw-r--r--webrtc/modules/audio_processing/transient/dyadic_decimator.h10
-rw-r--r--webrtc/modules/audio_processing/transient/file_utils.cc40
-rw-r--r--webrtc/modules/audio_processing/transient/file_utils.h9
-rw-r--r--webrtc/modules/audio_processing/transient/moving_moments.cc27
-rw-r--r--webrtc/modules/audio_processing/transient/moving_moments.h17
-rw-r--r--webrtc/modules/audio_processing/transient/transient_detector.cc47
-rw-r--r--webrtc/modules/audio_processing/transient/transient_detector.h22
-rw-r--r--webrtc/modules/audio_processing/transient/transient_suppressor.h104
-rw-r--r--webrtc/modules/audio_processing/transient/transient_suppressor_impl.cc (renamed from webrtc/modules/audio_processing/transient/transient_suppressor.cc)131
-rw-r--r--webrtc/modules/audio_processing/transient/transient_suppressor_impl.h123
-rw-r--r--webrtc/modules/audio_processing/transient/windows_private.h557
-rw-r--r--webrtc/modules/audio_processing/transient/wpd_node.cc27
-rw-r--r--webrtc/modules/audio_processing/transient/wpd_node.h13
-rw-r--r--webrtc/modules/audio_processing/transient/wpd_tree.cc33
-rw-r--r--webrtc/modules/audio_processing/transient/wpd_tree.h19
-rw-r--r--webrtc/modules/audio_processing/typing_detection.cc23
-rw-r--r--webrtc/modules/audio_processing/typing_detection.h11
-rw-r--r--webrtc/modules/audio_processing/utility/BUILD.gn81
-rw-r--r--webrtc/modules/audio_processing/utility/cascaded_biquad_filter.cc117
-rw-r--r--webrtc/modules/audio_processing/utility/cascaded_biquad_filter.h80
-rw-r--r--webrtc/modules/audio_processing/utility/delay_estimator.cc (renamed from webrtc/modules/audio_processing/utility/delay_estimator.c)190
-rw-r--r--webrtc/modules/audio_processing/utility/delay_estimator.h18
-rw-r--r--webrtc/modules/audio_processing/utility/delay_estimator_internal.h13
-rw-r--r--webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc (renamed from webrtc/modules/audio_processing/utility/delay_estimator_wrapper.c)100
-rw-r--r--webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h12
-rw-r--r--webrtc/modules/audio_processing/utility/pffft_wrapper.cc135
-rw-r--r--webrtc/modules/audio_processing/utility/pffft_wrapper.h94
-rw-r--r--webrtc/modules/audio_processing/vad/BUILD.gn69
-rw-r--r--webrtc/modules/audio_processing/vad/common.h8
-rw-r--r--webrtc/modules/audio_processing/vad/gmm.cc5
-rw-r--r--webrtc/modules/audio_processing/vad/gmm.h6
-rw-r--r--webrtc/modules/audio_processing/vad/noise_gmm_tables.h27
-rw-r--r--webrtc/modules/audio_processing/vad/pitch_based_vad.cc16
-rw-r--r--webrtc/modules/audio_processing/vad/pitch_based_vad.h18
-rw-r--r--webrtc/modules/audio_processing/vad/pitch_internal.cc6
-rw-r--r--webrtc/modules/audio_processing/vad/pitch_internal.h10
-rw-r--r--webrtc/modules/audio_processing/vad/pole_zero_filter.cc7
-rw-r--r--webrtc/modules/audio_processing/vad/pole_zero_filter.h11
-rw-r--r--webrtc/modules/audio_processing/vad/standalone_vad.cc14
-rw-r--r--webrtc/modules/audio_processing/vad/standalone_vad.h17
-rw-r--r--webrtc/modules/audio_processing/vad/vad_audio_proc.cc42
-rw-r--r--webrtc/modules/audio_processing/vad/vad_audio_proc.h57
-rw-r--r--webrtc/modules/audio_processing/vad/vad_audio_proc_internal.h33
-rw-r--r--webrtc/modules/audio_processing/vad/vad_circular_buffer.cc9
-rw-r--r--webrtc/modules/audio_processing/vad/vad_circular_buffer.h10
-rw-r--r--webrtc/modules/audio_processing/vad/voice_activity_detector.cc15
-rw-r--r--webrtc/modules/audio_processing/vad/voice_activity_detector.h28
-rw-r--r--webrtc/modules/audio_processing/vad/voice_gmm_tables.h22
-rw-r--r--webrtc/modules/audio_processing/voice_detection.cc92
-rw-r--r--webrtc/modules/audio_processing/voice_detection.h59
-rw-r--r--webrtc/modules/audio_processing/voice_detection_impl.cc176
-rw-r--r--webrtc/modules/audio_processing/voice_detection_impl.h64
-rw-r--r--webrtc/modules/interface/meson.build7
-rw-r--r--webrtc/modules/interface/module_common_types.h816
-rw-r--r--webrtc/modules/meson.build2
-rw-r--r--webrtc/modules/third_party/fft/BUILD.gn16
-rw-r--r--webrtc/modules/third_party/fft/LICENSE25
-rw-r--r--webrtc/modules/third_party/fft/fft.c (renamed from webrtc/modules/audio_coding/codecs/isac/main/source/fft.c)7
-rw-r--r--webrtc/modules/third_party/fft/fft.h (renamed from webrtc/modules/audio_coding/codecs/isac/main/source/fft.h)33
-rw-r--r--webrtc/modules/third_party/fft/meson.build13
-rw-r--r--webrtc/modules/utility/interface/audio_frame_operations.h58
-rw-r--r--webrtc/rtc_base/BUILD.gn1482
-rw-r--r--webrtc/rtc_base/arraysize.h (renamed from webrtc/base/arraysize.h)9
-rw-r--r--webrtc/rtc_base/atomic_ops.h (renamed from webrtc/base/atomicops.h)55
-rw-r--r--webrtc/rtc_base/buffer.h437
-rw-r--r--webrtc/rtc_base/checks.cc207
-rw-r--r--webrtc/rtc_base/checks.h485
-rw-r--r--webrtc/rtc_base/compile_assert_c.h (renamed from webrtc/system_wrappers/include/compile_assert_c.h)19
-rw-r--r--webrtc/rtc_base/constructor_magic.h20
-rw-r--r--webrtc/rtc_base/deprecation.h45
-rw-r--r--webrtc/rtc_base/event.cc203
-rw-r--r--webrtc/rtc_base/event.h86
-rw-r--r--webrtc/rtc_base/event_tracer.cc412
-rw-r--r--webrtc/rtc_base/event_tracer.h82
-rw-r--r--webrtc/rtc_base/experiments/field_trial_parser.cc247
-rw-r--r--webrtc/rtc_base/experiments/field_trial_parser.h288
-rw-r--r--webrtc/rtc_base/gtest_prod_util.h38
-rw-r--r--webrtc/rtc_base/ignore_wundef.h33
-rw-r--r--webrtc/rtc_base/logging.cc562
-rw-r--r--webrtc/rtc_base/logging.h712
-rw-r--r--webrtc/rtc_base/memory/BUILD.gn56
-rw-r--r--webrtc/rtc_base/memory/aligned_malloc.cc (renamed from webrtc/system_wrappers/source/aligned_malloc.cc)16
-rw-r--r--webrtc/rtc_base/memory/aligned_malloc.h (renamed from webrtc/system_wrappers/include/aligned_malloc.h)22
-rw-r--r--webrtc/rtc_base/meson.build64
-rw-r--r--webrtc/rtc_base/numerics/safe_compare.h176
-rw-r--r--webrtc/rtc_base/numerics/safe_conversions.h (renamed from webrtc/base/safe_conversions.h)28
-rw-r--r--webrtc/rtc_base/numerics/safe_conversions_impl.h (renamed from webrtc/base/safe_conversions_impl.h)135
-rw-r--r--webrtc/rtc_base/numerics/safe_minmax.h335
-rw-r--r--webrtc/rtc_base/platform_thread.cc192
-rw-r--r--webrtc/rtc_base/platform_thread.h104
-rw-r--r--webrtc/rtc_base/platform_thread_types.cc115
-rw-r--r--webrtc/rtc_base/platform_thread_types.h (renamed from webrtc/base/platform_thread.h)27
-rw-r--r--webrtc/rtc_base/race_checker.cc54
-rw-r--r--webrtc/rtc_base/race_checker.h78
-rw-r--r--webrtc/rtc_base/ref_count.h67
-rw-r--r--webrtc/rtc_base/ref_counted_object.h64
-rw-r--r--webrtc/rtc_base/ref_counter.h75
-rw-r--r--webrtc/rtc_base/sanitizer.h144
-rw-r--r--webrtc/rtc_base/string_encode.cc387
-rw-r--r--webrtc/rtc_base/string_encode.h154
-rw-r--r--webrtc/rtc_base/string_to_number.cc90
-rw-r--r--webrtc/rtc_base/string_to_number.h116
-rw-r--r--webrtc/rtc_base/string_utils.cc53
-rw-r--r--webrtc/rtc_base/string_utils.h93
-rw-r--r--webrtc/rtc_base/strings/string_builder.cc141
-rw-r--r--webrtc/rtc_base/strings/string_builder.h175
-rw-r--r--webrtc/rtc_base/swap_queue.h249
-rw-r--r--webrtc/rtc_base/synchronization/BUILD.gn138
-rw-r--r--webrtc/rtc_base/synchronization/mutex.cc39
-rw-r--r--webrtc/rtc_base/synchronization/mutex.h108
-rw-r--r--webrtc/rtc_base/synchronization/mutex_critical_section.h54
-rw-r--r--webrtc/rtc_base/synchronization/mutex_pthread.h53
-rw-r--r--webrtc/rtc_base/synchronization/rw_lock_posix.cc (renamed from webrtc/system_wrappers/source/rw_lock_posix.cc)7
-rw-r--r--webrtc/rtc_base/synchronization/rw_lock_posix.h (renamed from webrtc/system_wrappers/source/rw_lock_posix.h)11
-rw-r--r--webrtc/rtc_base/synchronization/rw_lock_win.cc41
-rw-r--r--webrtc/rtc_base/synchronization/rw_lock_win.h (renamed from webrtc/system_wrappers/source/rw_lock_win.h)20
-rw-r--r--webrtc/rtc_base/synchronization/rw_lock_wrapper.cc (renamed from webrtc/system_wrappers/source/rw_lock.cc)16
-rw-r--r--webrtc/rtc_base/synchronization/rw_lock_wrapper.h (renamed from webrtc/system_wrappers/include/rw_lock_wrapper.h)36
-rw-r--r--webrtc/rtc_base/synchronization/sequence_checker.cc112
-rw-r--r--webrtc/rtc_base/synchronization/sequence_checker.h187
-rw-r--r--webrtc/rtc_base/synchronization/yield.cc36
-rw-r--r--webrtc/rtc_base/synchronization/yield.h20
-rw-r--r--webrtc/rtc_base/synchronization/yield_policy.cc82
-rw-r--r--webrtc/rtc_base/synchronization/yield_policy.h38
-rw-r--r--webrtc/rtc_base/system/arch.h61
-rw-r--r--webrtc/rtc_base/system/asm_defines.h (renamed from webrtc/system_wrappers/include/asm_defines.h)12
-rw-r--r--webrtc/rtc_base/system/file_wrapper.cc127
-rw-r--r--webrtc/rtc_base/system/file_wrapper.h109
-rw-r--r--webrtc/rtc_base/system/ignore_warnings.h29
-rw-r--r--webrtc/rtc_base/system/inline.h31
-rw-r--r--webrtc/rtc_base/system/rtc_export.h43
-rw-r--r--webrtc/rtc_base/system/unused.h39
-rw-r--r--webrtc/rtc_base/system/warn_current_thread_is_deadlocked.h24
-rw-r--r--webrtc/rtc_base/thread_annotations.h95
-rw-r--r--webrtc/rtc_base/thread_checker.h27
-rw-r--r--webrtc/rtc_base/time_utils.cc327
-rw-r--r--webrtc/rtc_base/time_utils.h139
-rw-r--r--webrtc/rtc_base/trace_event.h1022
-rw-r--r--webrtc/rtc_base/type_traits.h140
-rw-r--r--webrtc/rtc_base/units/BUILD.gn33
-rw-r--r--webrtc/rtc_base/units/unit_base.h306
-rw-r--r--webrtc/rtc_base/win32.h104
-rw-r--r--webrtc/rtc_base/zero_memory.cc38
-rw-r--r--webrtc/rtc_base/zero_memory.h35
-rw-r--r--webrtc/system_wrappers/BUILD.gn252
-rw-r--r--webrtc/system_wrappers/include/aligned_array.h88
-rw-r--r--webrtc/system_wrappers/include/condition_variable_wrapper.h42
-rw-r--r--webrtc/system_wrappers/include/cpu_features_wrapper.h37
-rw-r--r--webrtc/system_wrappers/include/critical_section_wrapper.h54
-rw-r--r--webrtc/system_wrappers/include/event_wrapper.h70
-rw-r--r--webrtc/system_wrappers/include/field_trial.h102
-rw-r--r--webrtc/system_wrappers/include/file_wrapper.h78
-rw-r--r--webrtc/system_wrappers/include/fix_interlocked_exchange_pointer_win.h39
-rw-r--r--webrtc/system_wrappers/include/logging.h161
-rw-r--r--webrtc/system_wrappers/include/metrics.h417
-rw-r--r--webrtc/system_wrappers/include/scoped_vector.h157
-rw-r--r--webrtc/system_wrappers/include/sleep.h6
-rw-r--r--webrtc/system_wrappers/include/static_instance.h153
-rw-r--r--webrtc/system_wrappers/include/stl_util.h265
-rw-r--r--webrtc/system_wrappers/include/thread_wrapper.h95
-rw-r--r--webrtc/system_wrappers/include/trace.h92
-rw-r--r--webrtc/system_wrappers/meson.build41
-rw-r--r--webrtc/system_wrappers/source/condition_variable.cc41
-rw-r--r--webrtc/system_wrappers/source/condition_variable_event_win.cc195
-rw-r--r--webrtc/system_wrappers/source/condition_variable_event_win.h46
-rw-r--r--webrtc/system_wrappers/source/condition_variable_native_win.cc104
-rw-r--r--webrtc/system_wrappers/source/condition_variable_native_win.h54
-rw-r--r--webrtc/system_wrappers/source/cpu_features.cc73
-rw-r--r--webrtc/system_wrappers/source/critical_section.cc28
-rw-r--r--webrtc/system_wrappers/source/critical_section_posix.cc41
-rw-r--r--webrtc/system_wrappers/source/critical_section_posix.h36
-rw-r--r--webrtc/system_wrappers/source/critical_section_win.cc33
-rw-r--r--webrtc/system_wrappers/source/critical_section_win.h38
-rw-r--r--webrtc/system_wrappers/source/event.cc54
-rw-r--r--webrtc/system_wrappers/source/event_timer_posix.cc231
-rw-r--r--webrtc/system_wrappers/source/event_timer_posix.h60
-rw-r--r--webrtc/system_wrappers/source/event_timer_win.cc78
-rw-r--r--webrtc/system_wrappers/source/event_timer_win.h40
-rw-r--r--webrtc/system_wrappers/source/field_trial.cc155
-rw-r--r--webrtc/system_wrappers/source/file_impl.cc278
-rw-r--r--webrtc/system_wrappers/source/file_impl.h69
-rw-r--r--webrtc/system_wrappers/source/logging.cc62
-rw-r--r--webrtc/system_wrappers/source/metrics.cc328
-rw-r--r--webrtc/system_wrappers/source/metrics_default.cc29
-rw-r--r--webrtc/system_wrappers/source/rw_lock_generic.cc77
-rw-r--r--webrtc/system_wrappers/source/rw_lock_generic.h46
-rw-r--r--webrtc/system_wrappers/source/rw_lock_win.cc97
-rw-r--r--webrtc/system_wrappers/source/sleep.cc2
-rw-r--r--webrtc/system_wrappers/source/thread.cc33
-rw-r--r--webrtc/system_wrappers/source/thread_posix.cc166
-rw-r--r--webrtc/system_wrappers/source/thread_posix.h53
-rw-r--r--webrtc/system_wrappers/source/thread_win.cc107
-rw-r--r--webrtc/system_wrappers/source/thread_win.h48
-rw-r--r--webrtc/system_wrappers/source/trace_impl.cc604
-rw-r--r--webrtc/system_wrappers/source/trace_impl.h106
-rw-r--r--webrtc/system_wrappers/source/trace_posix.cc90
-rw-r--r--webrtc/system_wrappers/source/trace_posix.h39
-rw-r--r--webrtc/system_wrappers/source/trace_win.cc97
-rw-r--r--webrtc/system_wrappers/source/trace_win.h36
-rw-r--r--webrtc/third_party/pffft/BUILD.gn110
-rw-r--r--webrtc/third_party/pffft/LICENSE1
-rw-r--r--webrtc/third_party/pffft/meson.build21
-rw-r--r--webrtc/third_party/pffft/src/pffft.c1881
-rw-r--r--webrtc/third_party/pffft/src/pffft.h198
-rw-r--r--webrtc/third_party/rnnoise/BUILD.gn1
-rw-r--r--webrtc/third_party/rnnoise/COPYING1
-rw-r--r--webrtc/third_party/rnnoise/meson.build15
-rw-r--r--webrtc/third_party/rnnoise/src/rnn_activations.h102
-rw-r--r--webrtc/third_party/rnnoise/src/rnn_vad_weights.cc401
-rw-r--r--webrtc/third_party/rnnoise/src/rnn_vad_weights.h37
-rw-r--r--webrtc/typedefs.h111
859 files changed, 76136 insertions, 49529 deletions
diff --git a/README.md b/README.md
index 9133f17..ce885d4 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@ About
=====
This is meant to be a more Linux packaging friendly copy of the AudioProcessing
-module from the WebRTC[1][2] project. The ideal case is that we make no changes to
+module from the WebRTC[1] project. The ideal case is that we make no changes to
the code to make tracking upstream code easy.
This package currently only includes the AudioProcessing bits, but I am very
@@ -11,18 +11,17 @@ the code and hopefully eventually have a single point of packaging all the
WebRTC code to help people reuse the code and avoid keeping private copies in
several different projects.
-[1] http://code.google.com/p/webrtc/
-[2] https://chromium.googlesource.com/external/webrtc/trunk/webrtc.git
+[1] https://webrtc.googlesource.com/src
Feedback
========
Patches, suggestions welcome. You can send them to the PulseAudio mailing
-list[3] or to me at the address below.
+list[2] or to me at the address below.
-- Arun Raghavan <mail@arunraghavan.net>
-[3] http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
+[2] http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
Notes
====
diff --git a/UPDATING.md b/UPDATING.md
index 3f6a15a..ce851f9 100644
--- a/UPDATING.md
+++ b/UPDATING.md
@@ -8,7 +8,7 @@ project source code.
webrtc git repository Chromium uses.
2. Instructions on checking out the Chromium tree are on the
- [Chromium site][get-chromium]. As a shortcut, you can look at the DEPS file
+ [WebRTC repo][get-webrtc]. As a shortcut, you can look at the DEPS file
in the Chromium tree for the current webrtc version being used, and then
just use that commit hash with the webrtc tree.
@@ -61,6 +61,6 @@ project source code.
* Run some test streams through the canceller to make sure it is working
fine.
-[get-chromium]: http://dev.chromium.org/developers/how-tos/get-the-code
+[get-webrtc]: https://webrtc.googlesource.com/src/
[meld]: http://meldmerge.org/
[libtool-version-info]: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
diff --git a/meson.build b/meson.build
index 076f8f3..a15f2c6 100644
--- a/meson.build
+++ b/meson.build
@@ -1,12 +1,17 @@
project('webrtc-audio-processing', 'c', 'cpp',
- version : '0.3.1',
+ version : '0.4.0',
meson_version : '>= 0.52',
default_options : [ 'warning_level=1',
- 'buildtype=debugoptimized' ])
+ 'buildtype=debugoptimized',
+ 'c_std=c11',
+ 'cpp_std=c++14',
+ ]
+)
soversion = 0
cc = meson.get_compiler('c')
+cpp = meson.get_compiler('cpp')
host_system = host_machine.system()
@@ -16,14 +21,28 @@ os_deps = []
have_posix = false
have_win = false
+absl_dep = [
+ cpp.find_library('absl_base'),
+ cpp.find_library('absl_bad_optional_access'),
+ cpp.find_library('absl_flags_internal'),
+ cpp.find_library('absl_flags_marshalling'),
+ cpp.find_library('absl_flags_parse'),
+ cpp.find_library('absl_flags_registry'),
+ cpp.find_library('absl_flags_usage_internal'),
+ cpp.find_library('absl_raw_logging_internal'),
+ cpp.find_library('absl_strings'),
+ cpp.find_library('absl_synchronization'),
+ cpp.find_library('absl_throw_delegate'),
+]
+
if ['darwin', 'ios'].contains(host_system)
- os_cflags = ['-DWEBRTC_MAC', '-DWEBRTC_THREAD_RR', '-DWEBRTC_CLOCK_TYPE_REALTIME']
+ os_cflags = ['-DWEBRTC_MAC']
if host_system == 'ios'
os_cflags += ['-DWEBRTC_IOS']
endif
have_posix = true
elif host_system == 'android'
- os_cflags += ['-DWEBRTC_ANDROID', '-DWEBRTC_LINUX', '-DWEBRTC_THREAD_RR', '-DWEBRTC_CLOCK_TYPE_REALTIME']
+ os_cflags += ['-DWEBRTC_ANDROID', '-DWEBRTC_LINUX']
os_deps += [cc.find_library('log')]
os_deps += [dependency('gnustl', required : get_option('gnustl'))]
have_posix = true
@@ -46,7 +65,10 @@ arch_cflags = []
have_arm = false
have_armv7 = false
have_neon = false
+have_mips = false
+have_mips64 = false
have_x86 = false
+have_avx2 = false
if ['arm', 'armv7'].contains(host_machine.cpu_family())
if cc.compiles('''#ifdef __ARM_ARCH_ISA_ARM
#error no arm arch
@@ -67,8 +89,19 @@ if cc.compiles('''#ifndef __aarch64__
have_neon = true
arch_cflags += ['-DWEBRTC_ARCH_ARM64', '-DWEBRTC_HAS_NEON']
endif
+if ['mips', 'mips64'].contains(host_machine.cpu_family())
+ have_mips = true
+ arch_cflags += ['WEBRTC_ARCH_MIPS_FAMILY']
+endif
+if host_machine.cpu_family() == 'mips64'
+ have_mips64 = true
+endif
if ['x86', 'x86_64'].contains(host_machine.cpu_family())
have_x86 = true
+ # This is unconditionally enabled for now, actual usage is determined by
+ # runtime CPU detection, so we're just assuming the compiler supports avx2
+ have_avx2 = true
+ arch_cflags += ['-DWEBRTC_ENABLE_AVX2']
endif
neon_opt = get_option('neon')
@@ -84,16 +117,13 @@ if neon_opt != 'no'
endif
endif
-noise_cflags = []
-if get_option('ns_mode') == 'float'
- noise_cflags += ['-DWEBRTC_NS_FLOAT=1']
-else
- noise_cflags += ['-DWEBRTC_NS_FIXED=1']
-endif
-
-common_cflags = ['-DWEBRTC_AUDIO_PROCESSING_ONLY_BUILD', '-DNDEBUG'] + platform_cflags + os_cflags + arch_cflags + noise_cflags
-common_cxxflags = ['-std=c++11'] + common_cflags
-common_deps = os_deps
+common_cflags = [
+ '-DWEBRTC_LIBRARY_IMPL',
+ '-DWEBRTC_ENABLE_SYMBOL_EXPORT',
+ '-DNDEBUG'
+ ] + platform_cflags + os_cflags + arch_cflags
+common_cxxflags = common_cflags
+common_deps = os_deps + [absl_dep]
webrtc_inc = include_directories('.')
subdir('webrtc')
@@ -107,7 +137,7 @@ pkgconfig.generate(
filebase: 'webrtc-audio-processing',
subdirs: 'webrtc_audio_processing',
extra_cflags: [
- '-DWEBRTC_AUDIO_PROCESSING_ONLY_BUILD',
+ '-DWEBRTC_LIBRARY_IMPL',
] + platform_cflags,
libraries: libwebrtc_audio_processing,
)
@@ -119,7 +149,7 @@ pkgconfig.generate(
filebase: 'webrtc-audio-coding',
subdirs: 'webrtc_audio_processing',
extra_cflags: [
- '-DWEBRTC_AUDIO_PROCESSING_ONLY_BUILD',
+ '-DWEBRTC_LIBRARY_IMPL',
] + platform_cflags,
libraries: libwebrtc_audio_coding,
)
diff --git a/meson_options.txt b/meson_options.txt
index cfcd3fa..c939fb9 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,6 +1,3 @@
-option('ns_mode', type: 'combo',
- choices : ['float', 'fixed'],
- description: 'Noise suppresion mode to use.')
option('gnustl', type: 'feature',
value: 'auto',
description: 'Use gnustl for a c++ library implementation (only used on Android)')
diff --git a/webrtc/BUILD.gn b/webrtc/BUILD.gn
index ac14d7d..cec97c5 100644
--- a/webrtc/BUILD.gn
+++ b/webrtc/BUILD.gn
@@ -6,22 +6,146 @@
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
-# TODO(kjellander): Rebase this to webrtc/build/common.gypi changes after r6330.
+# This is the root build file for GN. GN will start processing by loading this
+# file, and recursively load all dependencies until all dependencies are either
+# resolved or known not to exist (which will cause the build to fail). So if
+# you add a new build file, there must be some path of dependencies from this
+# file to your new one or GN won't know about it.
-import("//build/config/crypto.gni")
import("//build/config/linux/pkg_config.gni")
-import("build/webrtc.gni")
-import("//third_party/protobuf/proto_library.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+import("webrtc.gni")
+if (rtc_enable_protobuf) {
+ import("//third_party/protobuf/proto_library.gni")
+}
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+if (!build_with_chromium) {
+ # This target should (transitively) cause everything to be built; if you run
+ # 'ninja default' and then 'ninja all', the second build should do no work.
+ group("default") {
+ testonly = true
+ deps = [ ":webrtc" ]
+ if (rtc_build_examples) {
+ deps += [ "examples" ]
+ }
+ if (rtc_build_tools) {
+ deps += [ "rtc_tools" ]
+ }
+ if (rtc_include_tests) {
+ deps += [
+ ":rtc_unittests",
+ ":slow_tests",
+ ":video_engine_tests",
+ ":voip_unittests",
+ ":webrtc_nonparallel_tests",
+ ":webrtc_perf_tests",
+ "common_audio:common_audio_unittests",
+ "common_video:common_video_unittests",
+ "examples:examples_unittests",
+ "media:rtc_media_unittests",
+ "modules:modules_tests",
+ "modules:modules_unittests",
+ "modules/audio_coding:audio_coding_tests",
+ "modules/audio_processing:audio_processing_tests",
+ "modules/remote_bitrate_estimator:rtp_to_text",
+ "modules/rtp_rtcp:test_packet_masks_metrics",
+ "modules/video_capture:video_capture_internal_impl",
+ "pc:peerconnection_unittests",
+ "pc:rtc_pc_unittests",
+ "rtc_tools:rtp_generator",
+ "rtc_tools:video_replay",
+ "stats:rtc_stats_unittests",
+ "system_wrappers:system_wrappers_unittests",
+ "test",
+ "video:screenshare_loopback",
+ "video:sv_loopback",
+ "video:video_loopback",
+ ]
+ if (!is_asan) {
+ # Do not build :webrtc_lib_link_test because lld complains on some OS
+ # (e.g. when target_os = "mac") when is_asan=true. For more details,
+ # see bugs.webrtc.org/11027#c5.
+ deps += [ ":webrtc_lib_link_test" ]
+ }
+ if (is_android) {
+ deps += [
+ "examples:android_examples_junit_tests",
+ "sdk/android:android_instrumentation_test_apk",
+ "sdk/android:android_sdk_junit_tests",
+ ]
+ } else {
+ deps += [ "modules/video_capture:video_capture_tests" ]
+ }
+ if (rtc_enable_protobuf) {
+ deps += [
+ "audio:low_bandwidth_audio_test",
+ "logging:rtc_event_log_rtp_dump",
+ "tools_webrtc/perf:webrtc_dashboard_upload",
+ ]
+ }
+ }
+ }
+}
+
+# Abseil Flags by default doesn't register command line flags on mobile
+# platforms, WebRTC tests requires them (e.g. on simualtors) so this
+# config will be applied to testonly targets globally (see webrtc.gni).
+config("absl_flags_configs") {
+ defines = [ "ABSL_FLAGS_STRIP_NAMES=0" ]
+}
+
+config("library_impl_config") {
+ # Build targets that contain WebRTC implementation need this macro to
+ # be defined in order to correctly export symbols when is_component_build
+ # is true.
+ # For more info see: rtc_base/build/rtc_export.h.
+ defines = [ "WEBRTC_LIBRARY_IMPL" ]
+}
# Contains the defines and includes in common.gypi that are duplicated both as
# target_defaults and direct_dependent_settings.
config("common_inherited_config") {
defines = []
+ cflags = []
+ ldflags = []
+
+ if (rtc_enable_symbol_export || is_component_build) {
+ defines = [ "WEBRTC_ENABLE_SYMBOL_EXPORT" ]
+ }
+
if (build_with_mozilla) {
defines += [ "WEBRTC_MOZILLA_BUILD" ]
}
+
+ if (!rtc_builtin_ssl_root_certificates) {
+ defines += [ "WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS" ]
+ }
+
+ if (rtc_disable_check_msg) {
+ defines += [ "RTC_DISABLE_CHECK_MSG" ]
+ }
+
+ if (rtc_enable_avx2) {
+ defines += [ "WEBRTC_ENABLE_AVX2" ]
+ }
+
+ # Some tests need to declare their own trace event handlers. If this define is
+ # not set, the first time TRACE_EVENT_* is called it will store the return
+ # value for the current handler in an static variable, so that subsequent
+ # changes to the handler for that TRACE_EVENT_* will be ignored.
+ # So when tests are included, we set this define, making it possible to use
+ # different event handlers in different tests.
+ if (rtc_include_tests) {
+ defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=1" ]
+ } else {
+ defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0" ]
+ }
if (build_with_chromium) {
- defines = [ "WEBRTC_CHROMIUM_BUILD" ]
+ defines += [ "WEBRTC_CHROMIUM_BUILD" ]
include_dirs = [
# The overrides must be included first as that is the mechanism for
# selecting the override headers in Chromium.
@@ -29,10 +153,18 @@ config("common_inherited_config") {
# Allow includes to be prefixed with webrtc/ in case it is not an
# immediate subdirectory of the top-level.
- "..",
+ ".",
+
+ # Just like the root WebRTC directory is added to include path, the
+ # corresponding directory tree with generated files needs to be added too.
+ # Note: this path does not change depending on the current target, e.g.
+ # it is always "//gen/third_party/webrtc" when building with Chromium.
+ # See also: http://cs.chromium.org/?q=%5C"default_include_dirs
+ # https://gn.googlesource.com/gn/+/master/docs/reference.md#target_gen_dir
+ target_gen_dir,
]
}
- if (is_posix) {
+ if (is_posix || is_fuchsia) {
defines += [ "WEBRTC_POSIX" ]
}
if (is_ios) {
@@ -41,15 +173,15 @@ config("common_inherited_config") {
"WEBRTC_IOS",
]
}
- if (is_ios && rtc_use_objc_h264) {
- defines += [ "WEBRTC_OBJC_H264" ]
- }
- if (is_linux) {
+ if (is_linux || is_chromeos) {
defines += [ "WEBRTC_LINUX" ]
}
if (is_mac) {
defines += [ "WEBRTC_MAC" ]
}
+ if (is_fuchsia) {
+ defines += [ "WEBRTC_FUCHSIA" ]
+ }
if (is_win) {
defines += [ "WEBRTC_WIN" ]
}
@@ -58,63 +190,173 @@ config("common_inherited_config") {
"WEBRTC_LINUX",
"WEBRTC_ANDROID",
]
+
+ if (build_with_mozilla) {
+ defines += [ "WEBRTC_ANDROID_OPENSLES" ]
+ }
+ }
+ if (is_chromeos) {
+ defines += [ "CHROMEOS" ]
+ }
+
+ if (rtc_sanitize_coverage != "") {
+ assert(is_clang, "sanitizer coverage requires clang")
+ cflags += [ "-fsanitize-coverage=${rtc_sanitize_coverage}" ]
+ ldflags += [ "-fsanitize-coverage=${rtc_sanitize_coverage}" ]
+ }
+
+ if (is_ubsan) {
+ cflags += [ "-fsanitize=float-cast-overflow" ]
+ }
+}
+
+# TODO(bugs.webrtc.org/9693): Remove the possibility to suppress this warning
+# as soon as WebRTC compiles without it.
+config("no_exit_time_destructors") {
+ if (is_clang) {
+ cflags = [ "-Wno-exit-time-destructors" ]
+ }
+}
+
+# TODO(bugs.webrtc.org/9693): Remove the possibility to suppress this warning
+# as soon as WebRTC compiles without it.
+config("no_global_constructors") {
+ if (is_clang) {
+ cflags = [ "-Wno-global-constructors" ]
}
}
-if (rtc_have_dbus_glib) {
- pkg_config("dbus-glib") {
- packages = [ "dbus-glib-1" ]
+config("rtc_prod_config") {
+ # Ideally, WebRTC production code (but not test code) should have these flags.
+ if (is_clang) {
+ cflags = [
+ "-Wexit-time-destructors",
+ "-Wglobal-constructors",
+ ]
}
}
config("common_config") {
cflags = []
+ cflags_c = []
cflags_cc = []
- if (rtc_restrict_logging) {
- defines = [ "WEBRTC_RESTRICT_LOGGING" ]
+ cflags_objc = []
+ defines = []
+
+ if (rtc_enable_protobuf) {
+ defines += [ "WEBRTC_ENABLE_PROTOBUF=1" ]
+ } else {
+ defines += [ "WEBRTC_ENABLE_PROTOBUF=0" ]
+ }
+
+ if (rtc_include_internal_audio_device) {
+ defines += [ "WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE" ]
+ }
+
+ if (rtc_libvpx_build_vp9) {
+ defines += [ "RTC_ENABLE_VP9" ]
+ }
+
+ if (rtc_enable_sctp) {
+ defines += [ "HAVE_SCTP" ]
+ }
+
+ if (rtc_enable_external_auth) {
+ defines += [ "ENABLE_EXTERNAL_AUTH" ]
+ }
+
+ if (rtc_use_h264) {
+ defines += [ "WEBRTC_USE_H264" ]
+ }
+
+ if (rtc_use_absl_mutex) {
+ defines += [ "WEBRTC_ABSL_MUTEX" ]
+ }
+
+ if (rtc_disable_logging) {
+ defines += [ "RTC_DISABLE_LOGGING" ]
+ }
+
+ if (rtc_disable_trace_events) {
+ defines += [ "RTC_DISABLE_TRACE_EVENTS" ]
+ }
+
+ if (rtc_disable_metrics) {
+ defines += [ "RTC_DISABLE_METRICS" ]
}
- if (rtc_have_dbus_glib) {
- defines += [ "HAVE_DBUS_GLIB" ]
+ if (rtc_exclude_transient_suppressor) {
+ defines += [ "WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR" ]
+ }
- # TODO(kjellander): Investigate this, it seems like include <dbus/dbus.h>
- # is still not found even if the execution of
- # build/config/linux/pkg-config.py dbus-glib-1 returns correct include
- # dirs on Linux.
- all_dependent_configs = [ "dbus-glib" ]
+ if (rtc_exclude_audio_processing_module) {
+ defines += [ "WEBRTC_EXCLUDE_AUDIO_PROCESSING_MODULE" ]
}
+ cflags = []
+
if (build_with_chromium) {
- defines += [ "LOGGING_INSIDE_WEBRTC" ]
+ defines += [
+ # NOTICE: Since common_inherited_config is used in public_configs for our
+ # targets, there's no point including the defines in that config here.
+ # TODO(kjellander): Cleanup unused ones and move defines closer to the
+ # source when webrtc:4256 is completed.
+ "HAVE_WEBRTC_VIDEO",
+ "LOGGING_INSIDE_WEBRTC",
+ ]
} else {
- if (is_posix) {
- # -Wextra is currently disabled in Chromium"s common.gypi. Enable
- # for targets that can handle it. For Android/arm64 right now
- # there will be an "enumeral and non-enumeral type in conditional
- # expression" warning in android_tools/ndk_experimental"s version
- # of stlport.
- # See: https://code.google.com/p/chromium/issues/detail?id=379699
- if (current_cpu != "arm64" || !is_android) {
- cflags = [
- "-Wextra",
-
- # We need to repeat some flags from Chromium"s common.gypi
- # here that get overridden by -Wextra.
- "-Wno-unused-parameter",
- "-Wno-missing-field-initializers",
- "-Wno-strict-overflow",
- ]
- cflags_cc = [
- "-Wnon-virtual-dtor",
+ if (is_posix || is_fuchsia) {
+ cflags_c += [
+ # TODO(bugs.webrtc.org/9029): enable commented compiler flags.
+ # Some of these flags should also be added to cflags_objc.
- # This is enabled for clang; enable for gcc as well.
- "-Woverloaded-virtual",
- ]
- }
+ # "-Wextra", (used when building C++ but not when building C)
+ # "-Wmissing-prototypes", (C/Obj-C only)
+ # "-Wmissing-declarations", (ensure this is always used C/C++, etc..)
+ "-Wstrict-prototypes",
+
+ # "-Wpointer-arith", (ensure this is always used C/C++, etc..)
+ # "-Wbad-function-cast", (C/Obj-C only)
+ # "-Wnested-externs", (C/Obj-C only)
+ ]
+ cflags_objc += [ "-Wstrict-prototypes" ]
+ cflags_cc = [
+ "-Wnon-virtual-dtor",
+
+ # This is enabled for clang; enable for gcc as well.
+ "-Woverloaded-virtual",
+ ]
}
if (is_clang) {
- cflags += [ "-Wthread-safety" ]
+ cflags += [
+ "-Wc++11-narrowing",
+ "-Wimplicit-fallthrough",
+ "-Wthread-safety",
+ "-Winconsistent-missing-override",
+ "-Wundef",
+ ]
+
+ # use_xcode_clang only refers to the iOS toolchain, host binaries use
+ # chromium's clang always.
+ if (!is_nacl &&
+ (!use_xcode_clang || current_toolchain == host_toolchain)) {
+ # Flags NaCl (Clang 3.7) and Xcode 7.3 (Clang clang-703.0.31) do not
+ # recognize.
+ cflags += [ "-Wunused-lambda-capture" ]
+ }
+ }
+
+ if (is_win && !is_clang) {
+ # MSVC warning suppressions (needed to use Abseil).
+ # TODO(bugs.webrtc.org/9274): Remove these warnings as soon as MSVC allows
+ # external headers warning suppression (or fix them upstream).
+ cflags += [ "/wd4702" ] # unreachable code
+
+ # MSVC 2019 warning suppressions for C++17 compiling
+ cflags +=
+ [ "/wd5041" ] # out-of-line definition for constexpr static data
+ # member is not needed and is deprecated in C++17
}
}
@@ -129,8 +371,6 @@ config("common_config") {
defines += [ "WEBRTC_ARCH_ARM_V7" ]
if (arm_use_neon) {
defines += [ "WEBRTC_HAS_NEON" ]
- } else if (arm_optionally_use_neon) {
- defines += [ "WEBRTC_DETECT_NEON" ]
}
}
}
@@ -163,119 +403,325 @@ config("common_config") {
"-fno-builtin-sinf",
]
}
-}
-
-source_set("webrtc") {
- sources = [
- "call.h",
- "config.h",
- "frame_callback.h",
- "transport.h",
- ]
- defines = []
- configs += [ ":common_config" ]
- public_configs = [ ":common_inherited_config" ]
-
- deps = [
- "audio",
- ":webrtc_common",
- "base:rtc_base",
- "call",
- "common_audio",
- "common_video",
- "modules/audio_coding",
- "modules/audio_conference_mixer",
- "modules/audio_device",
- "modules/audio_processing",
- "modules/bitrate_controller",
- "modules/desktop_capture",
- "modules/media_file",
- "modules/rtp_rtcp",
- "modules/utility",
- "modules/video_coding",
- "modules/video_processing",
- "system_wrappers",
- "tools",
- "video",
- "voice_engine",
- ]
+ if (use_fuzzing_engine && optimize_for_fuzzing) {
+ # Used in Chromium's overrides to disable logging
+ defines += [ "WEBRTC_UNSAFE_FUZZER_MODE" ]
+ }
- if (build_with_chromium) {
- deps += [
- "modules/video_capture",
- "modules/video_render",
+ if (!build_with_chromium && rtc_win_undef_unicode) {
+ cflags += [
+ "/UUNICODE",
+ "/U_UNICODE",
]
}
+}
- if (rtc_enable_protobuf) {
- defines += [ "ENABLE_RTC_EVENT_LOG" ]
- deps += [ ":rtc_event_log_proto" ]
+config("common_objc") {
+ frameworks = [ "Foundation.framework" ]
+
+ if (rtc_use_metal_rendering) {
+ defines = [ "RTC_SUPPORTS_METAL" ]
}
}
if (!build_with_chromium) {
- executable("webrtc_tests") {
- testonly = true
+ # Target to build all the WebRTC production code.
+ rtc_static_library("webrtc") {
+ # Only the root target and the test should depend on this.
+ visibility = [
+ "//:default",
+ "//:webrtc_lib_link_test",
+ ]
+
+ sources = []
+ complete_static_lib = true
+ suppressed_configs += [ "//build/config/compiler:thin_archive" ]
+ defines = []
+
deps = [
- ":webrtc",
- "modules/video_render:video_render_internal_impl",
+ "api:create_peerconnection_factory",
+ "api:libjingle_peerconnection_api",
+ "api:rtc_error",
+ "api:transport_api",
+ "api/crypto",
+ "api/rtc_event_log:rtc_event_log_factory",
+ "api/task_queue",
+ "api/task_queue:default_task_queue_factory",
+ "audio",
+ "call",
+ "common_audio",
+ "common_video",
+ "logging:rtc_event_log_api",
+ "media",
+ "modules",
"modules/video_capture:video_capture_internal_impl",
- "test",
+ "p2p:rtc_p2p",
+ "pc:libjingle_peerconnection",
+ "pc:peerconnection",
+ "pc:rtc_pc",
+ "pc:rtc_pc_base",
+ "rtc_base",
+ "sdk",
+ "video",
]
+
+ if (rtc_include_builtin_audio_codecs) {
+ deps += [
+ "api/audio_codecs:builtin_audio_decoder_factory",
+ "api/audio_codecs:builtin_audio_encoder_factory",
+ ]
+ }
+
+ if (rtc_include_builtin_video_codecs) {
+ deps += [
+ "api/video_codecs:builtin_video_decoder_factory",
+ "api/video_codecs:builtin_video_encoder_factory",
+ ]
+ }
+
+ if (build_with_mozilla) {
+ deps += [
+ "api/video:video_frame",
+ "api/video:video_rtp_headers",
+ ]
+ } else {
+ deps += [
+ "api",
+ "logging",
+ "p2p",
+ "pc",
+ "stats",
+ ]
+ }
+
+ if (rtc_enable_protobuf) {
+ deps += [ "logging:rtc_event_log_proto" ]
+ }
}
-}
-source_set("webrtc_common") {
- sources = [
- "common_types.cc",
- "common_types.h",
- "config.cc",
- "config.h",
- "engine_configurations.h",
- "typedefs.h",
- ]
+ if (rtc_include_tests && !is_asan) {
+ rtc_executable("webrtc_lib_link_test") {
+ testonly = true
- configs += [ ":common_config" ]
- public_configs = [ ":common_inherited_config" ]
+ sources = [ "webrtc_lib_link_test.cc" ]
+ deps = [
+ # NOTE: Don't add deps here. If this test fails to link, it means you
+ # need to add stuff to the webrtc static lib target above.
+ ":webrtc",
+ ]
+ }
+ }
}
-source_set("gtest_prod") {
- sources = [
- "test/testsupport/gtest_prod_util.h",
- ]
+if (use_libfuzzer || use_afl) {
+ # This target is only here for gn to discover fuzzer build targets under
+ # webrtc/test/fuzzers/.
+ group("webrtc_fuzzers_dummy") {
+ testonly = true
+ deps = [ "test/fuzzers:webrtc_fuzzer_main" ]
+ }
}
-if (rtc_enable_protobuf) {
- proto_library("rtc_event_log_proto") {
- sources = [
- "call/rtc_event_log.proto",
+if (rtc_include_tests) {
+ rtc_test("rtc_unittests") {
+ testonly = true
+
+ deps = [
+ "api:compile_all_headers",
+ "api:rtc_api_unittests",
+ "api/audio/test:audio_api_unittests",
+ "api/audio_codecs/test:audio_codecs_api_unittests",
+ "api/numerics:numerics_unittests",
+ "api/transport:stun_unittest",
+ "api/video/test:rtc_api_video_unittests",
+ "api/video_codecs/test:video_codecs_api_unittests",
+ "call:fake_network_pipe_unittests",
+ "p2p:libstunprober_unittests",
+ "p2p:rtc_p2p_unittests",
+ "rtc_base:robo_caller_unittests",
+ "rtc_base:rtc_base_approved_unittests",
+ "rtc_base:rtc_base_unittests",
+ "rtc_base:rtc_json_unittests",
+ "rtc_base:rtc_numerics_unittests",
+ "rtc_base:rtc_operations_chain_unittests",
+ "rtc_base:rtc_task_queue_unittests",
+ "rtc_base:sigslot_unittest",
+ "rtc_base:untyped_function_unittest",
+ "rtc_base:weak_ptr_unittests",
+ "rtc_base/experiments:experiments_unittests",
+ "rtc_base/synchronization:sequence_checker_unittests",
+ "rtc_base/task_utils:pending_task_safety_flag_unittests",
+ "rtc_base/task_utils:to_queued_task_unittests",
+ "sdk:sdk_tests",
+ "test:rtp_test_utils",
+ "test:test_main",
+ "test/network:network_emulation_unittests",
+ ]
+
+ if (rtc_enable_protobuf) {
+ deps += [ "logging:rtc_event_log_tests" ]
+ }
+
+ if (is_android) {
+ # Do not use Chromium's launcher. native_unittests defines its own JNI_OnLoad.
+ use_default_launcher = false
+
+ deps += [
+ "sdk/android:native_unittests",
+ "sdk/android:native_unittests_java",
+ "//testing/android/native_test:native_test_support",
+ ]
+ shard_timeout = 900
+ }
+
+ if (is_ios || is_mac) {
+ deps += [ "sdk:rtc_unittests_objc" ]
+ }
+ }
+
+ rtc_test("benchmarks") {
+ testonly = true
+ deps = [
+ "rtc_base/synchronization:mutex_benchmark",
+ "test:benchmark_main",
]
- proto_out_dir = "webrtc/call"
}
-}
-source_set("rtc_event_log") {
- sources = [
- "call/rtc_event_log.cc",
- "call/rtc_event_log.h",
+ # This runs tests that must run in real time and therefore can take some
+ # time to execute. They are in a separate executable to avoid making the
+ # regular unittest suite too slow to run frequently.
+ rtc_test("slow_tests") {
+ testonly = true
+ deps = [
+ "rtc_base/task_utils:repeating_task_unittests",
+ "test:test_main",
+ ]
+ }
+
+ # TODO(pbos): Rename test suite, this is no longer "just" for video targets.
+ video_engine_tests_resources = [
+ "resources/foreman_cif_short.yuv",
+ "resources/voice_engine/audio_long16.pcm",
]
- defines = []
- configs += [ ":common_config" ]
- public_configs = [ ":common_inherited_config" ]
+ if (is_ios) {
+ bundle_data("video_engine_tests_bundle_data") {
+ testonly = true
+ sources = video_engine_tests_resources
+ outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
+ }
+ }
+
+ rtc_test("video_engine_tests") {
+ testonly = true
+ deps = [
+ "audio:audio_tests",
- deps = [
- ":webrtc_common",
+ # TODO(eladalon): call_tests aren't actually video-specific, so we
+ # should move them to a more appropriate test suite.
+ "call:call_tests",
+ "call/adaptation:resource_adaptation_tests",
+ "test:test_common",
+ "test:test_main",
+ "test:video_test_common",
+ "video:video_tests",
+ "video/adaptation:video_adaptation_tests",
+ ]
+ data = video_engine_tests_resources
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_native_code" ]
+ shard_timeout = 900
+ }
+ if (is_ios) {
+ deps += [ ":video_engine_tests_bundle_data" ]
+ }
+ }
+
+ webrtc_perf_tests_resources = [
+ "resources/ConferenceMotion_1280_720_50.yuv",
+ "resources/audio_coding/speech_mono_16kHz.pcm",
+ "resources/audio_coding/speech_mono_32_48kHz.pcm",
+ "resources/audio_coding/testfile32kHz.pcm",
+ "resources/difficult_photo_1850_1110.yuv",
+ "resources/foreman_cif.yuv",
+ "resources/paris_qcif.yuv",
+ "resources/photo_1850_1110.yuv",
+ "resources/presentation_1850_1110.yuv",
+ "resources/voice_engine/audio_long16.pcm",
+ "resources/web_screenshot_1850_1110.yuv",
]
- if (rtc_enable_protobuf) {
- defines += [ "ENABLE_RTC_EVENT_LOG" ]
- deps += [ ":rtc_event_log_proto" ]
+ if (is_ios) {
+ bundle_data("webrtc_perf_tests_bundle_data") {
+ testonly = true
+ sources = webrtc_perf_tests_resources
+ outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
+ }
}
- if (is_clang && !is_nacl) {
- # Suppress warnings from Chrome's Clang plugins.
- # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
- configs -= [ "//build/config/clang:find_bad_constructs" ]
+
+ rtc_test("webrtc_perf_tests") {
+ testonly = true
+ deps = [
+ "audio:audio_perf_tests",
+ "call:call_perf_tests",
+ "modules/audio_coding:audio_coding_perf_tests",
+ "modules/audio_processing:audio_processing_perf_tests",
+ "pc:peerconnection_perf_tests",
+ "test:test_main",
+ "video:video_full_stack_tests",
+ "video:video_pc_full_stack_tests",
+ ]
+
+ data = webrtc_perf_tests_resources
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_native_code" ]
+ shard_timeout = 4500
+ }
+ if (is_ios) {
+ deps += [ ":webrtc_perf_tests_bundle_data" ]
+ }
+ }
+
+ rtc_test("webrtc_nonparallel_tests") {
+ testonly = true
+ deps = [ "rtc_base:rtc_base_nonparallel_tests" ]
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_support" ]
+ shard_timeout = 900
+ }
+ }
+
+ rtc_test("voip_unittests") {
+ testonly = true
+ deps = [
+ "api/voip:voip_engine_factory_unittests",
+ "audio/voip/test:audio_channel_unittests",
+ "audio/voip/test:audio_egress_unittests",
+ "audio/voip/test:audio_ingress_unittests",
+ "audio/voip/test:voip_core_unittests",
+ "test:test_main",
+ ]
}
}
+
+# ---- Poisons ----
+#
+# Here is one empty dummy target for each poison type (needed because
+# "being poisonous with poison type foo" is implemented as "depends on
+# //:poison_foo").
+#
+# The set of poison_* targets needs to be kept in sync with the
+# `all_poison_types` list in webrtc.gni.
+#
+group("poison_audio_codecs") {
+}
+
+group("poison_default_task_queue") {
+}
+
+group("poison_rtc_json") {
+}
+
+group("poison_software_video_codecs") {
+}
diff --git a/webrtc/LICENSE b/webrtc/LICENSE
new file mode 100644
index 0000000..4c41b7b
--- /dev/null
+++ b/webrtc/LICENSE
@@ -0,0 +1,29 @@
+Copyright (c) 2011, The WebRTC project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of Google nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/webrtc/LICENSE_THIRD_PARTY b/webrtc/LICENSE_THIRD_PARTY
deleted file mode 100644
index b64dbba..0000000
--- a/webrtc/LICENSE_THIRD_PARTY
+++ /dev/null
@@ -1,419 +0,0 @@
-This source tree contains third party source code which is governed by third
-party licenses. Paths to the files and associated licenses are collected here.
-
-Files governed by third party licenses:
-common_audio/fft4g.c
-common_audio/signal_processing/spl_sqrt_floor.c
-common_audio/signal_processing/spl_sqrt_floor_arm.S
-modules/audio_coding/codecs/g711/main/source/g711.c
-modules/audio_coding/codecs/g711/main/source/g711.h
-modules/audio_coding/codecs/g722/main/source/g722_decode.c
-modules/audio_coding/codecs/g722/main/source/g722_enc_dec.h
-modules/audio_coding/codecs/g722/main/source/g722_encode.c
-modules/audio_coding/codecs/isac/main/source/fft.c
-modules/audio_device/mac/portaudio/pa_memorybarrier.h
-modules/audio_device/mac/portaudio/pa_ringbuffer.c
-modules/audio_device/mac/portaudio/pa_ringbuffer.h
-modules/audio_processing/aec/aec_rdft.c
-system_wrappers/source/condition_variable_event_win.cc
-system_wrappers/source/set_thread_name_win.h
-system_wrappers/source/spreadsortlib/constants.hpp
-system_wrappers/source/spreadsortlib/spreadsort.hpp
-
-Individual licenses for each file:
--------------------------------------------------------------------------------
-Files:
-common_audio/signal_processing/spl_sqrt_floor.c
-common_audio/signal_processing/spl_sqrt_floor_arm.S
-
-License:
-/*
- * Written by Wilco Dijkstra, 1996. The following email exchange establishes the
- * license.
- *
- * From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com>
- * Date: Fri, Jun 24, 2011 at 3:20 AM
- * Subject: Re: sqrt routine
- * To: Kevin Ma <kma@google.com>
- * Hi Kevin,
- * Thanks for asking. Those routines are public domain (originally posted to
- * comp.sys.arm a long time ago), so you can use them freely for any purpose.
- * Cheers,
- * Wilco
- *
- * ----- Original Message -----
- * From: "Kevin Ma" <kma@google.com>
- * To: <Wilco.Dijkstra@ntlworld.com>
- * Sent: Thursday, June 23, 2011 11:44 PM
- * Subject: Fwd: sqrt routine
- * Hi Wilco,
- * I saw your sqrt routine from several web sites, including
- * http://www.finesse.demon.co.uk/steven/sqrt.html.
- * Just wonder if there's any copyright information with your Successive
- * approximation routines, or if I can freely use it for any purpose.
- * Thanks.
- * Kevin
- */
--------------------------------------------------------------------------------
-Files:
-modules/audio_coding/codecs/g711/main/source/g711.c
-modules/audio_coding/codecs/g711/main/source/g711.h
-
-License:
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * g711.h - In line A-law and u-law conversion routines
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2001 Steve Underwood
- *
- * Despite my general liking of the GPL, I place this code in the
- * public domain for the benefit of all mankind - even the slimy
- * ones who might try to proprietize my work and use it to my
- * detriment.
- */
--------------------------------------------------------------------------------
-Files:
-modules/audio_coding/codecs/g722/main/source/g722_decode.c
-modules/audio_coding/codecs/g722/main/source/g722_enc_dec.h
-modules/audio_coding/codecs/g722/main/source/g722_encode.c
-
-License:
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * g722_decode.c - The ITU G.722 codec, decode part.
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2005 Steve Underwood
- *
- * Despite my general liking of the GPL, I place my own contributions
- * to this code in the public domain for the benefit of all mankind -
- * even the slimy ones who might try to proprietize my work and use it
- * to my detriment.
- *
- * Based in part on a single channel G.722 codec which is:
- *
- * Copyright (c) CMU 1993
- * Computer Science, Speech Group
- * Chengxiang Lu and Alex Hauptmann
- */
--------------------------------------------------------------------------------
-Files:
-modules/audio_coding/codecs/isac/main/source/fft.c
-
-License:
-/*
- * Copyright(c)1995,97 Mark Olesen <olesen@me.QueensU.CA>
- * Queen's Univ at Kingston (Canada)
- *
- * Permission to use, copy, modify, and distribute this software for
- * any purpose without fee is hereby granted, provided that this
- * entire notice is included in all copies of any software which is
- * or includes a copy or modification of this software and in all
- * copies of the supporting documentation for such software.
- *
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S
- * UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY
- * KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * All of which is to say that you can do what you like with this
- * source code provided you don't try to sell it as your own and you
- * include an unaltered copy of this message (including the
- * copyright).
- *
- * It is also implicitly understood that bug fixes and improvements
- * should make their way back to the general Internet community so
- * that everyone benefits.
- */
--------------------------------------------------------------------------------
-Files:
-modules/audio_device/mac/portaudio/pa_memorybarrier.h
-modules/audio_device/mac/portaudio/pa_ringbuffer.c
-modules/audio_device/mac/portaudio/pa_ringbuffer.h
-
-License:
-/*
- * $Id: pa_memorybarrier.h 1240 2007-07-17 13:05:07Z bjornroche $
- * Portable Audio I/O Library
- * Memory barrier utilities
- *
- * Author: Bjorn Roche, XO Audio, LLC
- *
- * This program uses the PortAudio Portable Audio Library.
- * For more information see: http://www.portaudio.com
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * The text above constitutes the entire PortAudio license; however,
- * the PortAudio community also makes the following non-binding requests:
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version. It is also
- * requested that these non-binding requests be included along with the
- * license above.
- */
-
-/*
- * $Id: pa_ringbuffer.c 1421 2009-11-18 16:09:05Z bjornroche $
- * Portable Audio I/O Library
- * Ring Buffer utility.
- *
- * Author: Phil Burk, http://www.softsynth.com
- * modified for SMP safety on Mac OS X by Bjorn Roche
- * modified for SMP safety on Linux by Leland Lucius
- * also, allowed for const where possible
- * modified for multiple-byte-sized data elements by Sven Fischer
- *
- * Note that this is safe only for a single-thread reader and a
- * single-thread writer.
- *
- * This program uses the PortAudio Portable Audio Library.
- * For more information see: http://www.portaudio.com
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * The text above constitutes the entire PortAudio license; however,
- * the PortAudio community also makes the following non-binding requests:
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version. It is also
- * requested that these non-binding requests be included along with the
- * license above.
- */
--------------------------------------------------------------------------------
-Files:
-common_audio/fft4g.c
-modules/audio_processing/aec/aec_rdft.c
-
-License:
-/*
- * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
- * Copyright Takuya OOURA, 1996-2001
- *
- * You may use, copy, modify and distribute this code for any purpose (include
- * commercial use) and without fee. Please refer to this package when you modify
- * this code.
- */
--------------------------------------------------------------------------------
-Files:
-system_wrappers/source/condition_variable_event_win.cc
-
-Source:
-http://www1.cse.wustl.edu/~schmidt/ACE-copying.html
-
-License:
-Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM),
-and CoSMIC(TM)
-
-ACE(TM), TAO(TM), CIAO(TM), DAnCE>(TM), and CoSMIC(TM) (henceforth referred to
-as "DOC software") are copyrighted by Douglas C. Schmidt and his research
-group at Washington University, University of California, Irvine, and
-Vanderbilt University, Copyright (c) 1993-2009, all rights reserved. Since DOC
-software is open-source, freely available software, you are free to use,
-modify, copy, and distribute--perpetually and irrevocably--the DOC software
-source code and object code produced from the source, as well as copy and
-distribute modified versions of this software. You must, however, include this
-copyright statement along with any code built using DOC software that you
-release. No copyright statement needs to be provided if you just ship binary
-executables of your software products.
-You can use DOC software in commercial and/or binary software releases and are
-under no obligation to redistribute any of your source code that is built
-using DOC software. Note, however, that you may not misappropriate the DOC
-software code, such as copyrighting it yourself or claiming authorship of the
-DOC software code, in a way that will prevent DOC software from being
-distributed freely using an open-source development model. You needn't inform
-anyone that you're using DOC software in your software, though we encourage
-you to let us know so we can promote your project in the DOC software success
-stories.
-
-The ACE, TAO, CIAO, DAnCE, and CoSMIC web sites are maintained by the DOC
-Group at the Institute for Software Integrated Systems (ISIS) and the Center
-for Distributed Object Computing of Washington University, St. Louis for the
-development of open-source software as part of the open-source software
-community. Submissions are provided by the submitter ``as is'' with no
-warranties whatsoever, including any warranty of merchantability,
-noninfringement of third party intellectual property, or fitness for any
-particular purpose. In no event shall the submitter be liable for any direct,
-indirect, special, exemplary, punitive, or consequential damages, including
-without limitation, lost profits, even if advised of the possibility of such
-damages. Likewise, DOC software is provided as is with no warranties of any
-kind, including the warranties of design, merchantability, and fitness for a
-particular purpose, noninfringement, or arising from a course of dealing,
-usage or trade practice. Washington University, UC Irvine, Vanderbilt
-University, their employees, and students shall have no liability with respect
-to the infringement of copyrights, trade secrets or any patents by DOC
-software or any part thereof. Moreover, in no event will Washington
-University, UC Irvine, or Vanderbilt University, their employees, or students
-be liable for any lost revenue or profits or other special, indirect and
-consequential damages.
-
-DOC software is provided with no support and without any obligation on the
-part of Washington University, UC Irvine, Vanderbilt University, their
-employees, or students to assist in its use, correction, modification, or
-enhancement. A number of companies around the world provide commercial support
-for DOC software, however. DOC software is Y2K-compliant, as long as the
-underlying OS platform is Y2K-compliant. Likewise, DOC software is compliant
-with the new US daylight savings rule passed by Congress as "The Energy Policy
-Act of 2005," which established new daylight savings times (DST) rules for the
-United States that expand DST as of March 2007. Since DOC software obtains
-time/date and calendaring information from operating systems users will not be
-affected by the new DST rules as long as they upgrade their operating systems
-accordingly.
-
-The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), Washington
-University, UC Irvine, and Vanderbilt University, may not be used to endorse
-or promote products or services derived from this source without express
-written permission from Washington University, UC Irvine, or Vanderbilt
-University. This license grants no permission to call products or services
-derived from this source ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM),
-nor does it grant permission for the name Washington University, UC Irvine, or
-Vanderbilt University to appear in their names.
--------------------------------------------------------------------------------
-Files:
-system_wrappers/source/set_thread_name_win.h
-
-Source:
-http://msdn.microsoft.com/en-us/cc300389.aspx#P
-
-License:
-This license governs use of code marked as “sample” or “example” available on
-this web site without a license agreement, as provided under the section above
-titled “NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.” If you use
-such code (the “software”), you accept this license. If you do not accept the
-license, do not use the software.
-
-1. Definitions
-
-The terms “reproduce,” “reproduction,” “derivative works,” and “distribution”
-have the same meaning here as under U.S. copyright law.
-
-A “contribution” is the original software, or any additions or changes to the
-software.
-
-A “contributor” is any person that distributes its contribution under this
-license.
-
-“Licensed patents” are a contributor’s patent claims that read directly on its
-contribution.
-
-2. Grant of Rights
-
-(A) Copyright Grant - Subject to the terms of this license, including the
-license conditions and limitations in section 3, each contributor grants you a
-non-exclusive, worldwide, royalty-free copyright license to reproduce its
-contribution, prepare derivative works of its contribution, and distribute its
-contribution or any derivative works that you create.
-
-(B) Patent Grant - Subject to the terms of this license, including the license
-conditions and limitations in section 3, each contributor grants you a
-non-exclusive, worldwide, royalty-free license under its licensed patents to
-make, have made, use, sell, offer for sale, import, and/or otherwise dispose
-of its contribution in the software or derivative works of the contribution in
-the software.
-
-3. Conditions and Limitations
-
-(A) No Trademark License- This license does not grant you rights to use any
-contributors’ name, logo, or trademarks.
-
-(B) If you bring a patent claim against any contributor over patents that you
-claim are infringed by the software, your patent license from such contributor
-to the software ends automatically.
-
-(C) If you distribute any portion of the software, you must retain all
-copyright, patent, trademark, and attribution notices that are present in the
-software.
-
-(D) If you distribute any portion of the software in source code form, you may
-do so only under this license by including a complete copy of this license
-with your distribution. If you distribute any portion of the software in
-compiled or object code form, you may only do so under a license that complies
-with this license.
-
-(E) The software is licensed “as-is.” You bear the risk of using it. The
-contributors give no express warranties, guarantees or conditions. You may
-have additional consumer rights under your local laws which this license
-cannot change. To the extent permitted under your local laws, the contributors
-exclude the implied warranties of merchantability, fitness for a particular
-purpose and non-infringement.
-
-(F) Platform Limitation - The licenses granted in sections 2(A) and 2(B)
-extend only to the software or derivative works that you create that run on a
-Microsoft Windows operating system product.
--------------------------------------------------------------------------------
-Files:
-system_wrappers/source/spreadsortlib/constants.hpp
-system_wrappers/source/spreadsortlib/spreadsort.hpp
-
-License:
-/*Boost Software License - Version 1.0 - August 17th, 2003
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.*/
diff --git a/webrtc/api/array_view.h b/webrtc/api/array_view.h
new file mode 100644
index 0000000..a66369a
--- /dev/null
+++ b/webrtc/api/array_view.h
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2015 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_ARRAY_VIEW_H_
+#define API_ARRAY_VIEW_H_
+
+#include <algorithm>
+#include <array>
+#include <type_traits>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/type_traits.h"
+
+namespace rtc {
+
+// tl;dr: rtc::ArrayView is the same thing as gsl::span from the Guideline
+// Support Library.
+//
+// Many functions read from or write to arrays. The obvious way to do this is
+// to use two arguments, a pointer to the first element and an element count:
+//
+// bool Contains17(const int* arr, size_t size) {
+// for (size_t i = 0; i < size; ++i) {
+// if (arr[i] == 17)
+// return true;
+// }
+// return false;
+// }
+//
+// This is flexible, since it doesn't matter how the array is stored (C array,
+// std::vector, rtc::Buffer, ...), but it's error-prone because the caller has
+// to correctly specify the array length:
+//
+// Contains17(arr, arraysize(arr)); // C array
+// Contains17(arr.data(), arr.size()); // std::vector
+// Contains17(arr, size); // pointer + size
+// ...
+//
+// It's also kind of messy to have two separate arguments for what is
+// conceptually a single thing.
+//
+// Enter rtc::ArrayView<T>. It contains a T pointer (to an array it doesn't
+// own) and a count, and supports the basic things you'd expect, such as
+// indexing and iteration. It allows us to write our function like this:
+//
+// bool Contains17(rtc::ArrayView<const int> arr) {
+// for (auto e : arr) {
+// if (e == 17)
+// return true;
+// }
+// return false;
+// }
+//
+// And even better, because a bunch of things will implicitly convert to
+// ArrayView, we can call it like this:
+//
+// Contains17(arr); // C array
+// Contains17(arr); // std::vector
+// Contains17(rtc::ArrayView<int>(arr, size)); // pointer + size
+// Contains17(nullptr); // nullptr -> empty ArrayView
+// ...
+//
+// ArrayView<T> stores both a pointer and a size, but you may also use
+// ArrayView<T, N>, which has a size that's fixed at compile time (which means
+// it only has to store the pointer).
+//
+// One important point is that ArrayView<T> and ArrayView<const T> are
+// different types, which allow and don't allow mutation of the array elements,
+// respectively. The implicit conversions work just like you'd hope, so that
+// e.g. vector<int> will convert to either ArrayView<int> or ArrayView<const
+// int>, but const vector<int> will convert only to ArrayView<const int>.
+// (ArrayView itself can be the source type in such conversions, so
+// ArrayView<int> will convert to ArrayView<const int>.)
+//
+// Note: ArrayView is tiny (just a pointer and a count if variable-sized, just
+// a pointer if fix-sized) and trivially copyable, so it's probably cheaper to
+// pass it by value than by const reference.
+
+namespace impl {
+
+// Magic constant for indicating that the size of an ArrayView is variable
+// instead of fixed.
+enum : std::ptrdiff_t { kArrayViewVarSize = -4711 };
+
+// Base class for ArrayViews of fixed nonzero size.
+template <typename T, std::ptrdiff_t Size>
+class ArrayViewBase {
+ static_assert(Size > 0, "ArrayView size must be variable or non-negative");
+
+ public:
+ ArrayViewBase(T* data, size_t size) : data_(data) {}
+
+ static constexpr size_t size() { return Size; }
+ static constexpr bool empty() { return false; }
+ T* data() const { return data_; }
+
+ protected:
+ static constexpr bool fixed_size() { return true; }
+
+ private:
+ T* data_;
+};
+
+// Specialized base class for ArrayViews of fixed zero size.
+template <typename T>
+class ArrayViewBase<T, 0> {
+ public:
+ explicit ArrayViewBase(T* data, size_t size) {}
+
+ static constexpr size_t size() { return 0; }
+ static constexpr bool empty() { return true; }
+ T* data() const { return nullptr; }
+
+ protected:
+ static constexpr bool fixed_size() { return true; }
+};
+
+// Specialized base class for ArrayViews of variable size.
+template <typename T>
+class ArrayViewBase<T, impl::kArrayViewVarSize> {
+ public:
+ ArrayViewBase(T* data, size_t size)
+ : data_(size == 0 ? nullptr : data), size_(size) {}
+
+ size_t size() const { return size_; }
+ bool empty() const { return size_ == 0; }
+ T* data() const { return data_; }
+
+ protected:
+ static constexpr bool fixed_size() { return false; }
+
+ private:
+ T* data_;
+ size_t size_;
+};
+
+} // namespace impl
+
+template <typename T, std::ptrdiff_t Size = impl::kArrayViewVarSize>
+class ArrayView final : public impl::ArrayViewBase<T, Size> {
+ public:
+ using value_type = T;
+ using const_iterator = const T*;
+
+ // Construct an ArrayView from a pointer and a length.
+ template <typename U>
+ ArrayView(U* data, size_t size)
+ : impl::ArrayViewBase<T, Size>::ArrayViewBase(data, size) {
+ RTC_DCHECK_EQ(size == 0 ? nullptr : data, this->data());
+ RTC_DCHECK_EQ(size, this->size());
+ RTC_DCHECK_EQ(!this->data(),
+ this->size() == 0); // data is null iff size == 0.
+ }
+
+ // Construct an empty ArrayView. Note that fixed-size ArrayViews of size > 0
+ // cannot be empty.
+ ArrayView() : ArrayView(nullptr, 0) {}
+ ArrayView(std::nullptr_t) // NOLINT
+ : ArrayView() {}
+ ArrayView(std::nullptr_t, size_t size)
+ : ArrayView(static_cast<T*>(nullptr), size) {
+ static_assert(Size == 0 || Size == impl::kArrayViewVarSize, "");
+ RTC_DCHECK_EQ(0, size);
+ }
+
+ // Construct an ArrayView from a C-style array.
+ template <typename U, size_t N>
+ ArrayView(U (&array)[N]) // NOLINT
+ : ArrayView(array, N) {
+ static_assert(Size == N || Size == impl::kArrayViewVarSize,
+ "Array size must match ArrayView size");
+ }
+
+ // (Only if size is fixed.) Construct a fixed size ArrayView<T, N> from a
+ // non-const std::array instance. For an ArrayView with variable size, the
+ // used ctor is ArrayView(U& u) instead.
+ template <typename U,
+ size_t N,
+ typename std::enable_if<
+ Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr>
+ ArrayView(std::array<U, N>& u) // NOLINT
+ : ArrayView(u.data(), u.size()) {}
+
+ // (Only if size is fixed.) Construct a fixed size ArrayView<T, N> where T is
+ // const from a const(expr) std::array instance. For an ArrayView with
+ // variable size, the used ctor is ArrayView(U& u) instead.
+ template <typename U,
+ size_t N,
+ typename std::enable_if<
+ Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr>
+ ArrayView(const std::array<U, N>& u) // NOLINT
+ : ArrayView(u.data(), u.size()) {}
+
+ // (Only if size is fixed.) Construct an ArrayView from any type U that has a
+ // static constexpr size() method whose return value is equal to Size, and a
+ // data() method whose return value converts implicitly to T*. In particular,
+ // this means we allow conversion from ArrayView<T, N> to ArrayView<const T,
+ // N>, but not the other way around. We also don't allow conversion from
+ // ArrayView<T> to ArrayView<T, N>, or from ArrayView<T, M> to ArrayView<T,
+ // N> when M != N.
+ template <
+ typename U,
+ typename std::enable_if<Size != impl::kArrayViewVarSize &&
+ HasDataAndSize<U, T>::value>::type* = nullptr>
+ ArrayView(U& u) // NOLINT
+ : ArrayView(u.data(), u.size()) {
+ static_assert(U::size() == Size, "Sizes must match exactly");
+ }
+ template <
+ typename U,
+ typename std::enable_if<Size != impl::kArrayViewVarSize &&
+ HasDataAndSize<U, T>::value>::type* = nullptr>
+ ArrayView(const U& u) // NOLINT(runtime/explicit)
+ : ArrayView(u.data(), u.size()) {
+ static_assert(U::size() == Size, "Sizes must match exactly");
+ }
+
+ // (Only if size is variable.) Construct an ArrayView from any type U that
+ // has a size() method whose return value converts implicitly to size_t, and
+ // a data() method whose return value converts implicitly to T*. In
+ // particular, this means we allow conversion from ArrayView<T> to
+ // ArrayView<const T>, but not the other way around. Other allowed
+ // conversions include
+ // ArrayView<T, N> to ArrayView<T> or ArrayView<const T>,
+ // std::vector<T> to ArrayView<T> or ArrayView<const T>,
+ // const std::vector<T> to ArrayView<const T>,
+ // rtc::Buffer to ArrayView<uint8_t> or ArrayView<const uint8_t>, and
+ // const rtc::Buffer to ArrayView<const uint8_t>.
+ template <
+ typename U,
+ typename std::enable_if<Size == impl::kArrayViewVarSize &&
+ HasDataAndSize<U, T>::value>::type* = nullptr>
+ ArrayView(U& u) // NOLINT
+ : ArrayView(u.data(), u.size()) {}
+ template <
+ typename U,
+ typename std::enable_if<Size == impl::kArrayViewVarSize &&
+ HasDataAndSize<U, T>::value>::type* = nullptr>
+ ArrayView(const U& u) // NOLINT(runtime/explicit)
+ : ArrayView(u.data(), u.size()) {}
+
+ // Indexing and iteration. These allow mutation even if the ArrayView is
+ // const, because the ArrayView doesn't own the array. (To prevent mutation,
+ // use a const element type.)
+ T& operator[](size_t idx) const {
+ RTC_DCHECK_LT(idx, this->size());
+ RTC_DCHECK(this->data());
+ return this->data()[idx];
+ }
+ T* begin() const { return this->data(); }
+ T* end() const { return this->data() + this->size(); }
+ const T* cbegin() const { return this->data(); }
+ const T* cend() const { return this->data() + this->size(); }
+
+ ArrayView<T> subview(size_t offset, size_t size) const {
+ return offset < this->size()
+ ? ArrayView<T>(this->data() + offset,
+ std::min(size, this->size() - offset))
+ : ArrayView<T>();
+ }
+ ArrayView<T> subview(size_t offset) const {
+ return subview(offset, this->size());
+ }
+};
+
+// Comparing two ArrayViews compares their (pointer,size) pairs; it does *not*
+// dereference the pointers.
+template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2>
+bool operator==(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) {
+ return a.data() == b.data() && a.size() == b.size();
+}
+template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2>
+bool operator!=(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) {
+ return !(a == b);
+}
+
+// Variable-size ArrayViews are the size of two pointers; fixed-size ArrayViews
+// are the size of one pointer. (And as a special case, fixed-size ArrayViews
+// of size 0 require no storage.)
+static_assert(sizeof(ArrayView<int>) == 2 * sizeof(int*), "");
+static_assert(sizeof(ArrayView<int, 17>) == sizeof(int*), "");
+static_assert(std::is_empty<ArrayView<int, 0>>::value, "");
+
+template <typename T>
+inline ArrayView<T> MakeArrayView(T* data, size_t size) {
+ return ArrayView<T>(data, size);
+}
+
+// Only for primitive types that have the same size and aligment.
+// Allow reinterpret cast of the array view to another primitive type of the
+// same size.
+// Template arguments order is (U, T, Size) to allow deduction of the template
+// arguments in client calls: reinterpret_array_view<target_type>(array_view).
+template <typename U, typename T, std::ptrdiff_t Size>
+inline ArrayView<U, Size> reinterpret_array_view(ArrayView<T, Size> view) {
+ static_assert(sizeof(U) == sizeof(T) && alignof(U) == alignof(T),
+ "ArrayView reinterpret_cast is only supported for casting "
+ "between views that represent the same chunk of memory.");
+ static_assert(
+ std::is_fundamental<T>::value && std::is_fundamental<U>::value,
+ "ArrayView reinterpret_cast is only supported for casting between "
+ "fundamental types.");
+ return ArrayView<U, Size>(reinterpret_cast<U*>(view.data()), view.size());
+}
+
+} // namespace rtc
+
+#endif // API_ARRAY_VIEW_H_
diff --git a/webrtc/api/audio/audio_frame.cc b/webrtc/api/audio/audio_frame.cc
new file mode 100644
index 0000000..c6e5cf4
--- /dev/null
+++ b/webrtc/api/audio/audio_frame.cc
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/audio/audio_frame.h"
+
+#include <string.h>
+#include <algorithm>
+#include <utility>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+
+AudioFrame::AudioFrame() {
+ // Visual Studio doesn't like this in the class definition.
+ static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes");
+}
+
+void swap(AudioFrame& a, AudioFrame& b) {
+ using std::swap;
+ swap(a.timestamp_, b.timestamp_);
+ swap(a.elapsed_time_ms_, b.elapsed_time_ms_);
+ swap(a.ntp_time_ms_, b.ntp_time_ms_);
+ swap(a.samples_per_channel_, b.samples_per_channel_);
+ swap(a.sample_rate_hz_, b.sample_rate_hz_);
+ swap(a.num_channels_, b.num_channels_);
+ swap(a.channel_layout_, b.channel_layout_);
+ swap(a.speech_type_, b.speech_type_);
+ swap(a.vad_activity_, b.vad_activity_);
+ swap(a.profile_timestamp_ms_, b.profile_timestamp_ms_);
+ swap(a.packet_infos_, b.packet_infos_);
+ const size_t length_a = a.samples_per_channel_ * a.num_channels_;
+ const size_t length_b = b.samples_per_channel_ * b.num_channels_;
+ RTC_DCHECK_LE(length_a, AudioFrame::kMaxDataSizeSamples);
+ RTC_DCHECK_LE(length_b, AudioFrame::kMaxDataSizeSamples);
+ std::swap_ranges(a.data_, a.data_ + std::max(length_a, length_b), b.data_);
+ swap(a.muted_, b.muted_);
+ swap(a.absolute_capture_timestamp_ms_, b.absolute_capture_timestamp_ms_);
+}
+
+void AudioFrame::Reset() {
+ ResetWithoutMuting();
+ muted_ = true;
+}
+
+void AudioFrame::ResetWithoutMuting() {
+ // TODO(wu): Zero is a valid value for |timestamp_|. We should initialize
+ // to an invalid value, or add a new member to indicate invalidity.
+ timestamp_ = 0;
+ elapsed_time_ms_ = -1;
+ ntp_time_ms_ = -1;
+ samples_per_channel_ = 0;
+ sample_rate_hz_ = 0;
+ num_channels_ = 0;
+ channel_layout_ = CHANNEL_LAYOUT_NONE;
+ speech_type_ = kUndefined;
+ vad_activity_ = kVadUnknown;
+ profile_timestamp_ms_ = 0;
+ packet_infos_ = RtpPacketInfos();
+ absolute_capture_timestamp_ms_ = absl::nullopt;
+}
+
+void AudioFrame::UpdateFrame(uint32_t timestamp,
+ const int16_t* data,
+ size_t samples_per_channel,
+ int sample_rate_hz,
+ SpeechType speech_type,
+ VADActivity vad_activity,
+ size_t num_channels) {
+ timestamp_ = timestamp;
+ samples_per_channel_ = samples_per_channel;
+ sample_rate_hz_ = sample_rate_hz;
+ speech_type_ = speech_type;
+ vad_activity_ = vad_activity;
+ num_channels_ = num_channels;
+ channel_layout_ = GuessChannelLayout(num_channels);
+ if (channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED) {
+ RTC_DCHECK_EQ(num_channels, ChannelLayoutToChannelCount(channel_layout_));
+ }
+
+ const size_t length = samples_per_channel * num_channels;
+ RTC_CHECK_LE(length, kMaxDataSizeSamples);
+ if (data != nullptr) {
+ memcpy(data_, data, sizeof(int16_t) * length);
+ muted_ = false;
+ } else {
+ muted_ = true;
+ }
+}
+
+void AudioFrame::CopyFrom(const AudioFrame& src) {
+ if (this == &src)
+ return;
+
+ timestamp_ = src.timestamp_;
+ elapsed_time_ms_ = src.elapsed_time_ms_;
+ ntp_time_ms_ = src.ntp_time_ms_;
+ packet_infos_ = src.packet_infos_;
+ muted_ = src.muted();
+ samples_per_channel_ = src.samples_per_channel_;
+ sample_rate_hz_ = src.sample_rate_hz_;
+ speech_type_ = src.speech_type_;
+ vad_activity_ = src.vad_activity_;
+ num_channels_ = src.num_channels_;
+ channel_layout_ = src.channel_layout_;
+ absolute_capture_timestamp_ms_ = src.absolute_capture_timestamp_ms();
+
+ const size_t length = samples_per_channel_ * num_channels_;
+ RTC_CHECK_LE(length, kMaxDataSizeSamples);
+ if (!src.muted()) {
+ memcpy(data_, src.data(), sizeof(int16_t) * length);
+ muted_ = false;
+ }
+}
+
+void AudioFrame::UpdateProfileTimeStamp() {
+ profile_timestamp_ms_ = rtc::TimeMillis();
+}
+
+int64_t AudioFrame::ElapsedProfileTimeMs() const {
+ if (profile_timestamp_ms_ == 0) {
+ // Profiling has not been activated.
+ return -1;
+ }
+ return rtc::TimeSince(profile_timestamp_ms_);
+}
+
+const int16_t* AudioFrame::data() const {
+ return muted_ ? empty_data() : data_;
+}
+
+// TODO(henrik.lundin) Can we skip zeroing the buffer?
+// See https://bugs.chromium.org/p/webrtc/issues/detail?id=5647.
+int16_t* AudioFrame::mutable_data() {
+ if (muted_) {
+ memset(data_, 0, kMaxDataSizeBytes);
+ muted_ = false;
+ }
+ return data_;
+}
+
+void AudioFrame::Mute() {
+ muted_ = true;
+}
+
+bool AudioFrame::muted() const {
+ return muted_;
+}
+
+// static
+const int16_t* AudioFrame::empty_data() {
+ static int16_t* null_data = new int16_t[kMaxDataSizeSamples]();
+ return &null_data[0];
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/audio/audio_frame.h b/webrtc/api/audio/audio_frame.h
new file mode 100644
index 0000000..78539f5
--- /dev/null
+++ b/webrtc/api/audio/audio_frame.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_AUDIO_AUDIO_FRAME_H_
+#define API_AUDIO_AUDIO_FRAME_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+
+#include "api/audio/channel_layout.h"
+#include "api/rtp_packet_infos.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+/* This class holds up to 120 ms of super-wideband (32 kHz) stereo audio. It
+ * allows for adding and subtracting frames while keeping track of the resulting
+ * states.
+ *
+ * Notes
+ * - This is a de-facto api, not designed for external use. The AudioFrame class
+ * is in need of overhaul or even replacement, and anyone depending on it
+ * should be prepared for that.
+ * - The total number of samples is samples_per_channel_ * num_channels_.
+ * - Stereo data is interleaved starting with the left channel.
+ */
+class AudioFrame {
+ public:
+ // Using constexpr here causes linker errors unless the variable also has an
+ // out-of-class definition, which is impractical in this header-only class.
+ // (This makes no sense because it compiles as an enum value, which we most
+ // certainly cannot take the address of, just fine.) C++17 introduces inline
+ // variables which should allow us to switch to constexpr and keep this a
+ // header-only class.
+ enum : size_t {
+ // Stereo, 32 kHz, 120 ms (2 * 32 * 120)
+ // Stereo, 192 kHz, 20 ms (2 * 192 * 20)
+ kMaxDataSizeSamples = 7680,
+ kMaxDataSizeBytes = kMaxDataSizeSamples * sizeof(int16_t),
+ };
+
+ enum VADActivity { kVadActive = 0, kVadPassive = 1, kVadUnknown = 2 };
+ enum SpeechType {
+ kNormalSpeech = 0,
+ kPLC = 1,
+ kCNG = 2,
+ kPLCCNG = 3,
+ kCodecPLC = 5,
+ kUndefined = 4
+ };
+
+ AudioFrame();
+
+ friend void swap(AudioFrame& a, AudioFrame& b);
+
+ // Resets all members to their default state.
+ void Reset();
+ // Same as Reset(), but leaves mute state unchanged. Muting a frame requires
+ // the buffer to be zeroed on the next call to mutable_data(). Callers
+ // intending to write to the buffer immediately after Reset() can instead use
+ // ResetWithoutMuting() to skip this wasteful zeroing.
+ void ResetWithoutMuting();
+
+ void UpdateFrame(uint32_t timestamp,
+ const int16_t* data,
+ size_t samples_per_channel,
+ int sample_rate_hz,
+ SpeechType speech_type,
+ VADActivity vad_activity,
+ size_t num_channels = 1);
+
+ void CopyFrom(const AudioFrame& src);
+
+ // Sets a wall-time clock timestamp in milliseconds to be used for profiling
+ // of time between two points in the audio chain.
+ // Example:
+ // t0: UpdateProfileTimeStamp()
+ // t1: ElapsedProfileTimeMs() => t1 - t0 [msec]
+ void UpdateProfileTimeStamp();
+ // Returns the time difference between now and when UpdateProfileTimeStamp()
+ // was last called. Returns -1 if UpdateProfileTimeStamp() has not yet been
+ // called.
+ int64_t ElapsedProfileTimeMs() const;
+
+ // data() returns a zeroed static buffer if the frame is muted.
+ // mutable_frame() always returns a non-static buffer; the first call to
+ // mutable_frame() zeros the non-static buffer and marks the frame unmuted.
+ const int16_t* data() const;
+ int16_t* mutable_data();
+
+ // Prefer to mute frames using AudioFrameOperations::Mute.
+ void Mute();
+ // Frame is muted by default.
+ bool muted() const;
+
+ size_t max_16bit_samples() const { return kMaxDataSizeSamples; }
+ size_t samples_per_channel() const { return samples_per_channel_; }
+ size_t num_channels() const { return num_channels_; }
+ ChannelLayout channel_layout() const { return channel_layout_; }
+ int sample_rate_hz() const { return sample_rate_hz_; }
+
+ void set_absolute_capture_timestamp_ms(
+ int64_t absolute_capture_time_stamp_ms) {
+ absolute_capture_timestamp_ms_ = absolute_capture_time_stamp_ms;
+ }
+
+ absl::optional<int64_t> absolute_capture_timestamp_ms() const {
+ return absolute_capture_timestamp_ms_;
+ }
+
+ // RTP timestamp of the first sample in the AudioFrame.
+ uint32_t timestamp_ = 0;
+ // Time since the first frame in milliseconds.
+ // -1 represents an uninitialized value.
+ int64_t elapsed_time_ms_ = -1;
+ // NTP time of the estimated capture time in local timebase in milliseconds.
+ // -1 represents an uninitialized value.
+ int64_t ntp_time_ms_ = -1;
+ size_t samples_per_channel_ = 0;
+ int sample_rate_hz_ = 0;
+ size_t num_channels_ = 0;
+ ChannelLayout channel_layout_ = CHANNEL_LAYOUT_NONE;
+ SpeechType speech_type_ = kUndefined;
+ VADActivity vad_activity_ = kVadUnknown;
+ // Monotonically increasing timestamp intended for profiling of audio frames.
+ // Typically used for measuring elapsed time between two different points in
+ // the audio path. No lock is used to save resources and we are thread safe
+ // by design.
+ // TODO(nisse@webrtc.org): consider using absl::optional.
+ int64_t profile_timestamp_ms_ = 0;
+
+ // Information about packets used to assemble this audio frame. This is needed
+ // by |SourceTracker| when the frame is delivered to the RTCRtpReceiver's
+ // MediaStreamTrack, in order to implement getContributingSources(). See:
+ // https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getcontributingsources
+ //
+ // TODO(bugs.webrtc.org/10757):
+ // Note that this information might not be fully accurate since we currently
+ // don't have a proper way to track it across the audio sync buffer. The
+ // sync buffer is the small sample-holding buffer located after the audio
+ // decoder and before where samples are assembled into output frames.
+ //
+ // |RtpPacketInfos| may also be empty if the audio samples did not come from
+ // RTP packets. E.g. if the audio were locally generated by packet loss
+ // concealment, comfort noise generation, etc.
+ RtpPacketInfos packet_infos_;
+
+ private:
+ // A permanently zeroed out buffer to represent muted frames. This is a
+ // header-only class, so the only way to avoid creating a separate empty
+ // buffer per translation unit is to wrap a static in an inline function.
+ static const int16_t* empty_data();
+
+ int16_t data_[kMaxDataSizeSamples];
+ bool muted_ = true;
+
+ // Absolute capture timestamp when this audio frame was originally captured.
+ // This is only valid for audio frames captured on this machine. The absolute
+ // capture timestamp of a received frame is found in |packet_infos_|.
+ // This timestamp MUST be based on the same clock as rtc::TimeMillis().
+ absl::optional<int64_t> absolute_capture_timestamp_ms_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(AudioFrame);
+};
+
+} // namespace webrtc
+
+#endif // API_AUDIO_AUDIO_FRAME_H_
diff --git a/webrtc/api/audio/channel_layout.cc b/webrtc/api/audio/channel_layout.cc
new file mode 100644
index 0000000..567f4d9
--- /dev/null
+++ b/webrtc/api/audio/channel_layout.cc
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/audio/channel_layout.h"
+
+#include <stddef.h>
+
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+static const int kLayoutToChannels[] = {
+ 0, // CHANNEL_LAYOUT_NONE
+ 0, // CHANNEL_LAYOUT_UNSUPPORTED
+ 1, // CHANNEL_LAYOUT_MONO
+ 2, // CHANNEL_LAYOUT_STEREO
+ 3, // CHANNEL_LAYOUT_2_1
+ 3, // CHANNEL_LAYOUT_SURROUND
+ 4, // CHANNEL_LAYOUT_4_0
+ 4, // CHANNEL_LAYOUT_2_2
+ 4, // CHANNEL_LAYOUT_QUAD
+ 5, // CHANNEL_LAYOUT_5_0
+ 6, // CHANNEL_LAYOUT_5_1
+ 5, // CHANNEL_LAYOUT_5_0_BACK
+ 6, // CHANNEL_LAYOUT_5_1_BACK
+ 7, // CHANNEL_LAYOUT_7_0
+ 8, // CHANNEL_LAYOUT_7_1
+ 8, // CHANNEL_LAYOUT_7_1_WIDE
+ 2, // CHANNEL_LAYOUT_STEREO_DOWNMIX
+ 3, // CHANNEL_LAYOUT_2POINT1
+ 4, // CHANNEL_LAYOUT_3_1
+ 5, // CHANNEL_LAYOUT_4_1
+ 6, // CHANNEL_LAYOUT_6_0
+ 6, // CHANNEL_LAYOUT_6_0_FRONT
+ 6, // CHANNEL_LAYOUT_HEXAGONAL
+ 7, // CHANNEL_LAYOUT_6_1
+ 7, // CHANNEL_LAYOUT_6_1_BACK
+ 7, // CHANNEL_LAYOUT_6_1_FRONT
+ 7, // CHANNEL_LAYOUT_7_0_FRONT
+ 8, // CHANNEL_LAYOUT_7_1_WIDE_BACK
+ 8, // CHANNEL_LAYOUT_OCTAGONAL
+ 0, // CHANNEL_LAYOUT_DISCRETE
+ 3, // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC
+ 5, // CHANNEL_LAYOUT_4_1_QUAD_SIDE
+ 0, // CHANNEL_LAYOUT_BITSTREAM
+};
+
+// The channel orderings for each layout as specified by FFmpeg. Each value
+// represents the index of each channel in each layout. Values of -1 mean the
+// channel at that index is not used for that layout. For example, the left side
+// surround sound channel in FFmpeg's 5.1 layout is in the 5th position (because
+// the order is L, R, C, LFE, LS, RS), so
+// kChannelOrderings[CHANNEL_LAYOUT_5_1][SIDE_LEFT] = 4;
+static const int kChannelOrderings[CHANNEL_LAYOUT_MAX + 1][CHANNELS_MAX + 1] = {
+ // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
+
+ // CHANNEL_LAYOUT_NONE
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_UNSUPPORTED
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_MONO
+ {-1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_STEREO
+ {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_2_1
+ {0, 1, -1, -1, -1, -1, -1, -1, 2, -1, -1},
+
+ // CHANNEL_LAYOUT_SURROUND
+ {0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_4_0
+ {0, 1, 2, -1, -1, -1, -1, -1, 3, -1, -1},
+
+ // CHANNEL_LAYOUT_2_2
+ {0, 1, -1, -1, -1, -1, -1, -1, -1, 2, 3},
+
+ // CHANNEL_LAYOUT_QUAD
+ {0, 1, -1, -1, 2, 3, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_5_0
+ {0, 1, 2, -1, -1, -1, -1, -1, -1, 3, 4},
+
+ // CHANNEL_LAYOUT_5_1
+ {0, 1, 2, 3, -1, -1, -1, -1, -1, 4, 5},
+
+ // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
+
+ // CHANNEL_LAYOUT_5_0_BACK
+ {0, 1, 2, -1, 3, 4, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_5_1_BACK
+ {0, 1, 2, 3, 4, 5, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_7_0
+ {0, 1, 2, -1, 5, 6, -1, -1, -1, 3, 4},
+
+ // CHANNEL_LAYOUT_7_1
+ {0, 1, 2, 3, 6, 7, -1, -1, -1, 4, 5},
+
+ // CHANNEL_LAYOUT_7_1_WIDE
+ {0, 1, 2, 3, -1, -1, 6, 7, -1, 4, 5},
+
+ // CHANNEL_LAYOUT_STEREO_DOWNMIX
+ {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_2POINT1
+ {0, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_3_1
+ {0, 1, 2, 3, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_4_1
+ {0, 1, 2, 4, -1, -1, -1, -1, 3, -1, -1},
+
+ // CHANNEL_LAYOUT_6_0
+ {0, 1, 2, -1, -1, -1, -1, -1, 5, 3, 4},
+
+ // CHANNEL_LAYOUT_6_0_FRONT
+ {0, 1, -1, -1, -1, -1, 4, 5, -1, 2, 3},
+
+ // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
+
+ // CHANNEL_LAYOUT_HEXAGONAL
+ {0, 1, 2, -1, 3, 4, -1, -1, 5, -1, -1},
+
+ // CHANNEL_LAYOUT_6_1
+ {0, 1, 2, 3, -1, -1, -1, -1, 6, 4, 5},
+
+ // CHANNEL_LAYOUT_6_1_BACK
+ {0, 1, 2, 3, 4, 5, -1, -1, 6, -1, -1},
+
+ // CHANNEL_LAYOUT_6_1_FRONT
+ {0, 1, -1, 6, -1, -1, 4, 5, -1, 2, 3},
+
+ // CHANNEL_LAYOUT_7_0_FRONT
+ {0, 1, 2, -1, -1, -1, 5, 6, -1, 3, 4},
+
+ // CHANNEL_LAYOUT_7_1_WIDE_BACK
+ {0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_OCTAGONAL
+ {0, 1, 2, -1, 5, 6, -1, -1, 7, 3, 4},
+
+ // CHANNEL_LAYOUT_DISCRETE
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC
+ {0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // CHANNEL_LAYOUT_4_1_QUAD_SIDE
+ {0, 1, -1, 4, -1, -1, -1, -1, -1, 2, 3},
+
+ // CHANNEL_LAYOUT_BITSTREAM
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+
+ // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
+};
+
+int ChannelLayoutToChannelCount(ChannelLayout layout) {
+ RTC_DCHECK_LT(static_cast<size_t>(layout), arraysize(kLayoutToChannels));
+ RTC_DCHECK_LE(kLayoutToChannels[layout], kMaxConcurrentChannels);
+ return kLayoutToChannels[layout];
+}
+
+// Converts a channel count into a channel layout.
+ChannelLayout GuessChannelLayout(int channels) {
+ switch (channels) {
+ case 1:
+ return CHANNEL_LAYOUT_MONO;
+ case 2:
+ return CHANNEL_LAYOUT_STEREO;
+ case 3:
+ return CHANNEL_LAYOUT_SURROUND;
+ case 4:
+ return CHANNEL_LAYOUT_QUAD;
+ case 5:
+ return CHANNEL_LAYOUT_5_0;
+ case 6:
+ return CHANNEL_LAYOUT_5_1;
+ case 7:
+ return CHANNEL_LAYOUT_6_1;
+ case 8:
+ return CHANNEL_LAYOUT_7_1;
+ default:
+ RTC_DLOG(LS_WARNING) << "Unsupported channel count: " << channels;
+ }
+ return CHANNEL_LAYOUT_UNSUPPORTED;
+}
+
+int ChannelOrder(ChannelLayout layout, Channels channel) {
+ RTC_DCHECK_LT(static_cast<size_t>(layout), arraysize(kChannelOrderings));
+ RTC_DCHECK_LT(static_cast<size_t>(channel), arraysize(kChannelOrderings[0]));
+ return kChannelOrderings[layout][channel];
+}
+
+const char* ChannelLayoutToString(ChannelLayout layout) {
+ switch (layout) {
+ case CHANNEL_LAYOUT_NONE:
+ return "NONE";
+ case CHANNEL_LAYOUT_UNSUPPORTED:
+ return "UNSUPPORTED";
+ case CHANNEL_LAYOUT_MONO:
+ return "MONO";
+ case CHANNEL_LAYOUT_STEREO:
+ return "STEREO";
+ case CHANNEL_LAYOUT_2_1:
+ return "2.1";
+ case CHANNEL_LAYOUT_SURROUND:
+ return "SURROUND";
+ case CHANNEL_LAYOUT_4_0:
+ return "4.0";
+ case CHANNEL_LAYOUT_2_2:
+ return "QUAD_SIDE";
+ case CHANNEL_LAYOUT_QUAD:
+ return "QUAD";
+ case CHANNEL_LAYOUT_5_0:
+ return "5.0";
+ case CHANNEL_LAYOUT_5_1:
+ return "5.1";
+ case CHANNEL_LAYOUT_5_0_BACK:
+ return "5.0_BACK";
+ case CHANNEL_LAYOUT_5_1_BACK:
+ return "5.1_BACK";
+ case CHANNEL_LAYOUT_7_0:
+ return "7.0";
+ case CHANNEL_LAYOUT_7_1:
+ return "7.1";
+ case CHANNEL_LAYOUT_7_1_WIDE:
+ return "7.1_WIDE";
+ case CHANNEL_LAYOUT_STEREO_DOWNMIX:
+ return "STEREO_DOWNMIX";
+ case CHANNEL_LAYOUT_2POINT1:
+ return "2POINT1";
+ case CHANNEL_LAYOUT_3_1:
+ return "3.1";
+ case CHANNEL_LAYOUT_4_1:
+ return "4.1";
+ case CHANNEL_LAYOUT_6_0:
+ return "6.0";
+ case CHANNEL_LAYOUT_6_0_FRONT:
+ return "6.0_FRONT";
+ case CHANNEL_LAYOUT_HEXAGONAL:
+ return "HEXAGONAL";
+ case CHANNEL_LAYOUT_6_1:
+ return "6.1";
+ case CHANNEL_LAYOUT_6_1_BACK:
+ return "6.1_BACK";
+ case CHANNEL_LAYOUT_6_1_FRONT:
+ return "6.1_FRONT";
+ case CHANNEL_LAYOUT_7_0_FRONT:
+ return "7.0_FRONT";
+ case CHANNEL_LAYOUT_7_1_WIDE_BACK:
+ return "7.1_WIDE_BACK";
+ case CHANNEL_LAYOUT_OCTAGONAL:
+ return "OCTAGONAL";
+ case CHANNEL_LAYOUT_DISCRETE:
+ return "DISCRETE";
+ case CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC:
+ return "STEREO_AND_KEYBOARD_MIC";
+ case CHANNEL_LAYOUT_4_1_QUAD_SIDE:
+ return "4.1_QUAD_SIDE";
+ case CHANNEL_LAYOUT_BITSTREAM:
+ return "BITSTREAM";
+ }
+ RTC_NOTREACHED() << "Invalid channel layout provided: " << layout;
+ return "";
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/audio/channel_layout.h b/webrtc/api/audio/channel_layout.h
new file mode 100644
index 0000000..175aee7
--- /dev/null
+++ b/webrtc/api/audio/channel_layout.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_AUDIO_CHANNEL_LAYOUT_H_
+#define API_AUDIO_CHANNEL_LAYOUT_H_
+
+namespace webrtc {
+
+// This file is derived from Chromium's base/channel_layout.h.
+
+// Enumerates the various representations of the ordering of audio channels.
+// Logged to UMA, so never reuse a value, always add new/greater ones!
+enum ChannelLayout {
+ CHANNEL_LAYOUT_NONE = 0,
+ CHANNEL_LAYOUT_UNSUPPORTED = 1,
+
+ // Front C
+ CHANNEL_LAYOUT_MONO = 2,
+
+ // Front L, Front R
+ CHANNEL_LAYOUT_STEREO = 3,
+
+ // Front L, Front R, Back C
+ CHANNEL_LAYOUT_2_1 = 4,
+
+ // Front L, Front R, Front C
+ CHANNEL_LAYOUT_SURROUND = 5,
+
+ // Front L, Front R, Front C, Back C
+ CHANNEL_LAYOUT_4_0 = 6,
+
+ // Front L, Front R, Side L, Side R
+ CHANNEL_LAYOUT_2_2 = 7,
+
+ // Front L, Front R, Back L, Back R
+ CHANNEL_LAYOUT_QUAD = 8,
+
+ // Front L, Front R, Front C, Side L, Side R
+ CHANNEL_LAYOUT_5_0 = 9,
+
+ // Front L, Front R, Front C, LFE, Side L, Side R
+ CHANNEL_LAYOUT_5_1 = 10,
+
+ // Front L, Front R, Front C, Back L, Back R
+ CHANNEL_LAYOUT_5_0_BACK = 11,
+
+ // Front L, Front R, Front C, LFE, Back L, Back R
+ CHANNEL_LAYOUT_5_1_BACK = 12,
+
+ // Front L, Front R, Front C, Side L, Side R, Back L, Back R
+ CHANNEL_LAYOUT_7_0 = 13,
+
+ // Front L, Front R, Front C, LFE, Side L, Side R, Back L, Back R
+ CHANNEL_LAYOUT_7_1 = 14,
+
+ // Front L, Front R, Front C, LFE, Side L, Side R, Front LofC, Front RofC
+ CHANNEL_LAYOUT_7_1_WIDE = 15,
+
+ // Stereo L, Stereo R
+ CHANNEL_LAYOUT_STEREO_DOWNMIX = 16,
+
+ // Stereo L, Stereo R, LFE
+ CHANNEL_LAYOUT_2POINT1 = 17,
+
+ // Stereo L, Stereo R, Front C, LFE
+ CHANNEL_LAYOUT_3_1 = 18,
+
+ // Stereo L, Stereo R, Front C, Rear C, LFE
+ CHANNEL_LAYOUT_4_1 = 19,
+
+ // Stereo L, Stereo R, Front C, Side L, Side R, Back C
+ CHANNEL_LAYOUT_6_0 = 20,
+
+ // Stereo L, Stereo R, Side L, Side R, Front LofC, Front RofC
+ CHANNEL_LAYOUT_6_0_FRONT = 21,
+
+ // Stereo L, Stereo R, Front C, Rear L, Rear R, Rear C
+ CHANNEL_LAYOUT_HEXAGONAL = 22,
+
+ // Stereo L, Stereo R, Front C, LFE, Side L, Side R, Rear Center
+ CHANNEL_LAYOUT_6_1 = 23,
+
+ // Stereo L, Stereo R, Front C, LFE, Back L, Back R, Rear Center
+ CHANNEL_LAYOUT_6_1_BACK = 24,
+
+ // Stereo L, Stereo R, Side L, Side R, Front LofC, Front RofC, LFE
+ CHANNEL_LAYOUT_6_1_FRONT = 25,
+
+ // Front L, Front R, Front C, Side L, Side R, Front LofC, Front RofC
+ CHANNEL_LAYOUT_7_0_FRONT = 26,
+
+ // Front L, Front R, Front C, LFE, Back L, Back R, Front LofC, Front RofC
+ CHANNEL_LAYOUT_7_1_WIDE_BACK = 27,
+
+ // Front L, Front R, Front C, Side L, Side R, Rear L, Back R, Back C.
+ CHANNEL_LAYOUT_OCTAGONAL = 28,
+
+ // Channels are not explicitly mapped to speakers.
+ CHANNEL_LAYOUT_DISCRETE = 29,
+
+ // Front L, Front R, Front C. Front C contains the keyboard mic audio. This
+ // layout is only intended for input for WebRTC. The Front C channel
+ // is stripped away in the WebRTC audio input pipeline and never seen outside
+ // of that.
+ CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC = 30,
+
+ // Front L, Front R, Side L, Side R, LFE
+ CHANNEL_LAYOUT_4_1_QUAD_SIDE = 31,
+
+ // Actual channel layout is specified in the bitstream and the actual channel
+ // count is unknown at Chromium media pipeline level (useful for audio
+ // pass-through mode).
+ CHANNEL_LAYOUT_BITSTREAM = 32,
+
+ // Max value, must always equal the largest entry ever logged.
+ CHANNEL_LAYOUT_MAX = CHANNEL_LAYOUT_BITSTREAM
+};
+
+// Note: Do not reorder or reassign these values; other code depends on their
+// ordering to operate correctly. E.g., CoreAudio channel layout computations.
+enum Channels {
+ LEFT = 0,
+ RIGHT,
+ CENTER,
+ LFE,
+ BACK_LEFT,
+ BACK_RIGHT,
+ LEFT_OF_CENTER,
+ RIGHT_OF_CENTER,
+ BACK_CENTER,
+ SIDE_LEFT,
+ SIDE_RIGHT,
+ CHANNELS_MAX =
+ SIDE_RIGHT, // Must always equal the largest value ever logged.
+};
+
+// The maximum number of concurrently active channels for all possible layouts.
+// ChannelLayoutToChannelCount() will never return a value higher than this.
+constexpr int kMaxConcurrentChannels = 8;
+
+// Returns the expected channel position in an interleaved stream. Values of -1
+// mean the channel at that index is not used for that layout. Values range
+// from 0 to ChannelLayoutToChannelCount(layout) - 1.
+int ChannelOrder(ChannelLayout layout, Channels channel);
+
+// Returns the number of channels in a given ChannelLayout.
+int ChannelLayoutToChannelCount(ChannelLayout layout);
+
+// Given the number of channels, return the best layout,
+// or return CHANNEL_LAYOUT_UNSUPPORTED if there is no good match.
+ChannelLayout GuessChannelLayout(int channels);
+
+// Returns a string representation of the channel layout.
+const char* ChannelLayoutToString(ChannelLayout layout);
+
+} // namespace webrtc
+
+#endif // API_AUDIO_CHANNEL_LAYOUT_H_
diff --git a/webrtc/api/audio/echo_canceller3_config.cc b/webrtc/api/audio/echo_canceller3_config.cc
new file mode 100644
index 0000000..aeb809e
--- /dev/null
+++ b/webrtc/api/audio/echo_canceller3_config.cc
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/audio/echo_canceller3_config.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+namespace {
+bool Limit(float* value, float min, float max) {
+ float clamped = rtc::SafeClamp(*value, min, max);
+ clamped = std::isfinite(clamped) ? clamped : min;
+ bool res = *value == clamped;
+ *value = clamped;
+ return res;
+}
+
+bool Limit(size_t* value, size_t min, size_t max) {
+ size_t clamped = rtc::SafeClamp(*value, min, max);
+ bool res = *value == clamped;
+ *value = clamped;
+ return res;
+}
+
+bool Limit(int* value, int min, int max) {
+ int clamped = rtc::SafeClamp(*value, min, max);
+ bool res = *value == clamped;
+ *value = clamped;
+ return res;
+}
+
+bool FloorLimit(size_t* value, size_t min) {
+ size_t clamped = *value >= min ? *value : min;
+ bool res = *value == clamped;
+ *value = clamped;
+ return res;
+}
+
+} // namespace
+
+EchoCanceller3Config::EchoCanceller3Config() = default;
+EchoCanceller3Config::EchoCanceller3Config(const EchoCanceller3Config& e) =
+ default;
+EchoCanceller3Config& EchoCanceller3Config::operator=(
+ const EchoCanceller3Config& e) = default;
+EchoCanceller3Config::Delay::Delay() = default;
+EchoCanceller3Config::Delay::Delay(const EchoCanceller3Config::Delay& e) =
+ default;
+EchoCanceller3Config::Delay& EchoCanceller3Config::Delay::operator=(
+ const Delay& e) = default;
+
+EchoCanceller3Config::EchoModel::EchoModel() = default;
+EchoCanceller3Config::EchoModel::EchoModel(
+ const EchoCanceller3Config::EchoModel& e) = default;
+EchoCanceller3Config::EchoModel& EchoCanceller3Config::EchoModel::operator=(
+ const EchoModel& e) = default;
+
+EchoCanceller3Config::Suppressor::Suppressor() = default;
+EchoCanceller3Config::Suppressor::Suppressor(
+ const EchoCanceller3Config::Suppressor& e) = default;
+EchoCanceller3Config::Suppressor& EchoCanceller3Config::Suppressor::operator=(
+ const Suppressor& e) = default;
+
+EchoCanceller3Config::Suppressor::MaskingThresholds::MaskingThresholds(
+ float enr_transparent,
+ float enr_suppress,
+ float emr_transparent)
+ : enr_transparent(enr_transparent),
+ enr_suppress(enr_suppress),
+ emr_transparent(emr_transparent) {}
+EchoCanceller3Config::Suppressor::MaskingThresholds::MaskingThresholds(
+ const EchoCanceller3Config::Suppressor::MaskingThresholds& e) = default;
+EchoCanceller3Config::Suppressor::MaskingThresholds&
+EchoCanceller3Config::Suppressor::MaskingThresholds::operator=(
+ const MaskingThresholds& e) = default;
+
+EchoCanceller3Config::Suppressor::Tuning::Tuning(MaskingThresholds mask_lf,
+ MaskingThresholds mask_hf,
+ float max_inc_factor,
+ float max_dec_factor_lf)
+ : mask_lf(mask_lf),
+ mask_hf(mask_hf),
+ max_inc_factor(max_inc_factor),
+ max_dec_factor_lf(max_dec_factor_lf) {}
+EchoCanceller3Config::Suppressor::Tuning::Tuning(
+ const EchoCanceller3Config::Suppressor::Tuning& e) = default;
+EchoCanceller3Config::Suppressor::Tuning&
+EchoCanceller3Config::Suppressor::Tuning::operator=(const Tuning& e) = default;
+
+bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
+ RTC_DCHECK(config);
+ EchoCanceller3Config* c = config;
+ bool res = true;
+
+ if (c->delay.down_sampling_factor != 4 &&
+ c->delay.down_sampling_factor != 8) {
+ c->delay.down_sampling_factor = 4;
+ res = false;
+ }
+
+ res = res & Limit(&c->delay.default_delay, 0, 5000);
+ res = res & Limit(&c->delay.num_filters, 0, 5000);
+ res = res & Limit(&c->delay.delay_headroom_samples, 0, 5000);
+ res = res & Limit(&c->delay.hysteresis_limit_blocks, 0, 5000);
+ res = res & Limit(&c->delay.fixed_capture_delay_samples, 0, 5000);
+ res = res & Limit(&c->delay.delay_estimate_smoothing, 0.f, 1.f);
+ res = res & Limit(&c->delay.delay_candidate_detection_threshold, 0.f, 1.f);
+ res = res & Limit(&c->delay.delay_selection_thresholds.initial, 1, 250);
+ res = res & Limit(&c->delay.delay_selection_thresholds.converged, 1, 250);
+
+ res = res & FloorLimit(&c->filter.refined.length_blocks, 1);
+ res = res & Limit(&c->filter.refined.leakage_converged, 0.f, 1000.f);
+ res = res & Limit(&c->filter.refined.leakage_diverged, 0.f, 1000.f);
+ res = res & Limit(&c->filter.refined.error_floor, 0.f, 1000.f);
+ res = res & Limit(&c->filter.refined.error_ceil, 0.f, 100000000.f);
+ res = res & Limit(&c->filter.refined.noise_gate, 0.f, 100000000.f);
+
+ res = res & FloorLimit(&c->filter.refined_initial.length_blocks, 1);
+ res = res & Limit(&c->filter.refined_initial.leakage_converged, 0.f, 1000.f);
+ res = res & Limit(&c->filter.refined_initial.leakage_diverged, 0.f, 1000.f);
+ res = res & Limit(&c->filter.refined_initial.error_floor, 0.f, 1000.f);
+ res = res & Limit(&c->filter.refined_initial.error_ceil, 0.f, 100000000.f);
+ res = res & Limit(&c->filter.refined_initial.noise_gate, 0.f, 100000000.f);
+
+ if (c->filter.refined.length_blocks <
+ c->filter.refined_initial.length_blocks) {
+ c->filter.refined_initial.length_blocks = c->filter.refined.length_blocks;
+ res = false;
+ }
+
+ res = res & FloorLimit(&c->filter.coarse.length_blocks, 1);
+ res = res & Limit(&c->filter.coarse.rate, 0.f, 1.f);
+ res = res & Limit(&c->filter.coarse.noise_gate, 0.f, 100000000.f);
+
+ res = res & FloorLimit(&c->filter.coarse_initial.length_blocks, 1);
+ res = res & Limit(&c->filter.coarse_initial.rate, 0.f, 1.f);
+ res = res & Limit(&c->filter.coarse_initial.noise_gate, 0.f, 100000000.f);
+
+ if (c->filter.coarse.length_blocks < c->filter.coarse_initial.length_blocks) {
+ c->filter.coarse_initial.length_blocks = c->filter.coarse.length_blocks;
+ res = false;
+ }
+
+ res = res & Limit(&c->filter.config_change_duration_blocks, 0, 100000);
+ res = res & Limit(&c->filter.initial_state_seconds, 0.f, 100.f);
+
+ res = res & Limit(&c->erle.min, 1.f, 100000.f);
+ res = res & Limit(&c->erle.max_l, 1.f, 100000.f);
+ res = res & Limit(&c->erle.max_h, 1.f, 100000.f);
+ if (c->erle.min > c->erle.max_l || c->erle.min > c->erle.max_h) {
+ c->erle.min = std::min(c->erle.max_l, c->erle.max_h);
+ res = false;
+ }
+ res = res & Limit(&c->erle.num_sections, 1, c->filter.refined.length_blocks);
+
+ res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f);
+ res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f);
+
+ res =
+ res & Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f);
+ res = res &
+ Limit(&c->echo_audibility.normal_render_limit, 0.f, 32768.f * 32768.f);
+ res = res & Limit(&c->echo_audibility.floor_power, 0.f, 32768.f * 32768.f);
+ res = res & Limit(&c->echo_audibility.audibility_threshold_lf, 0.f,
+ 32768.f * 32768.f);
+ res = res & Limit(&c->echo_audibility.audibility_threshold_mf, 0.f,
+ 32768.f * 32768.f);
+ res = res & Limit(&c->echo_audibility.audibility_threshold_hf, 0.f,
+ 32768.f * 32768.f);
+
+ res = res &
+ Limit(&c->render_levels.active_render_limit, 0.f, 32768.f * 32768.f);
+ res = res & Limit(&c->render_levels.poor_excitation_render_limit, 0.f,
+ 32768.f * 32768.f);
+ res = res & Limit(&c->render_levels.poor_excitation_render_limit_ds8, 0.f,
+ 32768.f * 32768.f);
+
+ res = res & Limit(&c->echo_model.noise_floor_hold, 0, 1000);
+ res = res & Limit(&c->echo_model.min_noise_floor_power, 0, 2000000.f);
+ res = res & Limit(&c->echo_model.stationary_gate_slope, 0, 1000000.f);
+ res = res & Limit(&c->echo_model.noise_gate_power, 0, 1000000.f);
+ res = res & Limit(&c->echo_model.noise_gate_slope, 0, 1000000.f);
+ res = res & Limit(&c->echo_model.render_pre_window_size, 0, 100);
+ res = res & Limit(&c->echo_model.render_post_window_size, 0, 100);
+
+ res = res & Limit(&c->comfort_noise.noise_floor_dbfs, -200.f, 0.f);
+
+ res = res & Limit(&c->suppressor.nearend_average_blocks, 1, 5000);
+
+ res = res &
+ Limit(&c->suppressor.normal_tuning.mask_lf.enr_transparent, 0.f, 100.f);
+ res = res &
+ Limit(&c->suppressor.normal_tuning.mask_lf.enr_suppress, 0.f, 100.f);
+ res = res &
+ Limit(&c->suppressor.normal_tuning.mask_lf.emr_transparent, 0.f, 100.f);
+ res = res &
+ Limit(&c->suppressor.normal_tuning.mask_hf.enr_transparent, 0.f, 100.f);
+ res = res &
+ Limit(&c->suppressor.normal_tuning.mask_hf.enr_suppress, 0.f, 100.f);
+ res = res &
+ Limit(&c->suppressor.normal_tuning.mask_hf.emr_transparent, 0.f, 100.f);
+ res = res & Limit(&c->suppressor.normal_tuning.max_inc_factor, 0.f, 100.f);
+ res = res & Limit(&c->suppressor.normal_tuning.max_dec_factor_lf, 0.f, 100.f);
+
+ res = res & Limit(&c->suppressor.nearend_tuning.mask_lf.enr_transparent, 0.f,
+ 100.f);
+ res = res &
+ Limit(&c->suppressor.nearend_tuning.mask_lf.enr_suppress, 0.f, 100.f);
+ res = res & Limit(&c->suppressor.nearend_tuning.mask_lf.emr_transparent, 0.f,
+ 100.f);
+ res = res & Limit(&c->suppressor.nearend_tuning.mask_hf.enr_transparent, 0.f,
+ 100.f);
+ res = res &
+ Limit(&c->suppressor.nearend_tuning.mask_hf.enr_suppress, 0.f, 100.f);
+ res = res & Limit(&c->suppressor.nearend_tuning.mask_hf.emr_transparent, 0.f,
+ 100.f);
+ res = res & Limit(&c->suppressor.nearend_tuning.max_inc_factor, 0.f, 100.f);
+ res =
+ res & Limit(&c->suppressor.nearend_tuning.max_dec_factor_lf, 0.f, 100.f);
+
+ res = res & Limit(&c->suppressor.dominant_nearend_detection.enr_threshold,
+ 0.f, 1000000.f);
+ res = res & Limit(&c->suppressor.dominant_nearend_detection.snr_threshold,
+ 0.f, 1000000.f);
+ res = res & Limit(&c->suppressor.dominant_nearend_detection.hold_duration, 0,
+ 10000);
+ res = res & Limit(&c->suppressor.dominant_nearend_detection.trigger_threshold,
+ 0, 10000);
+
+ res = res &
+ Limit(&c->suppressor.subband_nearend_detection.nearend_average_blocks,
+ 1, 1024);
+ res =
+ res & Limit(&c->suppressor.subband_nearend_detection.subband1.low, 0, 65);
+ res = res & Limit(&c->suppressor.subband_nearend_detection.subband1.high,
+ c->suppressor.subband_nearend_detection.subband1.low, 65);
+ res =
+ res & Limit(&c->suppressor.subband_nearend_detection.subband2.low, 0, 65);
+ res = res & Limit(&c->suppressor.subband_nearend_detection.subband2.high,
+ c->suppressor.subband_nearend_detection.subband2.low, 65);
+ res = res & Limit(&c->suppressor.subband_nearend_detection.nearend_threshold,
+ 0.f, 1.e24f);
+ res = res & Limit(&c->suppressor.subband_nearend_detection.snr_threshold, 0.f,
+ 1.e24f);
+
+ res = res & Limit(&c->suppressor.high_bands_suppression.enr_threshold, 0.f,
+ 1000000.f);
+ res = res & Limit(&c->suppressor.high_bands_suppression.max_gain_during_echo,
+ 0.f, 1.f);
+ res = res & Limit(&c->suppressor.high_bands_suppression
+ .anti_howling_activation_threshold,
+ 0.f, 32768.f * 32768.f);
+ res = res & Limit(&c->suppressor.high_bands_suppression.anti_howling_gain,
+ 0.f, 1.f);
+
+ res = res & Limit(&c->suppressor.floor_first_increase, 0.f, 1000000.f);
+
+ return res;
+}
+} // namespace webrtc
diff --git a/webrtc/api/audio/echo_canceller3_config.h b/webrtc/api/audio/echo_canceller3_config.h
new file mode 100644
index 0000000..af57d04
--- /dev/null
+++ b/webrtc/api/audio/echo_canceller3_config.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_AUDIO_ECHO_CANCELLER3_CONFIG_H_
+#define API_AUDIO_ECHO_CANCELLER3_CONFIG_H_
+
+#include <stddef.h> // size_t
+
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+
+// Configuration struct for EchoCanceller3
+struct RTC_EXPORT EchoCanceller3Config {
+ // Checks and updates the config parameters to lie within (mostly) reasonable
+ // ranges. Returns true if and only of the config did not need to be changed.
+ static bool Validate(EchoCanceller3Config* config);
+
+ EchoCanceller3Config();
+ EchoCanceller3Config(const EchoCanceller3Config& e);
+ EchoCanceller3Config& operator=(const EchoCanceller3Config& other);
+
+ struct Buffering {
+ size_t excess_render_detection_interval_blocks = 250;
+ size_t max_allowed_excess_render_blocks = 8;
+ } buffering;
+
+ struct Delay {
+ Delay();
+ Delay(const Delay& e);
+ Delay& operator=(const Delay& e);
+ size_t default_delay = 5;
+ size_t down_sampling_factor = 4;
+ size_t num_filters = 5;
+ size_t delay_headroom_samples = 32;
+ size_t hysteresis_limit_blocks = 1;
+ size_t fixed_capture_delay_samples = 0;
+ float delay_estimate_smoothing = 0.7f;
+ float delay_candidate_detection_threshold = 0.2f;
+ struct DelaySelectionThresholds {
+ int initial;
+ int converged;
+ } delay_selection_thresholds = {5, 20};
+ bool use_external_delay_estimator = false;
+ bool log_warning_on_delay_changes = false;
+ struct AlignmentMixing {
+ bool downmix;
+ bool adaptive_selection;
+ float activity_power_threshold;
+ bool prefer_first_two_channels;
+ };
+ AlignmentMixing render_alignment_mixing = {false, true, 10000.f, true};
+ AlignmentMixing capture_alignment_mixing = {false, true, 10000.f, false};
+ } delay;
+
+ struct Filter {
+ struct RefinedConfiguration {
+ size_t length_blocks;
+ float leakage_converged;
+ float leakage_diverged;
+ float error_floor;
+ float error_ceil;
+ float noise_gate;
+ };
+
+ struct CoarseConfiguration {
+ size_t length_blocks;
+ float rate;
+ float noise_gate;
+ };
+
+ RefinedConfiguration refined = {13, 0.00005f, 0.05f,
+ 0.001f, 2.f, 20075344.f};
+ CoarseConfiguration coarse = {13, 0.7f, 20075344.f};
+
+ RefinedConfiguration refined_initial = {12, 0.005f, 0.5f,
+ 0.001f, 2.f, 20075344.f};
+ CoarseConfiguration coarse_initial = {12, 0.9f, 20075344.f};
+
+ size_t config_change_duration_blocks = 250;
+ float initial_state_seconds = 2.5f;
+ bool conservative_initial_phase = false;
+ bool enable_coarse_filter_output_usage = true;
+ bool use_linear_filter = true;
+ bool export_linear_aec_output = false;
+ } filter;
+
+ struct Erle {
+ float min = 1.f;
+ float max_l = 4.f;
+ float max_h = 1.5f;
+ bool onset_detection = true;
+ size_t num_sections = 1;
+ bool clamp_quality_estimate_to_zero = true;
+ bool clamp_quality_estimate_to_one = true;
+ } erle;
+
+ struct EpStrength {
+ float default_gain = 1.f;
+ float default_len = 0.83f;
+ bool echo_can_saturate = true;
+ bool bounded_erl = false;
+ } ep_strength;
+
+ struct EchoAudibility {
+ float low_render_limit = 4 * 64.f;
+ float normal_render_limit = 64.f;
+ float floor_power = 2 * 64.f;
+ float audibility_threshold_lf = 10;
+ float audibility_threshold_mf = 10;
+ float audibility_threshold_hf = 10;
+ bool use_stationarity_properties = false;
+ bool use_stationarity_properties_at_init = false;
+ } echo_audibility;
+
+ struct RenderLevels {
+ float active_render_limit = 100.f;
+ float poor_excitation_render_limit = 150.f;
+ float poor_excitation_render_limit_ds8 = 20.f;
+ float render_power_gain_db = 0.f;
+ } render_levels;
+
+ struct EchoRemovalControl {
+ bool has_clock_drift = false;
+ bool linear_and_stable_echo_path = false;
+ } echo_removal_control;
+
+ struct EchoModel {
+ EchoModel();
+ EchoModel(const EchoModel& e);
+ EchoModel& operator=(const EchoModel& e);
+ size_t noise_floor_hold = 50;
+ float min_noise_floor_power = 1638400.f;
+ float stationary_gate_slope = 10.f;
+ float noise_gate_power = 27509.42f;
+ float noise_gate_slope = 0.3f;
+ size_t render_pre_window_size = 1;
+ size_t render_post_window_size = 1;
+ bool model_reverb_in_nonlinear_mode = true;
+ } echo_model;
+
+ struct ComfortNoise {
+ float noise_floor_dbfs = -96.03406f;
+ } comfort_noise;
+
+ struct Suppressor {
+ Suppressor();
+ Suppressor(const Suppressor& e);
+ Suppressor& operator=(const Suppressor& e);
+
+ size_t nearend_average_blocks = 4;
+
+ struct MaskingThresholds {
+ MaskingThresholds(float enr_transparent,
+ float enr_suppress,
+ float emr_transparent);
+ MaskingThresholds(const MaskingThresholds& e);
+ MaskingThresholds& operator=(const MaskingThresholds& e);
+ float enr_transparent;
+ float enr_suppress;
+ float emr_transparent;
+ };
+
+ struct Tuning {
+ Tuning(MaskingThresholds mask_lf,
+ MaskingThresholds mask_hf,
+ float max_inc_factor,
+ float max_dec_factor_lf);
+ Tuning(const Tuning& e);
+ Tuning& operator=(const Tuning& e);
+ MaskingThresholds mask_lf;
+ MaskingThresholds mask_hf;
+ float max_inc_factor;
+ float max_dec_factor_lf;
+ };
+
+ Tuning normal_tuning = Tuning(MaskingThresholds(.3f, .4f, .3f),
+ MaskingThresholds(.07f, .1f, .3f),
+ 2.0f,
+ 0.25f);
+ Tuning nearend_tuning = Tuning(MaskingThresholds(1.09f, 1.1f, .3f),
+ MaskingThresholds(.1f, .3f, .3f),
+ 2.0f,
+ 0.25f);
+
+ struct DominantNearendDetection {
+ float enr_threshold = .25f;
+ float enr_exit_threshold = 10.f;
+ float snr_threshold = 30.f;
+ int hold_duration = 50;
+ int trigger_threshold = 12;
+ bool use_during_initial_phase = true;
+ } dominant_nearend_detection;
+
+ struct SubbandNearendDetection {
+ size_t nearend_average_blocks = 1;
+ struct SubbandRegion {
+ size_t low;
+ size_t high;
+ };
+ SubbandRegion subband1 = {1, 1};
+ SubbandRegion subband2 = {1, 1};
+ float nearend_threshold = 1.f;
+ float snr_threshold = 1.f;
+ } subband_nearend_detection;
+
+ bool use_subband_nearend_detection = false;
+
+ struct HighBandsSuppression {
+ float enr_threshold = 1.f;
+ float max_gain_during_echo = 1.f;
+ float anti_howling_activation_threshold = 400.f;
+ float anti_howling_gain = 1.f;
+ } high_bands_suppression;
+
+ float floor_first_increase = 0.00001f;
+ } suppressor;
+};
+} // namespace webrtc
+
+#endif // API_AUDIO_ECHO_CANCELLER3_CONFIG_H_
diff --git a/webrtc/api/audio/echo_control.h b/webrtc/api/audio/echo_control.h
new file mode 100644
index 0000000..8d567bf
--- /dev/null
+++ b/webrtc/api/audio/echo_control.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_AUDIO_ECHO_CONTROL_H_
+#define API_AUDIO_ECHO_CONTROL_H_
+
+#include <memory>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+class AudioBuffer;
+
+// Interface for an acoustic echo cancellation (AEC) submodule.
+class EchoControl {
+ public:
+ // Analysis (not changing) of the render signal.
+ virtual void AnalyzeRender(AudioBuffer* render) = 0;
+
+ // Analysis (not changing) of the capture signal.
+ virtual void AnalyzeCapture(AudioBuffer* capture) = 0;
+
+ // Processes the capture signal in order to remove the echo.
+ virtual void ProcessCapture(AudioBuffer* capture, bool level_change) = 0;
+
+ // As above, but also returns the linear filter output.
+ virtual void ProcessCapture(AudioBuffer* capture,
+ AudioBuffer* linear_output,
+ bool level_change) = 0;
+
+ struct Metrics {
+ double echo_return_loss;
+ double echo_return_loss_enhancement;
+ int delay_ms;
+ };
+
+ // Collect current metrics from the echo controller.
+ virtual Metrics GetMetrics() const = 0;
+
+ // Provides an optional external estimate of the audio buffer delay.
+ virtual void SetAudioBufferDelay(int delay_ms) = 0;
+
+ // Returns wheter the signal is altered.
+ virtual bool ActiveProcessing() const = 0;
+
+ virtual ~EchoControl() {}
+};
+
+// Interface for a factory that creates EchoControllers.
+class EchoControlFactory {
+ public:
+ virtual std::unique_ptr<EchoControl> Create(int sample_rate_hz,
+ int num_render_channels,
+ int num_capture_channels) = 0;
+
+ virtual ~EchoControlFactory() = default;
+};
+} // namespace webrtc
+
+#endif // API_AUDIO_ECHO_CONTROL_H_
diff --git a/webrtc/api/audio_codecs/audio_decoder.cc b/webrtc/api/audio_codecs/audio_decoder.cc
new file mode 100644
index 0000000..97cda27
--- /dev/null
+++ b/webrtc/api/audio_codecs/audio_decoder.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 "api/audio_codecs/audio_decoder.h"
+
+#include <assert.h>
+
+#include <memory>
+#include <utility>
+
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/sanitizer.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+
+namespace {
+
+class OldStyleEncodedFrame final : public AudioDecoder::EncodedAudioFrame {
+ public:
+ OldStyleEncodedFrame(AudioDecoder* decoder, rtc::Buffer&& payload)
+ : decoder_(decoder), payload_(std::move(payload)) {}
+
+ size_t Duration() const override {
+ const int ret = decoder_->PacketDuration(payload_.data(), payload_.size());
+ return ret < 0 ? 0 : static_cast<size_t>(ret);
+ }
+
+ absl::optional<DecodeResult> Decode(
+ rtc::ArrayView<int16_t> decoded) const override {
+ auto speech_type = AudioDecoder::kSpeech;
+ const int ret = decoder_->Decode(
+ payload_.data(), payload_.size(), decoder_->SampleRateHz(),
+ decoded.size() * sizeof(int16_t), decoded.data(), &speech_type);
+ return ret < 0 ? absl::nullopt
+ : absl::optional<DecodeResult>(
+ {static_cast<size_t>(ret), speech_type});
+ }
+
+ private:
+ AudioDecoder* const decoder_;
+ const rtc::Buffer payload_;
+};
+
+} // namespace
+
+bool AudioDecoder::EncodedAudioFrame::IsDtxPacket() const {
+ return false;
+}
+
+AudioDecoder::ParseResult::ParseResult() = default;
+AudioDecoder::ParseResult::ParseResult(ParseResult&& b) = default;
+AudioDecoder::ParseResult::ParseResult(uint32_t timestamp,
+ int priority,
+ std::unique_ptr<EncodedAudioFrame> frame)
+ : timestamp(timestamp), priority(priority), frame(std::move(frame)) {
+ RTC_DCHECK_GE(priority, 0);
+}
+
+AudioDecoder::ParseResult::~ParseResult() = default;
+
+AudioDecoder::ParseResult& AudioDecoder::ParseResult::operator=(
+ ParseResult&& b) = default;
+
+std::vector<AudioDecoder::ParseResult> AudioDecoder::ParsePayload(
+ rtc::Buffer&& payload,
+ uint32_t timestamp) {
+ std::vector<ParseResult> results;
+ std::unique_ptr<EncodedAudioFrame> frame(
+ new OldStyleEncodedFrame(this, std::move(payload)));
+ results.emplace_back(timestamp, 0, std::move(frame));
+ return results;
+}
+
+int AudioDecoder::Decode(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ size_t max_decoded_bytes,
+ int16_t* decoded,
+ SpeechType* speech_type) {
+ TRACE_EVENT0("webrtc", "AudioDecoder::Decode");
+ rtc::MsanCheckInitialized(rtc::MakeArrayView(encoded, encoded_len));
+ int duration = PacketDuration(encoded, encoded_len);
+ if (duration >= 0 &&
+ duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
+ return -1;
+ }
+ return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
+ speech_type);
+}
+
+int AudioDecoder::DecodeRedundant(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ size_t max_decoded_bytes,
+ int16_t* decoded,
+ SpeechType* speech_type) {
+ TRACE_EVENT0("webrtc", "AudioDecoder::DecodeRedundant");
+ rtc::MsanCheckInitialized(rtc::MakeArrayView(encoded, encoded_len));
+ int duration = PacketDurationRedundant(encoded, encoded_len);
+ if (duration >= 0 &&
+ duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
+ return -1;
+ }
+ return DecodeRedundantInternal(encoded, encoded_len, sample_rate_hz, decoded,
+ speech_type);
+}
+
+int AudioDecoder::DecodeRedundantInternal(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ int16_t* decoded,
+ SpeechType* speech_type) {
+ return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
+ speech_type);
+}
+
+bool AudioDecoder::HasDecodePlc() const {
+ return false;
+}
+
+size_t AudioDecoder::DecodePlc(size_t num_frames, int16_t* decoded) {
+ return 0;
+}
+
+// TODO(bugs.webrtc.org/9676): Remove default implementation.
+void AudioDecoder::GeneratePlc(size_t /*requested_samples_per_channel*/,
+ rtc::BufferT<int16_t>* /*concealment_audio*/) {}
+
+int AudioDecoder::ErrorCode() {
+ return 0;
+}
+
+int AudioDecoder::PacketDuration(const uint8_t* encoded,
+ size_t encoded_len) const {
+ return kNotImplemented;
+}
+
+int AudioDecoder::PacketDurationRedundant(const uint8_t* encoded,
+ size_t encoded_len) const {
+ return kNotImplemented;
+}
+
+bool AudioDecoder::PacketHasFec(const uint8_t* encoded,
+ size_t encoded_len) const {
+ return false;
+}
+
+AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) {
+ switch (type) {
+ case 0: // TODO(hlundin): Both iSAC and Opus return 0 for speech.
+ case 1:
+ return kSpeech;
+ case 2:
+ return kComfortNoise;
+ default:
+ assert(false);
+ return kSpeech;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/audio_codecs/audio_decoder.h b/webrtc/api/audio_codecs/audio_decoder.h
new file mode 100644
index 0000000..557ffe2
--- /dev/null
+++ b/webrtc/api/audio_codecs/audio_decoder.h
@@ -0,0 +1,193 @@
+/*
+ * 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 API_AUDIO_CODECS_AUDIO_DECODER_H_
+#define API_AUDIO_CODECS_AUDIO_DECODER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class AudioDecoder {
+ public:
+ enum SpeechType {
+ kSpeech = 1,
+ kComfortNoise = 2,
+ };
+
+ // Used by PacketDuration below. Save the value -1 for errors.
+ enum { kNotImplemented = -2 };
+
+ AudioDecoder() = default;
+ virtual ~AudioDecoder() = default;
+
+ class EncodedAudioFrame {
+ public:
+ struct DecodeResult {
+ size_t num_decoded_samples;
+ SpeechType speech_type;
+ };
+
+ virtual ~EncodedAudioFrame() = default;
+
+ // Returns the duration in samples-per-channel of this audio frame.
+ // If no duration can be ascertained, returns zero.
+ virtual size_t Duration() const = 0;
+
+ // Returns true if this packet contains DTX.
+ virtual bool IsDtxPacket() const;
+
+ // Decodes this frame of audio and writes the result in |decoded|.
+ // |decoded| must be large enough to store as many samples as indicated by a
+ // call to Duration() . On success, returns an absl::optional containing the
+ // total number of samples across all channels, as well as whether the
+ // decoder produced comfort noise or speech. On failure, returns an empty
+ // absl::optional. Decode may be called at most once per frame object.
+ virtual absl::optional<DecodeResult> Decode(
+ rtc::ArrayView<int16_t> decoded) const = 0;
+ };
+
+ struct ParseResult {
+ ParseResult();
+ ParseResult(uint32_t timestamp,
+ int priority,
+ std::unique_ptr<EncodedAudioFrame> frame);
+ ParseResult(ParseResult&& b);
+ ~ParseResult();
+
+ ParseResult& operator=(ParseResult&& b);
+
+ // The timestamp of the frame is in samples per channel.
+ uint32_t timestamp;
+ // The relative priority of the frame compared to other frames of the same
+ // payload and the same timeframe. A higher value means a lower priority.
+ // The highest priority is zero - negative values are not allowed.
+ int priority;
+ std::unique_ptr<EncodedAudioFrame> frame;
+ };
+
+ // Let the decoder parse this payload and prepare zero or more decodable
+ // frames. Each frame must be between 10 ms and 120 ms long. The caller must
+ // ensure that the AudioDecoder object outlives any frame objects returned by
+ // this call. The decoder is free to swap or move the data from the |payload|
+ // buffer. |timestamp| is the input timestamp, in samples, corresponding to
+ // the start of the payload.
+ virtual std::vector<ParseResult> ParsePayload(rtc::Buffer&& payload,
+ uint32_t timestamp);
+
+ // TODO(bugs.webrtc.org/10098): The Decode and DecodeRedundant methods are
+ // obsolete; callers should call ParsePayload instead. For now, subclasses
+ // must still implement DecodeInternal.
+
+ // Decodes |encode_len| bytes from |encoded| and writes the result in
+ // |decoded|. The maximum bytes allowed to be written into |decoded| is
+ // |max_decoded_bytes|. Returns the total number of samples across all
+ // channels. If the decoder produced comfort noise, |speech_type|
+ // is set to kComfortNoise, otherwise it is kSpeech. The desired output
+ // sample rate is provided in |sample_rate_hz|, which must be valid for the
+ // codec at hand.
+ int Decode(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ size_t max_decoded_bytes,
+ int16_t* decoded,
+ SpeechType* speech_type);
+
+ // Same as Decode(), but interfaces to the decoders redundant decode function.
+ // The default implementation simply calls the regular Decode() method.
+ int DecodeRedundant(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ size_t max_decoded_bytes,
+ int16_t* decoded,
+ SpeechType* speech_type);
+
+ // Indicates if the decoder implements the DecodePlc method.
+ virtual bool HasDecodePlc() const;
+
+ // Calls the packet-loss concealment of the decoder to update the state after
+ // one or several lost packets. The caller has to make sure that the
+ // memory allocated in |decoded| should accommodate |num_frames| frames.
+ virtual size_t DecodePlc(size_t num_frames, int16_t* decoded);
+
+ // Asks the decoder to generate packet-loss concealment and append it to the
+ // end of |concealment_audio|. The concealment audio should be in
+ // channel-interleaved format, with as many channels as the last decoded
+ // packet produced. The implementation must produce at least
+ // requested_samples_per_channel, or nothing at all. This is a signal to the
+ // caller to conceal the loss with other means. If the implementation provides
+ // concealment samples, it is also responsible for "stitching" it together
+ // with the decoded audio on either side of the concealment.
+ // Note: The default implementation of GeneratePlc will be deleted soon. All
+ // implementations must provide their own, which can be a simple as a no-op.
+ // TODO(bugs.webrtc.org/9676): Remove default impementation.
+ virtual void GeneratePlc(size_t requested_samples_per_channel,
+ rtc::BufferT<int16_t>* concealment_audio);
+
+ // Resets the decoder state (empty buffers etc.).
+ virtual void Reset() = 0;
+
+ // Returns the last error code from the decoder.
+ virtual int ErrorCode();
+
+ // Returns the duration in samples-per-channel of the payload in |encoded|
+ // which is |encoded_len| bytes long. Returns kNotImplemented if no duration
+ // estimate is available, or -1 in case of an error.
+ virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
+
+ // Returns the duration in samples-per-channel of the redandant payload in
+ // |encoded| which is |encoded_len| bytes long. Returns kNotImplemented if no
+ // duration estimate is available, or -1 in case of an error.
+ virtual int PacketDurationRedundant(const uint8_t* encoded,
+ size_t encoded_len) const;
+
+ // Detects whether a packet has forward error correction. The packet is
+ // comprised of the samples in |encoded| which is |encoded_len| bytes long.
+ // Returns true if the packet has FEC and false otherwise.
+ virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
+
+ // Returns the actual sample rate of the decoder's output. This value may not
+ // change during the lifetime of the decoder.
+ virtual int SampleRateHz() const = 0;
+
+ // The number of channels in the decoder's output. This value may not change
+ // during the lifetime of the decoder.
+ virtual size_t Channels() const = 0;
+
+ protected:
+ static SpeechType ConvertSpeechType(int16_t type);
+
+ virtual int DecodeInternal(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ int16_t* decoded,
+ SpeechType* speech_type) = 0;
+
+ virtual int DecodeRedundantInternal(const uint8_t* encoded,
+ size_t encoded_len,
+ int sample_rate_hz,
+ int16_t* decoded,
+ SpeechType* speech_type);
+
+ private:
+ RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoder);
+};
+
+} // namespace webrtc
+#endif // API_AUDIO_CODECS_AUDIO_DECODER_H_
diff --git a/webrtc/api/audio_codecs/audio_encoder.cc b/webrtc/api/audio_codecs/audio_encoder.cc
new file mode 100644
index 0000000..cd4d200
--- /dev/null
+++ b/webrtc/api/audio_codecs/audio_encoder.cc
@@ -0,0 +1,113 @@
+/*
+ * 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 "api/audio_codecs/audio_encoder.h"
+
+#include "rtc_base/checks.h"
+#include "rtc_base/trace_event.h"
+
+namespace webrtc {
+
+ANAStats::ANAStats() = default;
+ANAStats::~ANAStats() = default;
+ANAStats::ANAStats(const ANAStats&) = default;
+
+AudioEncoder::EncodedInfo::EncodedInfo() = default;
+AudioEncoder::EncodedInfo::EncodedInfo(const EncodedInfo&) = default;
+AudioEncoder::EncodedInfo::EncodedInfo(EncodedInfo&&) = default;
+AudioEncoder::EncodedInfo::~EncodedInfo() = default;
+AudioEncoder::EncodedInfo& AudioEncoder::EncodedInfo::operator=(
+ const EncodedInfo&) = default;
+AudioEncoder::EncodedInfo& AudioEncoder::EncodedInfo::operator=(EncodedInfo&&) =
+ default;
+
+int AudioEncoder::RtpTimestampRateHz() const {
+ return SampleRateHz();
+}
+
+AudioEncoder::EncodedInfo AudioEncoder::Encode(
+ uint32_t rtp_timestamp,
+ rtc::ArrayView<const int16_t> audio,
+ rtc::Buffer* encoded) {
+ TRACE_EVENT0("webrtc", "AudioEncoder::Encode");
+ RTC_CHECK_EQ(audio.size(),
+ static_cast<size_t>(NumChannels() * SampleRateHz() / 100));
+
+ const size_t old_size = encoded->size();
+ EncodedInfo info = EncodeImpl(rtp_timestamp, audio, encoded);
+ RTC_CHECK_EQ(encoded->size() - old_size, info.encoded_bytes);
+ return info;
+}
+
+bool AudioEncoder::SetFec(bool enable) {
+ return !enable;
+}
+
+bool AudioEncoder::SetDtx(bool enable) {
+ return !enable;
+}
+
+bool AudioEncoder::GetDtx() const {
+ return false;
+}
+
+bool AudioEncoder::SetApplication(Application application) {
+ return false;
+}
+
+void AudioEncoder::SetMaxPlaybackRate(int frequency_hz) {}
+
+void AudioEncoder::SetTargetBitrate(int target_bps) {}
+
+rtc::ArrayView<std::unique_ptr<AudioEncoder>>
+AudioEncoder::ReclaimContainedEncoders() {
+ return nullptr;
+}
+
+bool AudioEncoder::EnableAudioNetworkAdaptor(const std::string& config_string,
+ RtcEventLog* event_log) {
+ return false;
+}
+
+void AudioEncoder::DisableAudioNetworkAdaptor() {}
+
+void AudioEncoder::OnReceivedUplinkPacketLossFraction(
+ float uplink_packet_loss_fraction) {}
+
+void AudioEncoder::OnReceivedUplinkRecoverablePacketLossFraction(
+ float uplink_recoverable_packet_loss_fraction) {
+ RTC_NOTREACHED();
+}
+
+void AudioEncoder::OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) {
+ OnReceivedUplinkBandwidth(target_audio_bitrate_bps, absl::nullopt);
+}
+
+void AudioEncoder::OnReceivedUplinkBandwidth(
+ int target_audio_bitrate_bps,
+ absl::optional<int64_t> bwe_period_ms) {}
+
+void AudioEncoder::OnReceivedUplinkAllocation(BitrateAllocationUpdate update) {
+ OnReceivedUplinkBandwidth(update.target_bitrate.bps(),
+ update.bwe_period.ms());
+}
+
+void AudioEncoder::OnReceivedRtt(int rtt_ms) {}
+
+void AudioEncoder::OnReceivedOverhead(size_t overhead_bytes_per_packet) {}
+
+void AudioEncoder::SetReceiverFrameLengthRange(int min_frame_length_ms,
+ int max_frame_length_ms) {}
+
+ANAStats AudioEncoder::GetANAStats() const {
+ return ANAStats();
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/audio_codecs/audio_encoder.h b/webrtc/api/audio_codecs/audio_encoder.h
new file mode 100644
index 0000000..fd2d948
--- /dev/null
+++ b/webrtc/api/audio_codecs/audio_encoder.h
@@ -0,0 +1,257 @@
+/*
+ * 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 API_AUDIO_CODECS_AUDIO_ENCODER_H_
+#define API_AUDIO_CODECS_AUDIO_ENCODER_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/call/bitrate_allocation.h"
+#include "api/units/time_delta.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/deprecation.h"
+
+namespace webrtc {
+
+class RtcEventLog;
+
+// Statistics related to Audio Network Adaptation.
+struct ANAStats {
+ ANAStats();
+ ANAStats(const ANAStats&);
+ ~ANAStats();
+ // Number of actions taken by the ANA bitrate controller since the start of
+ // the call. If this value is not set, it indicates that the bitrate
+ // controller is disabled.
+ absl::optional<uint32_t> bitrate_action_counter;
+ // Number of actions taken by the ANA channel controller since the start of
+ // the call. If this value is not set, it indicates that the channel
+ // controller is disabled.
+ absl::optional<uint32_t> channel_action_counter;
+ // Number of actions taken by the ANA DTX controller since the start of the
+ // call. If this value is not set, it indicates that the DTX controller is
+ // disabled.
+ absl::optional<uint32_t> dtx_action_counter;
+ // Number of actions taken by the ANA FEC controller since the start of the
+ // call. If this value is not set, it indicates that the FEC controller is
+ // disabled.
+ absl::optional<uint32_t> fec_action_counter;
+ // Number of times the ANA frame length controller decided to increase the
+ // frame length since the start of the call. If this value is not set, it
+ // indicates that the frame length controller is disabled.
+ absl::optional<uint32_t> frame_length_increase_counter;
+ // Number of times the ANA frame length controller decided to decrease the
+ // frame length since the start of the call. If this value is not set, it
+ // indicates that the frame length controller is disabled.
+ absl::optional<uint32_t> frame_length_decrease_counter;
+ // The uplink packet loss fractions as set by the ANA FEC controller. If this
+ // value is not set, it indicates that the ANA FEC controller is not active.
+ absl::optional<float> uplink_packet_loss_fraction;
+};
+
+// This is the interface class for encoders in AudioCoding module. Each codec
+// type must have an implementation of this class.
+class AudioEncoder {
+ public:
+ // Used for UMA logging of codec usage. The same codecs, with the
+ // same values, must be listed in
+ // src/tools/metrics/histograms/histograms.xml in chromium to log
+ // correct values.
+ enum class CodecType {
+ kOther = 0, // Codec not specified, and/or not listed in this enum
+ kOpus = 1,
+ kIsac = 2,
+ kPcmA = 3,
+ kPcmU = 4,
+ kG722 = 5,
+ kIlbc = 6,
+
+ // Number of histogram bins in the UMA logging of codec types. The
+ // total number of different codecs that are logged cannot exceed this
+ // number.
+ kMaxLoggedAudioCodecTypes
+ };
+
+ struct EncodedInfoLeaf {
+ size_t encoded_bytes = 0;
+ uint32_t encoded_timestamp = 0;
+ int payload_type = 0;
+ bool send_even_if_empty = false;
+ bool speech = true;
+ CodecType encoder_type = CodecType::kOther;
+ };
+
+ // This is the main struct for auxiliary encoding information. Each encoded
+ // packet should be accompanied by one EncodedInfo struct, containing the
+ // total number of |encoded_bytes|, the |encoded_timestamp| and the
+ // |payload_type|. If the packet contains redundant encodings, the |redundant|
+ // vector will be populated with EncodedInfoLeaf structs. Each struct in the
+ // vector represents one encoding; the order of structs in the vector is the
+ // same as the order in which the actual payloads are written to the byte
+ // stream. When EncoderInfoLeaf structs are present in the vector, the main
+ // struct's |encoded_bytes| will be the sum of all the |encoded_bytes| in the
+ // vector.
+ struct EncodedInfo : public EncodedInfoLeaf {
+ EncodedInfo();
+ EncodedInfo(const EncodedInfo&);
+ EncodedInfo(EncodedInfo&&);
+ ~EncodedInfo();
+ EncodedInfo& operator=(const EncodedInfo&);
+ EncodedInfo& operator=(EncodedInfo&&);
+
+ std::vector<EncodedInfoLeaf> redundant;
+ };
+
+ virtual ~AudioEncoder() = default;
+
+ // Returns the input sample rate in Hz and the number of input channels.
+ // These are constants set at instantiation time.
+ virtual int SampleRateHz() const = 0;
+ virtual size_t NumChannels() const = 0;
+
+ // Returns the rate at which the RTP timestamps are updated. The default
+ // implementation returns SampleRateHz().
+ virtual int RtpTimestampRateHz() const;
+
+ // Returns the number of 10 ms frames the encoder will put in the next
+ // packet. This value may only change when Encode() outputs a packet; i.e.,
+ // the encoder may vary the number of 10 ms frames from packet to packet, but
+ // it must decide the length of the next packet no later than when outputting
+ // the preceding packet.
+ virtual size_t Num10MsFramesInNextPacket() const = 0;
+
+ // Returns the maximum value that can be returned by
+ // Num10MsFramesInNextPacket().
+ virtual size_t Max10MsFramesInAPacket() const = 0;
+
+ // Returns the current target bitrate in bits/s. The value -1 means that the
+ // codec adapts the target automatically, and a current target cannot be
+ // provided.
+ virtual int GetTargetBitrate() const = 0;
+
+ // Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 *
+ // NumChannels() samples). Multi-channel audio must be sample-interleaved.
+ // The encoder appends zero or more bytes of output to |encoded| and returns
+ // additional encoding information. Encode() checks some preconditions, calls
+ // EncodeImpl() which does the actual work, and then checks some
+ // postconditions.
+ EncodedInfo Encode(uint32_t rtp_timestamp,
+ rtc::ArrayView<const int16_t> audio,
+ rtc::Buffer* encoded);
+
+ // Resets the encoder to its starting state, discarding any input that has
+ // been fed to the encoder but not yet emitted in a packet.
+ virtual void Reset() = 0;
+
+ // Enables or disables codec-internal FEC (forward error correction). Returns
+ // true if the codec was able to comply. The default implementation returns
+ // true when asked to disable FEC and false when asked to enable it (meaning
+ // that FEC isn't supported).
+ virtual bool SetFec(bool enable);
+
+ // Enables or disables codec-internal VAD/DTX. Returns true if the codec was
+ // able to comply. The default implementation returns true when asked to
+ // disable DTX and false when asked to enable it (meaning that DTX isn't
+ // supported).
+ virtual bool SetDtx(bool enable);
+
+ // Returns the status of codec-internal DTX. The default implementation always
+ // returns false.
+ virtual bool GetDtx() const;
+
+ // Sets the application mode. Returns true if the codec was able to comply.
+ // The default implementation just returns false.
+ enum class Application { kSpeech, kAudio };
+ virtual bool SetApplication(Application application);
+
+ // Tells the encoder about the highest sample rate the decoder is expected to
+ // use when decoding the bitstream. The encoder would typically use this
+ // information to adjust the quality of the encoding. The default
+ // implementation does nothing.
+ virtual void SetMaxPlaybackRate(int frequency_hz);
+
+ // This is to be deprecated. Please use |OnReceivedTargetAudioBitrate|
+ // instead.
+ // Tells the encoder what average bitrate we'd like it to produce. The
+ // encoder is free to adjust or disregard the given bitrate (the default
+ // implementation does the latter).
+ RTC_DEPRECATED virtual void SetTargetBitrate(int target_bps);
+
+ // Causes this encoder to let go of any other encoders it contains, and
+ // returns a pointer to an array where they are stored (which is required to
+ // live as long as this encoder). Unless the returned array is empty, you may
+ // not call any methods on this encoder afterwards, except for the
+ // destructor. The default implementation just returns an empty array.
+ // NOTE: This method is subject to change. Do not call or override it.
+ virtual rtc::ArrayView<std::unique_ptr<AudioEncoder>>
+ ReclaimContainedEncoders();
+
+ // Enables audio network adaptor. Returns true if successful.
+ virtual bool EnableAudioNetworkAdaptor(const std::string& config_string,
+ RtcEventLog* event_log);
+
+ // Disables audio network adaptor.
+ virtual void DisableAudioNetworkAdaptor();
+
+ // Provides uplink packet loss fraction to this encoder to allow it to adapt.
+ // |uplink_packet_loss_fraction| is in the range [0.0, 1.0].
+ virtual void OnReceivedUplinkPacketLossFraction(
+ float uplink_packet_loss_fraction);
+
+ RTC_DEPRECATED virtual void OnReceivedUplinkRecoverablePacketLossFraction(
+ float uplink_recoverable_packet_loss_fraction);
+
+ // Provides target audio bitrate to this encoder to allow it to adapt.
+ virtual void OnReceivedTargetAudioBitrate(int target_bps);
+
+ // Provides target audio bitrate and corresponding probing interval of
+ // the bandwidth estimator to this encoder to allow it to adapt.
+ virtual void OnReceivedUplinkBandwidth(int target_audio_bitrate_bps,
+ absl::optional<int64_t> bwe_period_ms);
+
+ // Provides target audio bitrate and corresponding probing interval of
+ // the bandwidth estimator to this encoder to allow it to adapt.
+ virtual void OnReceivedUplinkAllocation(BitrateAllocationUpdate update);
+
+ // Provides RTT to this encoder to allow it to adapt.
+ virtual void OnReceivedRtt(int rtt_ms);
+
+ // Provides overhead to this encoder to adapt. The overhead is the number of
+ // bytes that will be added to each packet the encoder generates.
+ virtual void OnReceivedOverhead(size_t overhead_bytes_per_packet);
+
+ // To allow encoder to adapt its frame length, it must be provided the frame
+ // length range that receivers can accept.
+ virtual void SetReceiverFrameLengthRange(int min_frame_length_ms,
+ int max_frame_length_ms);
+
+ // Get statistics related to audio network adaptation.
+ virtual ANAStats GetANAStats() const;
+
+ // The range of frame lengths that are supported or nullopt if there's no sch
+ // information. This is used to calculated the full bitrate range, including
+ // overhead.
+ virtual absl::optional<std::pair<TimeDelta, TimeDelta>> GetFrameLengthRange()
+ const = 0;
+
+ protected:
+ // Subclasses implement this to perform the actual encoding. Called by
+ // Encode().
+ virtual EncodedInfo EncodeImpl(uint32_t rtp_timestamp,
+ rtc::ArrayView<const int16_t> audio,
+ rtc::Buffer* encoded) = 0;
+};
+} // namespace webrtc
+#endif // API_AUDIO_CODECS_AUDIO_ENCODER_H_
diff --git a/webrtc/api/call/bitrate_allocation.h b/webrtc/api/call/bitrate_allocation.h
new file mode 100644
index 0000000..13c7f74
--- /dev/null
+++ b/webrtc/api/call/bitrate_allocation.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef API_CALL_BITRATE_ALLOCATION_H_
+#define API_CALL_BITRATE_ALLOCATION_H_
+
+#include "api/units/data_rate.h"
+#include "api/units/time_delta.h"
+
+namespace webrtc {
+
+// BitrateAllocationUpdate provides information to allocated streams about their
+// bitrate allocation. It originates from the BitrateAllocater class and is
+// propagated from there.
+struct BitrateAllocationUpdate {
+ // The allocated target bitrate. Media streams should produce this amount of
+ // data. (Note that this may include packet overhead depending on
+ // configuration.)
+ DataRate target_bitrate = DataRate::Zero();
+ // The allocated part of the estimated link capacity. This is more stable than
+ // the target as it is based on the underlying link capacity estimate. This
+ // should be used to change encoder configuration when the cost of change is
+ // high.
+ DataRate stable_target_bitrate = DataRate::Zero();
+ // Predicted packet loss ratio.
+ double packet_loss_ratio = 0;
+ // Predicted round trip time.
+ TimeDelta round_trip_time = TimeDelta::PlusInfinity();
+ // |bwe_period| is deprecated, use |stable_target_bitrate| allocation instead.
+ TimeDelta bwe_period = TimeDelta::PlusInfinity();
+ // Congestion window pushback bitrate reduction fraction. Used in
+ // VideoStreamEncoder to reduce the bitrate by the given fraction
+ // by dropping frames.
+ double cwnd_reduce_ratio = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_CALL_BITRATE_ALLOCATION_H_
diff --git a/webrtc/api/function_view.h b/webrtc/api/function_view.h
new file mode 100644
index 0000000..5ae1bd6
--- /dev/null
+++ b/webrtc/api/function_view.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 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 API_FUNCTION_VIEW_H_
+#define API_FUNCTION_VIEW_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "rtc_base/checks.h"
+
+// Just like std::function, FunctionView will wrap any callable and hide its
+// actual type, exposing only its signature. But unlike std::function,
+// FunctionView doesn't own its callable---it just points to it. Thus, it's a
+// good choice mainly as a function argument when the callable argument will
+// not be called again once the function has returned.
+//
+// Its constructors are implicit, so that callers won't have to convert lambdas
+// and other callables to FunctionView<Blah(Blah, Blah)> explicitly. This is
+// safe because FunctionView is only a reference to the real callable.
+//
+// Example use:
+//
+// void SomeFunction(rtc::FunctionView<int(int)> index_transform);
+// ...
+// SomeFunction([](int i) { return 2 * i + 1; });
+//
+// Note: FunctionView is tiny (essentially just two pointers) and trivially
+// copyable, so it's probably cheaper to pass it by value than by const
+// reference.
+
+namespace rtc {
+
+template <typename T>
+class FunctionView; // Undefined.
+
+template <typename RetT, typename... ArgT>
+class FunctionView<RetT(ArgT...)> final {
+ public:
+ // Constructor for lambdas and other callables; it accepts every type of
+ // argument except those noted in its enable_if call.
+ template <
+ typename F,
+ typename std::enable_if<
+ // Not for function pointers; we have another constructor for that
+ // below.
+ !std::is_function<typename std::remove_pointer<
+ typename std::remove_reference<F>::type>::type>::value &&
+
+ // Not for nullptr; we have another constructor for that below.
+ !std::is_same<std::nullptr_t,
+ typename std::remove_cv<F>::type>::value &&
+
+ // Not for FunctionView objects; we have another constructor for that
+ // (the implicitly declared copy constructor).
+ !std::is_same<FunctionView,
+ typename std::remove_cv<typename std::remove_reference<
+ F>::type>::type>::value>::type* = nullptr>
+ FunctionView(F&& f)
+ : call_(CallVoidPtr<typename std::remove_reference<F>::type>) {
+ f_.void_ptr = &f;
+ }
+
+ // Constructor that accepts function pointers. If the argument is null, the
+ // result is an empty FunctionView.
+ template <
+ typename F,
+ typename std::enable_if<std::is_function<typename std::remove_pointer<
+ typename std::remove_reference<F>::type>::type>::value>::type* =
+ nullptr>
+ FunctionView(F&& f)
+ : call_(f ? CallFunPtr<typename std::remove_pointer<F>::type> : nullptr) {
+ f_.fun_ptr = reinterpret_cast<void (*)()>(f);
+ }
+
+ // Constructor that accepts nullptr. It creates an empty FunctionView.
+ template <typename F,
+ typename std::enable_if<std::is_same<
+ std::nullptr_t,
+ typename std::remove_cv<F>::type>::value>::type* = nullptr>
+ FunctionView(F&& f) : call_(nullptr) {}
+
+ // Default constructor. Creates an empty FunctionView.
+ FunctionView() : call_(nullptr) {}
+
+ RetT operator()(ArgT... args) const {
+ RTC_DCHECK(call_);
+ return call_(f_, std::forward<ArgT>(args)...);
+ }
+
+ // Returns true if we have a function, false if we don't (i.e., we're null).
+ explicit operator bool() const { return !!call_; }
+
+ private:
+ union VoidUnion {
+ void* void_ptr;
+ void (*fun_ptr)();
+ };
+
+ template <typename F>
+ static RetT CallVoidPtr(VoidUnion vu, ArgT... args) {
+ return (*static_cast<F*>(vu.void_ptr))(std::forward<ArgT>(args)...);
+ }
+ template <typename F>
+ static RetT CallFunPtr(VoidUnion vu, ArgT... args) {
+ return (reinterpret_cast<typename std::add_pointer<F>::type>(vu.fun_ptr))(
+ std::forward<ArgT>(args)...);
+ }
+
+ // A pointer to the callable thing, with type information erased. It's a
+ // union because we have to use separate types depending on if the callable
+ // thing is a function pointer or something else.
+ VoidUnion f_;
+
+ // Pointer to a dispatch function that knows the type of the callable thing
+ // that's stored in f_, and how to call it. A FunctionView object is empty
+ // (null) iff call_ is null.
+ RetT (*call_)(VoidUnion, ArgT...);
+};
+
+} // namespace rtc
+
+#endif // API_FUNCTION_VIEW_H_
diff --git a/webrtc/api/meson.build b/webrtc/api/meson.build
new file mode 100644
index 0000000..1d26709
--- /dev/null
+++ b/webrtc/api/meson.build
@@ -0,0 +1,46 @@
+api_sources = [
+ 'audio/audio_frame.cc',
+ 'audio/channel_layout.cc',
+ 'audio/echo_canceller3_config.cc',
+ 'audio_codecs/audio_decoder.cc',
+ 'audio_codecs/audio_encoder.cc',
+ 'rtp_headers.cc',
+ 'rtp_packet_info.cc',
+ 'task_queue/task_queue_base.cc',
+ 'units/data_rate.cc',
+ 'units/data_size.cc',
+ 'units/frequency.cc',
+ 'units/time_delta.cc',
+ 'units/timestamp.cc',
+ 'video/color_space.cc',
+ 'video/hdr_metadata.cc',
+ 'video/video_content_type.cc',
+ 'video/video_timing.cc',
+]
+
+api_headers = [
+ ['', 'array_view.h'],
+ ['', 'scoped_refptr.h'],
+ ['audio', 'echo_canceller3_config.h'],
+ ['audio', 'echo_control.h'],
+]
+
+foreach h : api_headers
+ install_headers(
+ join_paths(h[0], h[1]),
+ subdir: join_paths('webrtc_audio_processing', 'api', h[0])
+ )
+endforeach
+
+
+libapi = static_library('libapi',
+ api_sources,
+ dependencies: common_deps,
+ include_directories: webrtc_inc,
+ cpp_args : common_cxxflags
+)
+
+api_dep = declare_dependency(
+ link_with: libapi
+)
+
diff --git a/webrtc/api/ref_counted_base.h b/webrtc/api/ref_counted_base.h
new file mode 100644
index 0000000..a1761db
--- /dev/null
+++ b/webrtc/api/ref_counted_base.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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 API_REF_COUNTED_BASE_H_
+#define API_REF_COUNTED_BASE_H_
+
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counter.h"
+
+namespace rtc {
+
+class RefCountedBase {
+ public:
+ RefCountedBase() = default;
+
+ void AddRef() const { ref_count_.IncRef(); }
+ RefCountReleaseStatus Release() const {
+ const auto status = ref_count_.DecRef();
+ if (status == RefCountReleaseStatus::kDroppedLastRef) {
+ delete this;
+ }
+ return status;
+ }
+
+ protected:
+ virtual ~RefCountedBase() = default;
+
+ private:
+ mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
+};
+
+} // namespace rtc
+
+#endif // API_REF_COUNTED_BASE_H_
diff --git a/webrtc/common_types.cc b/webrtc/api/rtp_headers.cc
index 7b99f3c..e0ad9eb 100644
--- a/webrtc/common_types.cc
+++ b/webrtc/api/rtp_headers.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ * 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
@@ -8,18 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_types.h"
-
-#include <string.h>
+#include "api/rtp_headers.h"
namespace webrtc {
-int InStream::Rewind() { return -1; }
-
-int OutStream::Rewind() { return -1; }
-
-StreamDataCounters::StreamDataCounters() : first_packet_time_ms(-1) {}
-
RTPHeaderExtension::RTPHeaderExtension()
: hasTransmissionTimeOffset(false),
transmissionTimeOffset(0),
@@ -31,8 +23,16 @@ RTPHeaderExtension::RTPHeaderExtension()
voiceActivity(false),
audioLevel(0),
hasVideoRotation(false),
- videoRotation(0) {
-}
+ videoRotation(kVideoRotation_0),
+ hasVideoContentType(false),
+ videoContentType(VideoContentType::UNSPECIFIED),
+ has_video_timing(false) {}
+
+RTPHeaderExtension::RTPHeaderExtension(const RTPHeaderExtension& other) =
+ default;
+
+RTPHeaderExtension& RTPHeaderExtension::operator=(
+ const RTPHeaderExtension& other) = default;
RTPHeader::RTPHeader()
: markerBit(false),
@@ -41,11 +41,14 @@ RTPHeader::RTPHeader()
timestamp(0),
ssrc(0),
numCSRCs(0),
+ arrOfCSRCs(),
paddingLength(0),
headerLength(0),
payload_type_frequency(0),
- extension() {
- memset(&arrOfCSRCs, 0, sizeof(arrOfCSRCs));
-}
+ extension() {}
+
+RTPHeader::RTPHeader(const RTPHeader& other) = default;
+
+RTPHeader& RTPHeader::operator=(const RTPHeader& other) = default;
} // namespace webrtc
diff --git a/webrtc/api/rtp_headers.h b/webrtc/api/rtp_headers.h
new file mode 100644
index 0000000..b9a97c8
--- /dev/null
+++ b/webrtc/api/rtp_headers.h
@@ -0,0 +1,190 @@
+/*
+ * 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 API_RTP_HEADERS_H_
+#define API_RTP_HEADERS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/units/timestamp.h"
+#include "api/video/color_space.h"
+#include "api/video/video_content_type.h"
+#include "api/video/video_rotation.h"
+#include "api/video/video_timing.h"
+
+namespace webrtc {
+
+struct FeedbackRequest {
+ // Determines whether the recv delta as specified in
+ // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
+ // should be included.
+ bool include_timestamps;
+ // Include feedback of received packets in the range [sequence_number -
+ // sequence_count + 1, sequence_number]. That is, no feedback will be sent if
+ // sequence_count is zero.
+ int sequence_count;
+};
+
+// The Absolute Capture Time extension is used to stamp RTP packets with a NTP
+// timestamp showing when the first audio or video frame in a packet was
+// originally captured. The intent of this extension is to provide a way to
+// accomplish audio-to-video synchronization when RTCP-terminating intermediate
+// systems (e.g. mixers) are involved. See:
+// http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time
+struct AbsoluteCaptureTime {
+ // Absolute capture timestamp is the NTP timestamp of when the first frame in
+ // a packet was originally captured. This timestamp MUST be based on the same
+ // clock as the clock used to generate NTP timestamps for RTCP sender reports
+ // on the capture system.
+ //
+ // It’s not always possible to do an NTP clock readout at the exact moment of
+ // when a media frame is captured. A capture system MAY postpone the readout
+ // until a more convenient time. A capture system SHOULD have known delays
+ // (e.g. from hardware buffers) subtracted from the readout to make the final
+ // timestamp as close to the actual capture time as possible.
+ //
+ // This field is encoded as a 64-bit unsigned fixed-point number with the high
+ // 32 bits for the timestamp in seconds and low 32 bits for the fractional
+ // part. This is also known as the UQ32.32 format and is what the RTP
+ // specification defines as the canonical format to represent NTP timestamps.
+ uint64_t absolute_capture_timestamp;
+
+ // Estimated capture clock offset is the sender’s estimate of the offset
+ // between its own NTP clock and the capture system’s NTP clock. The sender is
+ // here defined as the system that owns the NTP clock used to generate the NTP
+ // timestamps for the RTCP sender reports on this stream. The sender system is
+ // typically either the capture system or a mixer.
+ //
+ // This field is encoded as a 64-bit two’s complement signed fixed-point
+ // number with the high 32 bits for the seconds and low 32 bits for the
+ // fractional part. It’s intended to make it easy for a receiver, that knows
+ // how to estimate the sender system’s NTP clock, to also estimate the capture
+ // system’s NTP clock:
+ //
+ // Capture NTP Clock = Sender NTP Clock + Capture Clock Offset
+ absl::optional<int64_t> estimated_capture_clock_offset;
+};
+
+inline bool operator==(const AbsoluteCaptureTime& lhs,
+ const AbsoluteCaptureTime& rhs) {
+ return (lhs.absolute_capture_timestamp == rhs.absolute_capture_timestamp) &&
+ (lhs.estimated_capture_clock_offset ==
+ rhs.estimated_capture_clock_offset);
+}
+
+inline bool operator!=(const AbsoluteCaptureTime& lhs,
+ const AbsoluteCaptureTime& rhs) {
+ return !(lhs == rhs);
+}
+
+struct RTPHeaderExtension {
+ RTPHeaderExtension();
+ RTPHeaderExtension(const RTPHeaderExtension& other);
+ RTPHeaderExtension& operator=(const RTPHeaderExtension& other);
+
+ static constexpr int kAbsSendTimeFraction = 18;
+
+ Timestamp GetAbsoluteSendTimestamp() const {
+ RTC_DCHECK(hasAbsoluteSendTime);
+ RTC_DCHECK(absoluteSendTime < (1ul << 24));
+ return Timestamp::Micros((absoluteSendTime * 1000000ll) /
+ (1 << kAbsSendTimeFraction));
+ }
+
+ TimeDelta GetAbsoluteSendTimeDelta(uint32_t previous_sendtime) const {
+ RTC_DCHECK(hasAbsoluteSendTime);
+ RTC_DCHECK(absoluteSendTime < (1ul << 24));
+ RTC_DCHECK(previous_sendtime < (1ul << 24));
+ int32_t delta =
+ static_cast<int32_t>((absoluteSendTime - previous_sendtime) << 8) >> 8;
+ return TimeDelta::Micros((delta * 1000000ll) / (1 << kAbsSendTimeFraction));
+ }
+
+ bool hasTransmissionTimeOffset;
+ int32_t transmissionTimeOffset;
+ bool hasAbsoluteSendTime;
+ uint32_t absoluteSendTime;
+ absl::optional<AbsoluteCaptureTime> absolute_capture_time;
+ bool hasTransportSequenceNumber;
+ uint16_t transportSequenceNumber;
+ absl::optional<FeedbackRequest> feedback_request;
+
+ // Audio Level includes both level in dBov and voiced/unvoiced bit. See:
+ // https://tools.ietf.org/html/rfc6464#section-3
+ bool hasAudioLevel;
+ bool voiceActivity;
+ uint8_t audioLevel;
+
+ // For Coordination of Video Orientation. See
+ // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/
+ // ts_126114v120700p.pdf
+ bool hasVideoRotation;
+ VideoRotation videoRotation;
+
+ // TODO(ilnik): Refactor this and one above to be absl::optional() and remove
+ // a corresponding bool flag.
+ bool hasVideoContentType;
+ VideoContentType videoContentType;
+
+ bool has_video_timing;
+ VideoSendTiming video_timing;
+
+ VideoPlayoutDelay playout_delay;
+
+ // For identification of a stream when ssrc is not signaled. See
+ // https://tools.ietf.org/html/draft-ietf-avtext-rid-09
+ // TODO(danilchap): Update url from draft to release version.
+ std::string stream_id;
+ std::string repaired_stream_id;
+
+ // For identifying the media section used to interpret this RTP packet. See
+ // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-38
+ std::string mid;
+
+ absl::optional<ColorSpace> color_space;
+};
+
+enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13
+
+struct RTPHeader {
+ RTPHeader();
+ RTPHeader(const RTPHeader& other);
+ RTPHeader& operator=(const RTPHeader& other);
+
+ bool markerBit;
+ uint8_t payloadType;
+ uint16_t sequenceNumber;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint8_t numCSRCs;
+ uint32_t arrOfCSRCs[kRtpCsrcSize];
+ size_t paddingLength;
+ size_t headerLength;
+ int payload_type_frequency;
+ RTPHeaderExtension extension;
+};
+
+// RTCP mode to use. Compound mode is described by RFC 4585 and reduced-size
+// RTCP mode is described by RFC 5506.
+enum class RtcpMode { kOff, kCompound, kReducedSize };
+
+enum NetworkState {
+ kNetworkUp,
+ kNetworkDown,
+};
+
+} // namespace webrtc
+
+#endif // API_RTP_HEADERS_H_
diff --git a/webrtc/api/rtp_packet_info.cc b/webrtc/api/rtp_packet_info.cc
new file mode 100644
index 0000000..a9ebd9d
--- /dev/null
+++ b/webrtc/api/rtp_packet_info.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/rtp_packet_info.h"
+
+#include <algorithm>
+#include <utility>
+
+namespace webrtc {
+
+RtpPacketInfo::RtpPacketInfo()
+ : ssrc_(0), rtp_timestamp_(0), receive_time_ms_(-1) {}
+
+RtpPacketInfo::RtpPacketInfo(
+ uint32_t ssrc,
+ std::vector<uint32_t> csrcs,
+ uint32_t rtp_timestamp,
+ absl::optional<uint8_t> audio_level,
+ absl::optional<AbsoluteCaptureTime> absolute_capture_time,
+ int64_t receive_time_ms)
+ : ssrc_(ssrc),
+ csrcs_(std::move(csrcs)),
+ rtp_timestamp_(rtp_timestamp),
+ audio_level_(audio_level),
+ absolute_capture_time_(absolute_capture_time),
+ receive_time_ms_(receive_time_ms) {}
+
+RtpPacketInfo::RtpPacketInfo(const RTPHeader& rtp_header,
+ int64_t receive_time_ms)
+ : ssrc_(rtp_header.ssrc),
+ rtp_timestamp_(rtp_header.timestamp),
+ receive_time_ms_(receive_time_ms) {
+ const auto& extension = rtp_header.extension;
+ const auto csrcs_count = std::min<size_t>(rtp_header.numCSRCs, kRtpCsrcSize);
+
+ csrcs_.assign(&rtp_header.arrOfCSRCs[0], &rtp_header.arrOfCSRCs[csrcs_count]);
+
+ if (extension.hasAudioLevel) {
+ audio_level_ = extension.audioLevel;
+ }
+
+ absolute_capture_time_ = extension.absolute_capture_time;
+}
+
+bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) {
+ return (lhs.ssrc() == rhs.ssrc()) && (lhs.csrcs() == rhs.csrcs()) &&
+ (lhs.rtp_timestamp() == rhs.rtp_timestamp()) &&
+ (lhs.audio_level() == rhs.audio_level()) &&
+ (lhs.absolute_capture_time() == rhs.absolute_capture_time()) &&
+ (lhs.receive_time_ms() == rhs.receive_time_ms());
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/rtp_packet_info.h b/webrtc/api/rtp_packet_info.h
new file mode 100644
index 0000000..639ba32
--- /dev/null
+++ b/webrtc/api/rtp_packet_info.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_RTP_PACKET_INFO_H_
+#define API_RTP_PACKET_INFO_H_
+
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/rtp_headers.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+
+//
+// Structure to hold information about a received |RtpPacket|. It is primarily
+// used to carry per-packet information from when a packet is received until
+// the information is passed to |SourceTracker|.
+//
+class RTC_EXPORT RtpPacketInfo {
+ public:
+ RtpPacketInfo();
+
+ RtpPacketInfo(uint32_t ssrc,
+ std::vector<uint32_t> csrcs,
+ uint32_t rtp_timestamp,
+ absl::optional<uint8_t> audio_level,
+ absl::optional<AbsoluteCaptureTime> absolute_capture_time,
+ int64_t receive_time_ms);
+
+ RtpPacketInfo(const RTPHeader& rtp_header, int64_t receive_time_ms);
+
+ RtpPacketInfo(const RtpPacketInfo& other) = default;
+ RtpPacketInfo(RtpPacketInfo&& other) = default;
+ RtpPacketInfo& operator=(const RtpPacketInfo& other) = default;
+ RtpPacketInfo& operator=(RtpPacketInfo&& other) = default;
+
+ uint32_t ssrc() const { return ssrc_; }
+ void set_ssrc(uint32_t value) { ssrc_ = value; }
+
+ const std::vector<uint32_t>& csrcs() const { return csrcs_; }
+ void set_csrcs(std::vector<uint32_t> value) { csrcs_ = std::move(value); }
+
+ uint32_t rtp_timestamp() const { return rtp_timestamp_; }
+ void set_rtp_timestamp(uint32_t value) { rtp_timestamp_ = value; }
+
+ absl::optional<uint8_t> audio_level() const { return audio_level_; }
+ void set_audio_level(absl::optional<uint8_t> value) { audio_level_ = value; }
+
+ const absl::optional<AbsoluteCaptureTime>& absolute_capture_time() const {
+ return absolute_capture_time_;
+ }
+ void set_absolute_capture_time(
+ const absl::optional<AbsoluteCaptureTime>& value) {
+ absolute_capture_time_ = value;
+ }
+
+ int64_t receive_time_ms() const { return receive_time_ms_; }
+ void set_receive_time_ms(int64_t value) { receive_time_ms_ = value; }
+
+ private:
+ // Fields from the RTP header:
+ // https://tools.ietf.org/html/rfc3550#section-5.1
+ uint32_t ssrc_;
+ std::vector<uint32_t> csrcs_;
+ uint32_t rtp_timestamp_;
+
+ // Fields from the Audio Level header extension:
+ // https://tools.ietf.org/html/rfc6464#section-3
+ absl::optional<uint8_t> audio_level_;
+
+ // Fields from the Absolute Capture Time header extension:
+ // http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time
+ absl::optional<AbsoluteCaptureTime> absolute_capture_time_;
+
+ // Local |webrtc::Clock|-based timestamp of when the packet was received.
+ int64_t receive_time_ms_;
+};
+
+bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs);
+
+inline bool operator!=(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace webrtc
+
+#endif // API_RTP_PACKET_INFO_H_
diff --git a/webrtc/api/rtp_packet_infos.h b/webrtc/api/rtp_packet_infos.h
new file mode 100644
index 0000000..d636464
--- /dev/null
+++ b/webrtc/api/rtp_packet_infos.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_RTP_PACKET_INFOS_H_
+#define API_RTP_PACKET_INFOS_H_
+
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+#include "api/ref_counted_base.h"
+#include "api/rtp_packet_info.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+
+// Semi-immutable structure to hold information about packets used to assemble
+// an audio or video frame. Uses internal reference counting to make it very
+// cheap to copy.
+//
+// We should ideally just use |std::vector<RtpPacketInfo>| and have it
+// |std::move()|-ed as the per-packet information is transferred from one object
+// to another. But moving the info, instead of copying it, is not easily done
+// for the current video code.
+class RTC_EXPORT RtpPacketInfos {
+ public:
+ using vector_type = std::vector<RtpPacketInfo>;
+
+ using value_type = vector_type::value_type;
+ using size_type = vector_type::size_type;
+ using difference_type = vector_type::difference_type;
+ using const_reference = vector_type::const_reference;
+ using const_pointer = vector_type::const_pointer;
+ using const_iterator = vector_type::const_iterator;
+ using const_reverse_iterator = vector_type::const_reverse_iterator;
+
+ using reference = const_reference;
+ using pointer = const_pointer;
+ using iterator = const_iterator;
+ using reverse_iterator = const_reverse_iterator;
+
+ RtpPacketInfos() {}
+ explicit RtpPacketInfos(const vector_type& entries)
+ : data_(Data::Create(entries)) {}
+
+ explicit RtpPacketInfos(vector_type&& entries)
+ : data_(Data::Create(std::move(entries))) {}
+
+ RtpPacketInfos(const RtpPacketInfos& other) = default;
+ RtpPacketInfos(RtpPacketInfos&& other) = default;
+ RtpPacketInfos& operator=(const RtpPacketInfos& other) = default;
+ RtpPacketInfos& operator=(RtpPacketInfos&& other) = default;
+
+ const_reference operator[](size_type pos) const { return entries()[pos]; }
+
+ const_reference at(size_type pos) const { return entries().at(pos); }
+ const_reference front() const { return entries().front(); }
+ const_reference back() const { return entries().back(); }
+
+ const_iterator begin() const { return entries().begin(); }
+ const_iterator end() const { return entries().end(); }
+ const_reverse_iterator rbegin() const { return entries().rbegin(); }
+ const_reverse_iterator rend() const { return entries().rend(); }
+
+ const_iterator cbegin() const { return entries().cbegin(); }
+ const_iterator cend() const { return entries().cend(); }
+ const_reverse_iterator crbegin() const { return entries().crbegin(); }
+ const_reverse_iterator crend() const { return entries().crend(); }
+
+ bool empty() const { return entries().empty(); }
+ size_type size() const { return entries().size(); }
+
+ private:
+ class Data : public rtc::RefCountedBase {
+ public:
+ static rtc::scoped_refptr<Data> Create(const vector_type& entries) {
+ // Performance optimization for the empty case.
+ if (entries.empty()) {
+ return nullptr;
+ }
+
+ return new Data(entries);
+ }
+
+ static rtc::scoped_refptr<Data> Create(vector_type&& entries) {
+ // Performance optimization for the empty case.
+ if (entries.empty()) {
+ return nullptr;
+ }
+
+ return new Data(std::move(entries));
+ }
+
+ const vector_type& entries() const { return entries_; }
+
+ private:
+ explicit Data(const vector_type& entries) : entries_(entries) {}
+ explicit Data(vector_type&& entries) : entries_(std::move(entries)) {}
+ ~Data() override {}
+
+ const vector_type entries_;
+ };
+
+ static const vector_type& empty_entries() {
+ static const vector_type& value = *new vector_type();
+ return value;
+ }
+
+ const vector_type& entries() const {
+ if (data_ != nullptr) {
+ return data_->entries();
+ } else {
+ return empty_entries();
+ }
+ }
+
+ rtc::scoped_refptr<Data> data_;
+};
+
+} // namespace webrtc
+
+#endif // API_RTP_PACKET_INFOS_H_
diff --git a/webrtc/api/scoped_refptr.h b/webrtc/api/scoped_refptr.h
new file mode 100644
index 0000000..fa4e83d
--- /dev/null
+++ b/webrtc/api/scoped_refptr.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 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.
+ */
+
+// Originally these classes are from Chromium.
+// http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h?view=markup
+
+//
+// A smart pointer class for reference counted objects. Use this class instead
+// of calling AddRef and Release manually on a reference counted object to
+// avoid common memory leaks caused by forgetting to Release an object
+// reference. Sample usage:
+//
+// class MyFoo : public RefCounted<MyFoo> {
+// ...
+// };
+//
+// void some_function() {
+// scoped_refptr<MyFoo> foo = new MyFoo();
+// foo->Method(param);
+// // |foo| is released when this function returns
+// }
+//
+// void some_other_function() {
+// scoped_refptr<MyFoo> foo = new MyFoo();
+// ...
+// foo = nullptr; // explicitly releases |foo|
+// ...
+// if (foo)
+// foo->Method(param);
+// }
+//
+// The above examples show how scoped_refptr<T> acts like a pointer to T.
+// Given two scoped_refptr<T> classes, it is also possible to exchange
+// references between the two objects, like so:
+//
+// {
+// scoped_refptr<MyFoo> a = new MyFoo();
+// scoped_refptr<MyFoo> b;
+//
+// b.swap(a);
+// // now, |b| references the MyFoo object, and |a| references null.
+// }
+//
+// To make both |a| and |b| in the above example reference the same MyFoo
+// object, simply use the assignment operator:
+//
+// {
+// scoped_refptr<MyFoo> a = new MyFoo();
+// scoped_refptr<MyFoo> b;
+//
+// b = a;
+// // now, |a| and |b| each own a reference to the same MyFoo object.
+// }
+//
+
+#ifndef API_SCOPED_REFPTR_H_
+#define API_SCOPED_REFPTR_H_
+
+#include <memory>
+#include <utility>
+
+namespace rtc {
+
+template <class T>
+class scoped_refptr {
+ public:
+ typedef T element_type;
+
+ scoped_refptr() : ptr_(nullptr) {}
+
+ scoped_refptr(T* p) : ptr_(p) { // NOLINT(runtime/explicit)
+ if (ptr_)
+ ptr_->AddRef();
+ }
+
+ scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
+ if (ptr_)
+ ptr_->AddRef();
+ }
+
+ template <typename U>
+ scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
+ if (ptr_)
+ ptr_->AddRef();
+ }
+
+ // Move constructors.
+ scoped_refptr(scoped_refptr<T>&& r) noexcept : ptr_(r.release()) {}
+
+ template <typename U>
+ scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.release()) {}
+
+ ~scoped_refptr() {
+ if (ptr_)
+ ptr_->Release();
+ }
+
+ T* get() const { return ptr_; }
+ operator T*() const { return ptr_; }
+ T* operator->() const { return ptr_; }
+
+ // Returns the (possibly null) raw pointer, and makes the scoped_refptr hold a
+ // null pointer, all without touching the reference count of the underlying
+ // pointed-to object. The object is still reference counted, and the caller of
+ // release() is now the proud owner of one reference, so it is responsible for
+ // calling Release() once on the object when no longer using it.
+ T* release() {
+ T* retVal = ptr_;
+ ptr_ = nullptr;
+ return retVal;
+ }
+
+ scoped_refptr<T>& operator=(T* p) {
+ // AddRef first so that self assignment should work
+ if (p)
+ p->AddRef();
+ if (ptr_)
+ ptr_->Release();
+ ptr_ = p;
+ return *this;
+ }
+
+ scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
+ return *this = r.ptr_;
+ }
+
+ template <typename U>
+ scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
+ return *this = r.get();
+ }
+
+ scoped_refptr<T>& operator=(scoped_refptr<T>&& r) noexcept {
+ scoped_refptr<T>(std::move(r)).swap(*this);
+ return *this;
+ }
+
+ template <typename U>
+ scoped_refptr<T>& operator=(scoped_refptr<U>&& r) noexcept {
+ scoped_refptr<T>(std::move(r)).swap(*this);
+ return *this;
+ }
+
+ void swap(T** pp) noexcept {
+ T* p = ptr_;
+ ptr_ = *pp;
+ *pp = p;
+ }
+
+ void swap(scoped_refptr<T>& r) noexcept { swap(&r.ptr_); }
+
+ protected:
+ T* ptr_;
+};
+
+} // namespace rtc
+
+#endif // API_SCOPED_REFPTR_H_
diff --git a/webrtc/api/task_queue/queued_task.h b/webrtc/api/task_queue/queued_task.h
new file mode 100644
index 0000000..5748628
--- /dev/null
+++ b/webrtc/api/task_queue/queued_task.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef API_TASK_QUEUE_QUEUED_TASK_H_
+#define API_TASK_QUEUE_QUEUED_TASK_H_
+
+namespace webrtc {
+
+// Base interface for asynchronously executed tasks.
+// The interface basically consists of a single function, Run(), that executes
+// on the target queue. For more details see the Run() method and TaskQueue.
+class QueuedTask {
+ public:
+ virtual ~QueuedTask() = default;
+
+ // Main routine that will run when the task is executed on the desired queue.
+ // The task should return |true| to indicate that it should be deleted or
+ // |false| to indicate that the queue should consider ownership of the task
+ // having been transferred. Returning |false| can be useful if a task has
+ // re-posted itself to a different queue or is otherwise being re-used.
+ virtual bool Run() = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_QUEUED_TASK_H_
diff --git a/webrtc/api/task_queue/task_queue_base.cc b/webrtc/api/task_queue/task_queue_base.cc
new file mode 100644
index 0000000..7d3539a
--- /dev/null
+++ b/webrtc/api/task_queue/task_queue_base.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/task_queue/task_queue_base.h"
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "rtc_base/checks.h"
+
+#if defined(ABSL_HAVE_THREAD_LOCAL)
+
+namespace webrtc {
+namespace {
+
+ABSL_CONST_INIT thread_local TaskQueueBase* current = nullptr;
+
+} // namespace
+
+TaskQueueBase* TaskQueueBase::Current() {
+ return current;
+}
+
+TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter(
+ TaskQueueBase* task_queue)
+ : previous_(current) {
+ current = task_queue;
+}
+
+TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() {
+ current = previous_;
+}
+} // namespace webrtc
+
+#elif defined(WEBRTC_POSIX)
+
+#include <pthread.h>
+
+namespace webrtc {
+namespace {
+
+ABSL_CONST_INIT pthread_key_t g_queue_ptr_tls = 0;
+
+void InitializeTls() {
+ RTC_CHECK(pthread_key_create(&g_queue_ptr_tls, nullptr) == 0);
+}
+
+pthread_key_t GetQueuePtrTls() {
+ static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+ RTC_CHECK(pthread_once(&init_once, &InitializeTls) == 0);
+ return g_queue_ptr_tls;
+}
+
+} // namespace
+
+TaskQueueBase* TaskQueueBase::Current() {
+ return static_cast<TaskQueueBase*>(pthread_getspecific(GetQueuePtrTls()));
+}
+
+TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter(
+ TaskQueueBase* task_queue)
+ : previous_(TaskQueueBase::Current()) {
+ pthread_setspecific(GetQueuePtrTls(), task_queue);
+}
+
+TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() {
+ pthread_setspecific(GetQueuePtrTls(), previous_);
+}
+
+} // namespace webrtc
+
+#else
+#error Unsupported platform
+#endif
diff --git a/webrtc/api/task_queue/task_queue_base.h b/webrtc/api/task_queue/task_queue_base.h
new file mode 100644
index 0000000..90b1efd
--- /dev/null
+++ b/webrtc/api/task_queue/task_queue_base.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_
+#define API_TASK_QUEUE_TASK_QUEUE_BASE_H_
+
+#include <memory>
+
+#include "api/task_queue/queued_task.h"
+#include "rtc_base/system/rtc_export.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+// Asynchronously executes tasks in a way that guarantees that they're executed
+// in FIFO order and that tasks never overlap. Tasks may always execute on the
+// same worker thread and they may not. To DCHECK that tasks are executing on a
+// known task queue, use IsCurrent().
+class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
+ public:
+ // Starts destruction of the task queue.
+ // On return ensures no task are running and no new tasks are able to start
+ // on the task queue.
+ // Responsible for deallocation. Deallocation may happen syncrhoniously during
+ // Delete or asynchronously after Delete returns.
+ // Code not running on the TaskQueue should not make any assumption when
+ // TaskQueue is deallocated and thus should not call any methods after Delete.
+ // Code running on the TaskQueue should not call Delete, but can assume
+ // TaskQueue still exists and may call other methods, e.g. PostTask.
+ virtual void Delete() = 0;
+
+ // Schedules a task to execute. Tasks are executed in FIFO order.
+ // If |task->Run()| returns true, task is deleted on the task queue
+ // before next QueuedTask starts executing.
+ // When a TaskQueue is deleted, pending tasks will not be executed but they
+ // will be deleted. The deletion of tasks may happen synchronously on the
+ // TaskQueue or it may happen asynchronously after TaskQueue is deleted.
+ // This may vary from one implementation to the next so assumptions about
+ // lifetimes of pending tasks should not be made.
+ virtual void PostTask(std::unique_ptr<QueuedTask> task) = 0;
+
+ // Schedules a task to execute a specified number of milliseconds from when
+ // the call is made. The precision should be considered as "best effort"
+ // and in some cases, such as on Windows when all high precision timers have
+ // been used up, can be off by as much as 15 millseconds.
+ virtual void PostDelayedTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) = 0;
+
+ // Returns the task queue that is running the current thread.
+ // Returns nullptr if this thread is not associated with any task queue.
+ static TaskQueueBase* Current();
+ bool IsCurrent() const { return Current() == this; }
+
+ protected:
+ class CurrentTaskQueueSetter {
+ public:
+ explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue);
+ CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete;
+ CurrentTaskQueueSetter& operator=(const CurrentTaskQueueSetter&) = delete;
+ ~CurrentTaskQueueSetter();
+
+ private:
+ TaskQueueBase* const previous_;
+ };
+
+ // Users of the TaskQueue should call Delete instead of directly deleting
+ // this object.
+ virtual ~TaskQueueBase() = default;
+};
+
+struct TaskQueueDeleter {
+ void operator()(TaskQueueBase* task_queue) const { task_queue->Delete(); }
+};
+
+} // namespace webrtc
+
+#endif // API_TASK_QUEUE_TASK_QUEUE_BASE_H_
diff --git a/webrtc/api/units/data_rate.cc b/webrtc/api/units/data_rate.cc
new file mode 100644
index 0000000..f9586c5
--- /dev/null
+++ b/webrtc/api/units/data_rate.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/units/data_rate.h"
+
+#include "api/array_view.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+std::string ToString(DataRate value) {
+ char buf[64];
+ rtc::SimpleStringBuilder sb(buf);
+ if (value.IsPlusInfinity()) {
+ sb << "+inf bps";
+ } else if (value.IsMinusInfinity()) {
+ sb << "-inf bps";
+ } else {
+ if (value.bps() == 0 || value.bps() % 1000 != 0) {
+ sb << value.bps() << " bps";
+ } else {
+ sb << value.kbps() << " kbps";
+ }
+ }
+ return sb.str();
+}
+} // namespace webrtc
diff --git a/webrtc/api/units/data_rate.h b/webrtc/api/units/data_rate.h
new file mode 100644
index 0000000..5c8a61f
--- /dev/null
+++ b/webrtc/api/units/data_rate.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_UNITS_DATA_RATE_H_
+#define API_UNITS_DATA_RATE_H_
+
+#ifdef UNIT_TEST
+#include <ostream> // no-presubmit-check TODO(webrtc:8982)
+#endif // UNIT_TEST
+
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "api/units/data_size.h"
+#include "api/units/frequency.h"
+#include "api/units/time_delta.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/units/unit_base.h"
+
+namespace webrtc {
+// DataRate is a class that represents a given data rate. This can be used to
+// represent bandwidth, encoding bitrate, etc. The internal storage is bits per
+// second (bps).
+class DataRate final : public rtc_units_impl::RelativeUnit<DataRate> {
+ public:
+ template <typename T>
+ static constexpr DataRate BitsPerSec(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromValue(value);
+ }
+ template <typename T>
+ static constexpr DataRate BytesPerSec(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction(8, value);
+ }
+ template <typename T>
+ static constexpr DataRate KilobitsPerSec(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction(1000, value);
+ }
+ static constexpr DataRate Infinity() { return PlusInfinity(); }
+
+ DataRate() = delete;
+
+ template <typename T = int64_t>
+ constexpr T bps() const {
+ return ToValue<T>();
+ }
+ template <typename T = int64_t>
+ constexpr T bytes_per_sec() const {
+ return ToFraction<8, T>();
+ }
+ template <typename T = int64_t>
+ constexpr T kbps() const {
+ return ToFraction<1000, T>();
+ }
+ constexpr int64_t bps_or(int64_t fallback_value) const {
+ return ToValueOr(fallback_value);
+ }
+ constexpr int64_t kbps_or(int64_t fallback_value) const {
+ return ToFractionOr<1000>(fallback_value);
+ }
+
+ private:
+ // Bits per second used internally to simplify debugging by making the value
+ // more recognizable.
+ friend class rtc_units_impl::UnitBase<DataRate>;
+ using RelativeUnit::RelativeUnit;
+ static constexpr bool one_sided = true;
+};
+
+namespace data_rate_impl {
+inline constexpr int64_t Microbits(const DataSize& size) {
+ constexpr int64_t kMaxBeforeConversion =
+ std::numeric_limits<int64_t>::max() / 8000000;
+ RTC_DCHECK_LE(size.bytes(), kMaxBeforeConversion)
+ << "size is too large to be expressed in microbits";
+ return size.bytes() * 8000000;
+}
+
+inline constexpr int64_t MillibytePerSec(const DataRate& size) {
+ constexpr int64_t kMaxBeforeConversion =
+ std::numeric_limits<int64_t>::max() / (1000 / 8);
+ RTC_DCHECK_LE(size.bps(), kMaxBeforeConversion)
+ << "rate is too large to be expressed in microbytes per second";
+ return size.bps() * (1000 / 8);
+}
+} // namespace data_rate_impl
+
+inline constexpr DataRate operator/(const DataSize size,
+ const TimeDelta duration) {
+ return DataRate::BitsPerSec(data_rate_impl::Microbits(size) / duration.us());
+}
+inline constexpr TimeDelta operator/(const DataSize size, const DataRate rate) {
+ return TimeDelta::Micros(data_rate_impl::Microbits(size) / rate.bps());
+}
+inline constexpr DataSize operator*(const DataRate rate,
+ const TimeDelta duration) {
+ int64_t microbits = rate.bps() * duration.us();
+ return DataSize::Bytes((microbits + 4000000) / 8000000);
+}
+inline constexpr DataSize operator*(const TimeDelta duration,
+ const DataRate rate) {
+ return rate * duration;
+}
+
+inline constexpr DataSize operator/(const DataRate rate,
+ const Frequency frequency) {
+ int64_t millihertz = frequency.millihertz<int64_t>();
+ // Note that the value is truncated here reather than rounded, potentially
+ // introducing an error of .5 bytes if rounding were expected.
+ return DataSize::Bytes(data_rate_impl::MillibytePerSec(rate) / millihertz);
+}
+inline constexpr Frequency operator/(const DataRate rate, const DataSize size) {
+ return Frequency::MilliHertz(data_rate_impl::MillibytePerSec(rate) /
+ size.bytes());
+}
+inline constexpr DataRate operator*(const DataSize size,
+ const Frequency frequency) {
+ RTC_DCHECK(frequency.IsZero() ||
+ size.bytes() <= std::numeric_limits<int64_t>::max() / 8 /
+ frequency.millihertz<int64_t>());
+ int64_t millibits_per_second =
+ size.bytes() * 8 * frequency.millihertz<int64_t>();
+ return DataRate::BitsPerSec((millibits_per_second + 500) / 1000);
+}
+inline constexpr DataRate operator*(const Frequency frequency,
+ const DataSize size) {
+ return size * frequency;
+}
+
+std::string ToString(DataRate value);
+inline std::string ToLogString(DataRate value) {
+ return ToString(value);
+}
+
+#ifdef UNIT_TEST
+inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
+ std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
+ DataRate value) {
+ return stream << ToString(value);
+}
+#endif // UNIT_TEST
+
+} // namespace webrtc
+
+#endif // API_UNITS_DATA_RATE_H_
diff --git a/webrtc/api/units/data_size.cc b/webrtc/api/units/data_size.cc
new file mode 100644
index 0000000..45487df
--- /dev/null
+++ b/webrtc/api/units/data_size.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/units/data_size.h"
+
+#include "api/array_view.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+std::string ToString(DataSize value) {
+ char buf[64];
+ rtc::SimpleStringBuilder sb(buf);
+ if (value.IsPlusInfinity()) {
+ sb << "+inf bytes";
+ } else if (value.IsMinusInfinity()) {
+ sb << "-inf bytes";
+ } else {
+ sb << value.bytes() << " bytes";
+ }
+ return sb.str();
+}
+} // namespace webrtc
diff --git a/webrtc/api/units/data_size.h b/webrtc/api/units/data_size.h
new file mode 100644
index 0000000..27a2a4e
--- /dev/null
+++ b/webrtc/api/units/data_size.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_UNITS_DATA_SIZE_H_
+#define API_UNITS_DATA_SIZE_H_
+
+#ifdef UNIT_TEST
+#include <ostream> // no-presubmit-check TODO(webrtc:8982)
+#endif // UNIT_TEST
+
+#include <string>
+#include <type_traits>
+
+#include "rtc_base/units/unit_base.h"
+
+namespace webrtc {
+// DataSize is a class represeting a count of bytes.
+class DataSize final : public rtc_units_impl::RelativeUnit<DataSize> {
+ public:
+ template <typename T>
+ static constexpr DataSize Bytes(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromValue(value);
+ }
+ static constexpr DataSize Infinity() { return PlusInfinity(); }
+
+ DataSize() = delete;
+
+ template <typename T = int64_t>
+ constexpr T bytes() const {
+ return ToValue<T>();
+ }
+
+ constexpr int64_t bytes_or(int64_t fallback_value) const {
+ return ToValueOr(fallback_value);
+ }
+
+ private:
+ friend class rtc_units_impl::UnitBase<DataSize>;
+ using RelativeUnit::RelativeUnit;
+ static constexpr bool one_sided = true;
+};
+
+std::string ToString(DataSize value);
+inline std::string ToLogString(DataSize value) {
+ return ToString(value);
+}
+
+#ifdef UNIT_TEST
+inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
+ std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
+ DataSize value) {
+ return stream << ToString(value);
+}
+#endif // UNIT_TEST
+
+} // namespace webrtc
+
+#endif // API_UNITS_DATA_SIZE_H_
diff --git a/webrtc/api/units/frequency.cc b/webrtc/api/units/frequency.cc
new file mode 100644
index 0000000..2d938a2
--- /dev/null
+++ b/webrtc/api/units/frequency.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "api/units/frequency.h"
+
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+std::string ToString(Frequency value) {
+ char buf[64];
+ rtc::SimpleStringBuilder sb(buf);
+ if (value.IsPlusInfinity()) {
+ sb << "+inf Hz";
+ } else if (value.IsMinusInfinity()) {
+ sb << "-inf Hz";
+ } else if (value.millihertz<int64_t>() % 1000 != 0) {
+ sb.AppendFormat("%.3f Hz", value.hertz<double>());
+ } else {
+ sb << value.hertz<int64_t>() << " Hz";
+ }
+ return sb.str();
+}
+} // namespace webrtc
diff --git a/webrtc/api/units/frequency.h b/webrtc/api/units/frequency.h
new file mode 100644
index 0000000..88912c6
--- /dev/null
+++ b/webrtc/api/units/frequency.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef API_UNITS_FREQUENCY_H_
+#define API_UNITS_FREQUENCY_H_
+
+#ifdef UNIT_TEST
+#include <ostream> // no-presubmit-check TODO(webrtc:8982)
+#endif // UNIT_TEST
+
+#include <cstdlib>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "api/units/time_delta.h"
+#include "rtc_base/units/unit_base.h"
+
+namespace webrtc {
+
+class Frequency final : public rtc_units_impl::RelativeUnit<Frequency> {
+ public:
+ template <typename T>
+ static constexpr Frequency MilliHertz(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromValue(value);
+ }
+ template <typename T>
+ static constexpr Frequency Hertz(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction(1'000, value);
+ }
+ template <typename T>
+ static constexpr Frequency KiloHertz(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction(1'000'000, value);
+ }
+
+ Frequency() = delete;
+
+ template <typename T = int64_t>
+ constexpr T hertz() const {
+ return ToFraction<1000, T>();
+ }
+ template <typename T = int64_t>
+ constexpr T millihertz() const {
+ return ToValue<T>();
+ }
+
+ private:
+ friend class rtc_units_impl::UnitBase<Frequency>;
+ using RelativeUnit::RelativeUnit;
+ static constexpr bool one_sided = true;
+};
+
+inline constexpr Frequency operator/(int64_t nominator,
+ const TimeDelta& interval) {
+ constexpr int64_t kKiloPerMicro = 1000 * 1000000;
+ RTC_DCHECK_LE(nominator, std::numeric_limits<int64_t>::max() / kKiloPerMicro);
+ RTC_CHECK(interval.IsFinite());
+ RTC_CHECK(!interval.IsZero());
+ return Frequency::MilliHertz(nominator * kKiloPerMicro / interval.us());
+}
+
+inline constexpr TimeDelta operator/(int64_t nominator,
+ const Frequency& frequency) {
+ constexpr int64_t kMegaPerMilli = 1000000 * 1000;
+ RTC_DCHECK_LE(nominator, std::numeric_limits<int64_t>::max() / kMegaPerMilli);
+ RTC_CHECK(frequency.IsFinite());
+ RTC_CHECK(!frequency.IsZero());
+ return TimeDelta::Micros(nominator * kMegaPerMilli / frequency.millihertz());
+}
+
+inline constexpr double operator*(Frequency frequency, TimeDelta time_delta) {
+ return frequency.hertz<double>() * time_delta.seconds<double>();
+}
+inline constexpr double operator*(TimeDelta time_delta, Frequency frequency) {
+ return frequency * time_delta;
+}
+
+std::string ToString(Frequency value);
+inline std::string ToLogString(Frequency value) {
+ return ToString(value);
+}
+
+#ifdef UNIT_TEST
+inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
+ std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
+ Frequency value) {
+ return stream << ToString(value);
+}
+#endif // UNIT_TEST
+
+} // namespace webrtc
+#endif // API_UNITS_FREQUENCY_H_
diff --git a/webrtc/api/units/time_delta.cc b/webrtc/api/units/time_delta.cc
new file mode 100644
index 0000000..31bf3e0
--- /dev/null
+++ b/webrtc/api/units/time_delta.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/units/time_delta.h"
+
+#include "api/array_view.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+std::string ToString(TimeDelta value) {
+ char buf[64];
+ rtc::SimpleStringBuilder sb(buf);
+ if (value.IsPlusInfinity()) {
+ sb << "+inf ms";
+ } else if (value.IsMinusInfinity()) {
+ sb << "-inf ms";
+ } else {
+ if (value.us() == 0 || (value.us() % 1000) != 0)
+ sb << value.us() << " us";
+ else if (value.ms() % 1000 != 0)
+ sb << value.ms() << " ms";
+ else
+ sb << value.seconds() << " s";
+ }
+ return sb.str();
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/units/time_delta.h b/webrtc/api/units/time_delta.h
new file mode 100644
index 0000000..173affc
--- /dev/null
+++ b/webrtc/api/units/time_delta.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_UNITS_TIME_DELTA_H_
+#define API_UNITS_TIME_DELTA_H_
+
+#ifdef UNIT_TEST
+#include <ostream> // no-presubmit-check TODO(webrtc:8982)
+#endif // UNIT_TEST
+
+#include <cstdlib>
+#include <string>
+#include <type_traits>
+
+#include "rtc_base/units/unit_base.h"
+
+namespace webrtc {
+
+// TimeDelta represents the difference between two timestamps. Commonly this can
+// be a duration. However since two Timestamps are not guaranteed to have the
+// same epoch (they might come from different computers, making exact
+// synchronisation infeasible), the duration covered by a TimeDelta can be
+// undefined. To simplify usage, it can be constructed and converted to
+// different units, specifically seconds (s), milliseconds (ms) and
+// microseconds (us).
+class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
+ public:
+ template <typename T>
+ static constexpr TimeDelta Seconds(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction(1'000'000, value);
+ }
+ template <typename T>
+ static constexpr TimeDelta Millis(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction(1'000, value);
+ }
+ template <typename T>
+ static constexpr TimeDelta Micros(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromValue(value);
+ }
+
+ TimeDelta() = delete;
+
+ template <typename T = int64_t>
+ constexpr T seconds() const {
+ return ToFraction<1000000, T>();
+ }
+ template <typename T = int64_t>
+ constexpr T ms() const {
+ return ToFraction<1000, T>();
+ }
+ template <typename T = int64_t>
+ constexpr T us() const {
+ return ToValue<T>();
+ }
+ template <typename T = int64_t>
+ constexpr T ns() const {
+ return ToMultiple<1000, T>();
+ }
+
+ constexpr int64_t seconds_or(int64_t fallback_value) const {
+ return ToFractionOr<1000000>(fallback_value);
+ }
+ constexpr int64_t ms_or(int64_t fallback_value) const {
+ return ToFractionOr<1000>(fallback_value);
+ }
+ constexpr int64_t us_or(int64_t fallback_value) const {
+ return ToValueOr(fallback_value);
+ }
+
+ constexpr TimeDelta Abs() const {
+ return us() < 0 ? TimeDelta::Micros(-us()) : *this;
+ }
+
+ private:
+ friend class rtc_units_impl::UnitBase<TimeDelta>;
+ using RelativeUnit::RelativeUnit;
+ static constexpr bool one_sided = false;
+};
+
+std::string ToString(TimeDelta value);
+inline std::string ToLogString(TimeDelta value) {
+ return ToString(value);
+}
+
+#ifdef UNIT_TEST
+inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
+ std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
+ TimeDelta value) {
+ return stream << ToString(value);
+}
+#endif // UNIT_TEST
+
+} // namespace webrtc
+
+#endif // API_UNITS_TIME_DELTA_H_
diff --git a/webrtc/api/units/timestamp.cc b/webrtc/api/units/timestamp.cc
new file mode 100644
index 0000000..fc4f419
--- /dev/null
+++ b/webrtc/api/units/timestamp.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/units/timestamp.h"
+
+#include "api/array_view.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+std::string ToString(Timestamp value) {
+ char buf[64];
+ rtc::SimpleStringBuilder sb(buf);
+ if (value.IsPlusInfinity()) {
+ sb << "+inf ms";
+ } else if (value.IsMinusInfinity()) {
+ sb << "-inf ms";
+ } else {
+ if (value.us() == 0 || (value.us() % 1000) != 0)
+ sb << value.us() << " us";
+ else if (value.ms() % 1000 != 0)
+ sb << value.ms() << " ms";
+ else
+ sb << value.seconds() << " s";
+ }
+ return sb.str();
+}
+} // namespace webrtc
diff --git a/webrtc/api/units/timestamp.h b/webrtc/api/units/timestamp.h
new file mode 100644
index 0000000..f83477e
--- /dev/null
+++ b/webrtc/api/units/timestamp.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_UNITS_TIMESTAMP_H_
+#define API_UNITS_TIMESTAMP_H_
+
+#ifdef UNIT_TEST
+#include <ostream> // no-presubmit-check TODO(webrtc:8982)
+#endif // UNIT_TEST
+
+#include <string>
+#include <type_traits>
+
+#include "api/units/time_delta.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+// Timestamp represents the time that has passed since some unspecified epoch.
+// The epoch is assumed to be before any represented timestamps, this means that
+// negative values are not valid. The most notable feature is that the
+// difference of two Timestamps results in a TimeDelta.
+class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
+ public:
+ template <typename T>
+ static constexpr Timestamp Seconds(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction(1'000'000, value);
+ }
+ template <typename T>
+ static constexpr Timestamp Millis(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromFraction(1'000, value);
+ }
+ template <typename T>
+ static constexpr Timestamp Micros(T value) {
+ static_assert(std::is_arithmetic<T>::value, "");
+ return FromValue(value);
+ }
+
+ Timestamp() = delete;
+
+ template <typename T = int64_t>
+ constexpr T seconds() const {
+ return ToFraction<1000000, T>();
+ }
+ template <typename T = int64_t>
+ constexpr T ms() const {
+ return ToFraction<1000, T>();
+ }
+ template <typename T = int64_t>
+ constexpr T us() const {
+ return ToValue<T>();
+ }
+
+ constexpr int64_t seconds_or(int64_t fallback_value) const {
+ return ToFractionOr<1000000>(fallback_value);
+ }
+ constexpr int64_t ms_or(int64_t fallback_value) const {
+ return ToFractionOr<1000>(fallback_value);
+ }
+ constexpr int64_t us_or(int64_t fallback_value) const {
+ return ToValueOr(fallback_value);
+ }
+
+ constexpr Timestamp operator+(const TimeDelta delta) const {
+ if (IsPlusInfinity() || delta.IsPlusInfinity()) {
+ RTC_DCHECK(!IsMinusInfinity());
+ RTC_DCHECK(!delta.IsMinusInfinity());
+ return PlusInfinity();
+ } else if (IsMinusInfinity() || delta.IsMinusInfinity()) {
+ RTC_DCHECK(!IsPlusInfinity());
+ RTC_DCHECK(!delta.IsPlusInfinity());
+ return MinusInfinity();
+ }
+ return Timestamp::Micros(us() + delta.us());
+ }
+ constexpr Timestamp operator-(const TimeDelta delta) const {
+ if (IsPlusInfinity() || delta.IsMinusInfinity()) {
+ RTC_DCHECK(!IsMinusInfinity());
+ RTC_DCHECK(!delta.IsPlusInfinity());
+ return PlusInfinity();
+ } else if (IsMinusInfinity() || delta.IsPlusInfinity()) {
+ RTC_DCHECK(!IsPlusInfinity());
+ RTC_DCHECK(!delta.IsMinusInfinity());
+ return MinusInfinity();
+ }
+ return Timestamp::Micros(us() - delta.us());
+ }
+ constexpr TimeDelta operator-(const Timestamp other) const {
+ if (IsPlusInfinity() || other.IsMinusInfinity()) {
+ RTC_DCHECK(!IsMinusInfinity());
+ RTC_DCHECK(!other.IsPlusInfinity());
+ return TimeDelta::PlusInfinity();
+ } else if (IsMinusInfinity() || other.IsPlusInfinity()) {
+ RTC_DCHECK(!IsPlusInfinity());
+ RTC_DCHECK(!other.IsMinusInfinity());
+ return TimeDelta::MinusInfinity();
+ }
+ return TimeDelta::Micros(us() - other.us());
+ }
+ constexpr Timestamp& operator-=(const TimeDelta delta) {
+ *this = *this - delta;
+ return *this;
+ }
+ constexpr Timestamp& operator+=(const TimeDelta delta) {
+ *this = *this + delta;
+ return *this;
+ }
+
+ private:
+ friend class rtc_units_impl::UnitBase<Timestamp>;
+ using UnitBase::UnitBase;
+ static constexpr bool one_sided = true;
+};
+
+std::string ToString(Timestamp value);
+inline std::string ToLogString(Timestamp value) {
+ return ToString(value);
+}
+
+#ifdef UNIT_TEST
+inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
+ std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
+ Timestamp value) {
+ return stream << ToString(value);
+}
+#endif // UNIT_TEST
+
+} // namespace webrtc
+
+#endif // API_UNITS_TIMESTAMP_H_
diff --git a/webrtc/api/video/color_space.cc b/webrtc/api/video/color_space.cc
new file mode 100644
index 0000000..710bb43
--- /dev/null
+++ b/webrtc/api/video/color_space.cc
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/video/color_space.h"
+
+namespace webrtc {
+namespace {
+// Try to convert |enum_value| into the enum class T. |enum_bitmask| is created
+// by the funciton below. Returns true if conversion was successful, false
+// otherwise.
+template <typename T>
+bool SetFromUint8(uint8_t enum_value, uint64_t enum_bitmask, T* out) {
+ if ((enum_value < 64) && ((enum_bitmask >> enum_value) & 1)) {
+ *out = static_cast<T>(enum_value);
+ return true;
+ }
+ return false;
+}
+
+// This function serves as an assert for the constexpr function below. It's on
+// purpose not declared as constexpr so that it causes a build problem if enum
+// values of 64 or above are used. The bitmask and the code generating it would
+// have to be extended if the standard is updated to include enum values >= 64.
+int EnumMustBeLessThan64() {
+ return -1;
+}
+
+template <typename T, size_t N>
+constexpr int MakeMask(const int index, const int length, T (&values)[N]) {
+ return length > 1
+ ? (MakeMask(index, 1, values) +
+ MakeMask(index + 1, length - 1, values))
+ : (static_cast<uint8_t>(values[index]) < 64
+ ? (uint64_t{1} << static_cast<uint8_t>(values[index]))
+ : EnumMustBeLessThan64());
+}
+
+// Create a bitmask where each bit corresponds to one potential enum value.
+// |values| should be an array listing all possible enum values. The bit is set
+// to one if the corresponding enum exists. Only works for enums with values
+// less than 64.
+template <typename T, size_t N>
+constexpr uint64_t CreateEnumBitmask(T (&values)[N]) {
+ return MakeMask(0, N, values);
+}
+
+bool SetChromaSitingFromUint8(uint8_t enum_value,
+ ColorSpace::ChromaSiting* chroma_siting) {
+ constexpr ColorSpace::ChromaSiting kChromaSitings[] = {
+ ColorSpace::ChromaSiting::kUnspecified,
+ ColorSpace::ChromaSiting::kCollocated, ColorSpace::ChromaSiting::kHalf};
+ constexpr uint64_t enum_bitmask = CreateEnumBitmask(kChromaSitings);
+
+ return SetFromUint8(enum_value, enum_bitmask, chroma_siting);
+}
+
+} // namespace
+
+ColorSpace::ColorSpace() = default;
+ColorSpace::ColorSpace(const ColorSpace& other) = default;
+ColorSpace::ColorSpace(ColorSpace&& other) = default;
+ColorSpace& ColorSpace::operator=(const ColorSpace& other) = default;
+
+ColorSpace::ColorSpace(PrimaryID primaries,
+ TransferID transfer,
+ MatrixID matrix,
+ RangeID range)
+ : ColorSpace(primaries,
+ transfer,
+ matrix,
+ range,
+ ChromaSiting::kUnspecified,
+ ChromaSiting::kUnspecified,
+ nullptr) {}
+
+ColorSpace::ColorSpace(PrimaryID primaries,
+ TransferID transfer,
+ MatrixID matrix,
+ RangeID range,
+ ChromaSiting chroma_siting_horz,
+ ChromaSiting chroma_siting_vert,
+ const HdrMetadata* hdr_metadata)
+ : primaries_(primaries),
+ transfer_(transfer),
+ matrix_(matrix),
+ range_(range),
+ chroma_siting_horizontal_(chroma_siting_horz),
+ chroma_siting_vertical_(chroma_siting_vert),
+ hdr_metadata_(hdr_metadata ? absl::make_optional(*hdr_metadata)
+ : absl::nullopt) {}
+
+ColorSpace::PrimaryID ColorSpace::primaries() const {
+ return primaries_;
+}
+
+ColorSpace::TransferID ColorSpace::transfer() const {
+ return transfer_;
+}
+
+ColorSpace::MatrixID ColorSpace::matrix() const {
+ return matrix_;
+}
+
+ColorSpace::RangeID ColorSpace::range() const {
+ return range_;
+}
+
+ColorSpace::ChromaSiting ColorSpace::chroma_siting_horizontal() const {
+ return chroma_siting_horizontal_;
+}
+
+ColorSpace::ChromaSiting ColorSpace::chroma_siting_vertical() const {
+ return chroma_siting_vertical_;
+}
+
+const HdrMetadata* ColorSpace::hdr_metadata() const {
+ return hdr_metadata_ ? &*hdr_metadata_ : nullptr;
+}
+
+bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) {
+ constexpr PrimaryID kPrimaryIds[] = {
+ PrimaryID::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M,
+ PrimaryID::kBT470BG, PrimaryID::kSMPTE170M, PrimaryID::kSMPTE240M,
+ PrimaryID::kFILM, PrimaryID::kBT2020, PrimaryID::kSMPTEST428,
+ PrimaryID::kSMPTEST431, PrimaryID::kSMPTEST432, PrimaryID::kJEDECP22};
+ constexpr uint64_t enum_bitmask = CreateEnumBitmask(kPrimaryIds);
+
+ return SetFromUint8(enum_value, enum_bitmask, &primaries_);
+}
+
+bool ColorSpace::set_transfer_from_uint8(uint8_t enum_value) {
+ constexpr TransferID kTransferIds[] = {
+ TransferID::kBT709, TransferID::kUnspecified,
+ TransferID::kGAMMA22, TransferID::kGAMMA28,
+ TransferID::kSMPTE170M, TransferID::kSMPTE240M,
+ TransferID::kLINEAR, TransferID::kLOG,
+ TransferID::kLOG_SQRT, TransferID::kIEC61966_2_4,
+ TransferID::kBT1361_ECG, TransferID::kIEC61966_2_1,
+ TransferID::kBT2020_10, TransferID::kBT2020_12,
+ TransferID::kSMPTEST2084, TransferID::kSMPTEST428,
+ TransferID::kARIB_STD_B67};
+ constexpr uint64_t enum_bitmask = CreateEnumBitmask(kTransferIds);
+
+ return SetFromUint8(enum_value, enum_bitmask, &transfer_);
+}
+
+bool ColorSpace::set_matrix_from_uint8(uint8_t enum_value) {
+ constexpr MatrixID kMatrixIds[] = {
+ MatrixID::kRGB, MatrixID::kBT709, MatrixID::kUnspecified,
+ MatrixID::kFCC, MatrixID::kBT470BG, MatrixID::kSMPTE170M,
+ MatrixID::kSMPTE240M, MatrixID::kYCOCG, MatrixID::kBT2020_NCL,
+ MatrixID::kBT2020_CL, MatrixID::kSMPTE2085, MatrixID::kCDNCLS,
+ MatrixID::kCDCLS, MatrixID::kBT2100_ICTCP};
+ constexpr uint64_t enum_bitmask = CreateEnumBitmask(kMatrixIds);
+
+ return SetFromUint8(enum_value, enum_bitmask, &matrix_);
+}
+
+bool ColorSpace::set_range_from_uint8(uint8_t enum_value) {
+ constexpr RangeID kRangeIds[] = {RangeID::kInvalid, RangeID::kLimited,
+ RangeID::kFull, RangeID::kDerived};
+ constexpr uint64_t enum_bitmask = CreateEnumBitmask(kRangeIds);
+
+ return SetFromUint8(enum_value, enum_bitmask, &range_);
+}
+
+bool ColorSpace::set_chroma_siting_horizontal_from_uint8(uint8_t enum_value) {
+ return SetChromaSitingFromUint8(enum_value, &chroma_siting_horizontal_);
+}
+
+bool ColorSpace::set_chroma_siting_vertical_from_uint8(uint8_t enum_value) {
+ return SetChromaSitingFromUint8(enum_value, &chroma_siting_vertical_);
+}
+
+void ColorSpace::set_hdr_metadata(const HdrMetadata* hdr_metadata) {
+ hdr_metadata_ =
+ hdr_metadata ? absl::make_optional(*hdr_metadata) : absl::nullopt;
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/video/color_space.h b/webrtc/api/video/color_space.h
new file mode 100644
index 0000000..a7ad86b
--- /dev/null
+++ b/webrtc/api/video/color_space.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_VIDEO_COLOR_SPACE_H_
+#define API_VIDEO_COLOR_SPACE_H_
+
+#include <stdint.h>
+
+#include "absl/types/optional.h"
+#include "api/video/hdr_metadata.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+
+// This class represents color information as specified in T-REC H.273,
+// available from https://www.itu.int/rec/T-REC-H.273.
+//
+// WebRTC's supported codecs:
+// - VP9 supports color profiles, see VP9 Bitstream & Decoding Process
+// Specification Version 0.6 Section 7.2.2 "Color config semantics" available
+// from https://www.webmproject.org.
+// - VP8 only supports BT.601, see
+// https://tools.ietf.org/html/rfc6386#section-9.2
+// - H264 uses the exact same representation as T-REC H.273. See T-REC-H.264
+// E.2.1, "VUI parameters semantics", available from
+// https://www.itu.int/rec/T-REC-H.264.
+
+class RTC_EXPORT ColorSpace {
+ public:
+ enum class PrimaryID : uint8_t {
+ // The indices are equal to the values specified in T-REC H.273 Table 2.
+ kBT709 = 1,
+ kUnspecified = 2,
+ kBT470M = 4,
+ kBT470BG = 5,
+ kSMPTE170M = 6, // Identical to BT601
+ kSMPTE240M = 7,
+ kFILM = 8,
+ kBT2020 = 9,
+ kSMPTEST428 = 10,
+ kSMPTEST431 = 11,
+ kSMPTEST432 = 12,
+ kJEDECP22 = 22, // Identical to EBU3213-E
+ // When adding/removing entries here, please make sure to do the
+ // corresponding change to kPrimaryIds.
+ };
+
+ enum class TransferID : uint8_t {
+ // The indices are equal to the values specified in T-REC H.273 Table 3.
+ kBT709 = 1,
+ kUnspecified = 2,
+ kGAMMA22 = 4,
+ kGAMMA28 = 5,
+ kSMPTE170M = 6,
+ kSMPTE240M = 7,
+ kLINEAR = 8,
+ kLOG = 9,
+ kLOG_SQRT = 10,
+ kIEC61966_2_4 = 11,
+ kBT1361_ECG = 12,
+ kIEC61966_2_1 = 13,
+ kBT2020_10 = 14,
+ kBT2020_12 = 15,
+ kSMPTEST2084 = 16,
+ kSMPTEST428 = 17,
+ kARIB_STD_B67 = 18,
+ // When adding/removing entries here, please make sure to do the
+ // corresponding change to kTransferIds.
+ };
+
+ enum class MatrixID : uint8_t {
+ // The indices are equal to the values specified in T-REC H.273 Table 4.
+ kRGB = 0,
+ kBT709 = 1,
+ kUnspecified = 2,
+ kFCC = 4,
+ kBT470BG = 5,
+ kSMPTE170M = 6,
+ kSMPTE240M = 7,
+ kYCOCG = 8,
+ kBT2020_NCL = 9,
+ kBT2020_CL = 10,
+ kSMPTE2085 = 11,
+ kCDNCLS = 12,
+ kCDCLS = 13,
+ kBT2100_ICTCP = 14,
+ // When adding/removing entries here, please make sure to do the
+ // corresponding change to kMatrixIds.
+ };
+
+ enum class RangeID {
+ // The indices are equal to the values specified at
+ // https://www.webmproject.org/docs/container/#colour for the element Range.
+ kInvalid = 0,
+ // Limited Rec. 709 color range with RGB values ranging from 16 to 235.
+ kLimited = 1,
+ // Full RGB color range with RGB valees from 0 to 255.
+ kFull = 2,
+ // Range is defined by MatrixCoefficients/TransferCharacteristics.
+ kDerived = 3,
+ // When adding/removing entries here, please make sure to do the
+ // corresponding change to kRangeIds.
+ };
+
+ enum class ChromaSiting {
+ // Chroma siting specifies how chroma is subsampled relative to the luma
+ // samples in a YUV video frame.
+ // The indices are equal to the values specified at
+ // https://www.webmproject.org/docs/container/#colour for the element
+ // ChromaSitingVert and ChromaSitingHorz.
+ kUnspecified = 0,
+ kCollocated = 1,
+ kHalf = 2,
+ // When adding/removing entries here, please make sure to do the
+ // corresponding change to kChromaSitings.
+ };
+
+ ColorSpace();
+ ColorSpace(const ColorSpace& other);
+ ColorSpace(ColorSpace&& other);
+ ColorSpace& operator=(const ColorSpace& other);
+ ColorSpace(PrimaryID primaries,
+ TransferID transfer,
+ MatrixID matrix,
+ RangeID range);
+ ColorSpace(PrimaryID primaries,
+ TransferID transfer,
+ MatrixID matrix,
+ RangeID range,
+ ChromaSiting chroma_siting_horizontal,
+ ChromaSiting chroma_siting_vertical,
+ const HdrMetadata* hdr_metadata);
+ friend bool operator==(const ColorSpace& lhs, const ColorSpace& rhs) {
+ return lhs.primaries_ == rhs.primaries_ && lhs.transfer_ == rhs.transfer_ &&
+ lhs.matrix_ == rhs.matrix_ && lhs.range_ == rhs.range_ &&
+ lhs.chroma_siting_horizontal_ == rhs.chroma_siting_horizontal_ &&
+ lhs.chroma_siting_vertical_ == rhs.chroma_siting_vertical_ &&
+ lhs.hdr_metadata_ == rhs.hdr_metadata_;
+ }
+ friend bool operator!=(const ColorSpace& lhs, const ColorSpace& rhs) {
+ return !(lhs == rhs);
+ }
+
+ PrimaryID primaries() const;
+ TransferID transfer() const;
+ MatrixID matrix() const;
+ RangeID range() const;
+ ChromaSiting chroma_siting_horizontal() const;
+ ChromaSiting chroma_siting_vertical() const;
+ const HdrMetadata* hdr_metadata() const;
+
+ bool set_primaries_from_uint8(uint8_t enum_value);
+ bool set_transfer_from_uint8(uint8_t enum_value);
+ bool set_matrix_from_uint8(uint8_t enum_value);
+ bool set_range_from_uint8(uint8_t enum_value);
+ bool set_chroma_siting_horizontal_from_uint8(uint8_t enum_value);
+ bool set_chroma_siting_vertical_from_uint8(uint8_t enum_value);
+ void set_hdr_metadata(const HdrMetadata* hdr_metadata);
+
+ private:
+ PrimaryID primaries_ = PrimaryID::kUnspecified;
+ TransferID transfer_ = TransferID::kUnspecified;
+ MatrixID matrix_ = MatrixID::kUnspecified;
+ RangeID range_ = RangeID::kInvalid;
+ ChromaSiting chroma_siting_horizontal_ = ChromaSiting::kUnspecified;
+ ChromaSiting chroma_siting_vertical_ = ChromaSiting::kUnspecified;
+ absl::optional<HdrMetadata> hdr_metadata_;
+};
+
+} // namespace webrtc
+#endif // API_VIDEO_COLOR_SPACE_H_
diff --git a/webrtc/api/video/hdr_metadata.cc b/webrtc/api/video/hdr_metadata.cc
new file mode 100644
index 0000000..e2a669c
--- /dev/null
+++ b/webrtc/api/video/hdr_metadata.cc
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "api/video/hdr_metadata.h"
+
+namespace webrtc {
+
+HdrMasteringMetadata::Chromaticity::Chromaticity() = default;
+
+HdrMasteringMetadata::HdrMasteringMetadata() = default;
+
+HdrMetadata::HdrMetadata() = default;
+
+} // namespace webrtc
diff --git a/webrtc/api/video/hdr_metadata.h b/webrtc/api/video/hdr_metadata.h
new file mode 100644
index 0000000..e9001a2
--- /dev/null
+++ b/webrtc/api/video/hdr_metadata.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_VIDEO_HDR_METADATA_H_
+#define API_VIDEO_HDR_METADATA_H_
+
+namespace webrtc {
+
+// SMPTE ST 2086 mastering metadata,
+// see https://ieeexplore.ieee.org/document/8353899.
+struct HdrMasteringMetadata {
+ struct Chromaticity {
+ Chromaticity();
+
+ bool operator==(const Chromaticity& rhs) const {
+ return x == rhs.x && y == rhs.y;
+ }
+
+ bool Validate() const {
+ return x >= 0.0 && x <= 1.0 && y >= 0.0 && y <= 1.0;
+ }
+
+ // xy chromaticity coordinates must be calculated as specified in ISO
+ // 11664-3:2012 Section 7, and must be specified with four decimal places.
+ // The x coordinate should be in the range [0.0001, 0.7400] and the y
+ // coordinate should be in the range [0.0001, 0.8400]. Valid range [0.0000,
+ // 1.0000].
+ float x = 0.0f;
+ float y = 0.0f;
+ };
+
+ HdrMasteringMetadata();
+
+ bool operator==(const HdrMasteringMetadata& rhs) const {
+ return ((primary_r == rhs.primary_r) && (primary_g == rhs.primary_g) &&
+ (primary_b == rhs.primary_b) && (white_point == rhs.white_point) &&
+ (luminance_max == rhs.luminance_max) &&
+ (luminance_min == rhs.luminance_min));
+ }
+
+ bool Validate() const {
+ return luminance_max >= 0.0 && luminance_max <= 20000.0 &&
+ luminance_min >= 0.0 && luminance_min <= 5.0 &&
+ primary_r.Validate() && primary_g.Validate() &&
+ primary_b.Validate() && white_point.Validate();
+ }
+
+ // The nominal primaries of the mastering display.
+ Chromaticity primary_r;
+ Chromaticity primary_g;
+ Chromaticity primary_b;
+
+ // The nominal chromaticity of the white point of the mastering display.
+ Chromaticity white_point;
+
+ // The nominal maximum display luminance of the mastering display. Specified
+ // in the unit candela/m2. The value should be in the range [5, 10000] with
+ // zero decimal places. Valid range [0, 20000].
+ float luminance_max = 0.0f;
+
+ // The nominal minimum display luminance of the mastering display. Specified
+ // in the unit candela/m2. The value should be in the range [0.0001, 5.0000]
+ // with four decimal places. Valid range [0.0000, 5.0000].
+ float luminance_min = 0.0f;
+};
+
+// High dynamic range (HDR) metadata common for HDR10 and WebM/VP9-based HDR
+// formats. This struct replicates the HDRMetadata struct defined in
+// https://cs.chromium.org/chromium/src/media/base/hdr_metadata.h
+struct HdrMetadata {
+ HdrMetadata();
+
+ bool operator==(const HdrMetadata& rhs) const {
+ return (
+ (max_content_light_level == rhs.max_content_light_level) &&
+ (max_frame_average_light_level == rhs.max_frame_average_light_level) &&
+ (mastering_metadata == rhs.mastering_metadata));
+ }
+
+ bool Validate() const {
+ return max_content_light_level >= 0 && max_content_light_level <= 20000 &&
+ max_frame_average_light_level >= 0 &&
+ max_frame_average_light_level <= 20000 &&
+ mastering_metadata.Validate();
+ }
+
+ HdrMasteringMetadata mastering_metadata;
+ // Max content light level (CLL), i.e. maximum brightness level present in the
+ // stream, in nits. 1 nit = 1 candela/m2. Valid range [0, 20000].
+ int max_content_light_level = 0;
+ // Max frame-average light level (FALL), i.e. maximum average brightness of
+ // the brightest frame in the stream, in nits. Valid range [0, 20000].
+ int max_frame_average_light_level = 0;
+};
+
+} // namespace webrtc
+
+#endif // API_VIDEO_HDR_METADATA_H_
diff --git a/webrtc/api/video/video_content_type.cc b/webrtc/api/video/video_content_type.cc
new file mode 100644
index 0000000..9ba3ece
--- /dev/null
+++ b/webrtc/api/video/video_content_type.cc
@@ -0,0 +1,93 @@
+/*
+ * 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 "api/video/video_content_type.h"
+
+// VideoContentType stored as a single byte, which is sent over the network.
+// Structure:
+//
+// 0 1 2 3 4 5 6 7
+// +---------------+
+// |r r e e e s s c|
+//
+// where:
+// r - reserved bits.
+// e - 3-bit number of an experiment group counted from 1. 0 means there's no
+// experiment ongoing.
+// s - 2-bit simulcast stream id or spatial layer, counted from 1. 0 means that
+// no simulcast information is set.
+// c - content type. 0 means real-time video, 1 means screenshare.
+//
+
+namespace webrtc {
+namespace videocontenttypehelpers {
+
+namespace {
+static constexpr uint8_t kScreenshareBitsSize = 1;
+static constexpr uint8_t kScreenshareBitsMask =
+ (1u << kScreenshareBitsSize) - 1;
+
+static constexpr uint8_t kSimulcastShift = 1;
+static constexpr uint8_t kSimulcastBitsSize = 2;
+static constexpr uint8_t kSimulcastBitsMask = ((1u << kSimulcastBitsSize) - 1)
+ << kSimulcastShift; // 0b00000110
+
+static constexpr uint8_t kExperimentShift = 3;
+static constexpr uint8_t kExperimentBitsSize = 3;
+static constexpr uint8_t kExperimentBitsMask =
+ ((1u << kExperimentBitsSize) - 1) << kExperimentShift; // 0b00111000
+
+static constexpr uint8_t kTotalBitsSize =
+ kScreenshareBitsSize + kSimulcastBitsSize + kExperimentBitsSize;
+} // namespace
+
+bool SetExperimentId(VideoContentType* content_type, uint8_t experiment_id) {
+ // Store in bits 2-4.
+ if (experiment_id >= (1 << kExperimentBitsSize))
+ return false;
+ *content_type = static_cast<VideoContentType>(
+ (static_cast<uint8_t>(*content_type) & ~kExperimentBitsMask) |
+ ((experiment_id << kExperimentShift) & kExperimentBitsMask));
+ return true;
+}
+
+bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id) {
+ // Store in bits 5-6.
+ if (simulcast_id >= (1 << kSimulcastBitsSize))
+ return false;
+ *content_type = static_cast<VideoContentType>(
+ (static_cast<uint8_t>(*content_type) & ~kSimulcastBitsMask) |
+ ((simulcast_id << kSimulcastShift) & kSimulcastBitsMask));
+ return true;
+}
+
+uint8_t GetExperimentId(const VideoContentType& content_type) {
+ return (static_cast<uint8_t>(content_type) & kExperimentBitsMask) >>
+ kExperimentShift;
+}
+uint8_t GetSimulcastId(const VideoContentType& content_type) {
+ return (static_cast<uint8_t>(content_type) & kSimulcastBitsMask) >>
+ kSimulcastShift;
+}
+
+bool IsScreenshare(const VideoContentType& content_type) {
+ return (static_cast<uint8_t>(content_type) & kScreenshareBitsMask) > 0;
+}
+
+bool IsValidContentType(uint8_t value) {
+ // Any 6-bit value is allowed.
+ return value < (1 << kTotalBitsSize);
+}
+
+const char* ToString(const VideoContentType& content_type) {
+ return IsScreenshare(content_type) ? "screen" : "realtime";
+}
+} // namespace videocontenttypehelpers
+} // namespace webrtc
diff --git a/webrtc/api/video/video_content_type.h b/webrtc/api/video/video_content_type.h
new file mode 100644
index 0000000..2d38a62
--- /dev/null
+++ b/webrtc/api/video/video_content_type.h
@@ -0,0 +1,39 @@
+/*
+ * 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 API_VIDEO_VIDEO_CONTENT_TYPE_H_
+#define API_VIDEO_VIDEO_CONTENT_TYPE_H_
+
+#include <stdint.h>
+
+namespace webrtc {
+
+enum class VideoContentType : uint8_t {
+ UNSPECIFIED = 0,
+ SCREENSHARE = 1,
+};
+
+namespace videocontenttypehelpers {
+bool SetExperimentId(VideoContentType* content_type, uint8_t experiment_id);
+bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id);
+
+uint8_t GetExperimentId(const VideoContentType& content_type);
+uint8_t GetSimulcastId(const VideoContentType& content_type);
+
+bool IsScreenshare(const VideoContentType& content_type);
+
+bool IsValidContentType(uint8_t value);
+
+const char* ToString(const VideoContentType& content_type);
+} // namespace videocontenttypehelpers
+
+} // namespace webrtc
+
+#endif // API_VIDEO_VIDEO_CONTENT_TYPE_H_
diff --git a/webrtc/api/video/video_rotation.h b/webrtc/api/video/video_rotation.h
new file mode 100644
index 0000000..6a29588
--- /dev/null
+++ b/webrtc/api/video/video_rotation.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_VIDEO_VIDEO_ROTATION_H_
+#define API_VIDEO_VIDEO_ROTATION_H_
+
+namespace webrtc {
+
+// enum for clockwise rotation.
+enum VideoRotation {
+ kVideoRotation_0 = 0,
+ kVideoRotation_90 = 90,
+ kVideoRotation_180 = 180,
+ kVideoRotation_270 = 270
+};
+
+} // namespace webrtc
+
+#endif // API_VIDEO_VIDEO_ROTATION_H_
diff --git a/webrtc/api/video/video_timing.cc b/webrtc/api/video/video_timing.cc
new file mode 100644
index 0000000..df1bc48
--- /dev/null
+++ b/webrtc/api/video/video_timing.cc
@@ -0,0 +1,92 @@
+/*
+ * 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 "api/video/video_timing.h"
+
+#include "api/array_view.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) {
+ if (time_ms < base_ms) {
+ RTC_DLOG(LS_ERROR) << "Delta " << (time_ms - base_ms)
+ << "ms expected to be positive";
+ }
+ return rtc::saturated_cast<uint16_t>(time_ms - base_ms);
+}
+
+TimingFrameInfo::TimingFrameInfo()
+ : rtp_timestamp(0),
+ capture_time_ms(-1),
+ encode_start_ms(-1),
+ encode_finish_ms(-1),
+ packetization_finish_ms(-1),
+ pacer_exit_ms(-1),
+ network_timestamp_ms(-1),
+ network2_timestamp_ms(-1),
+ receive_start_ms(-1),
+ receive_finish_ms(-1),
+ decode_start_ms(-1),
+ decode_finish_ms(-1),
+ render_time_ms(-1),
+ flags(VideoSendTiming::kNotTriggered) {}
+
+int64_t TimingFrameInfo::EndToEndDelay() const {
+ return capture_time_ms >= 0 ? decode_finish_ms - capture_time_ms : -1;
+}
+
+bool TimingFrameInfo::IsLongerThan(const TimingFrameInfo& other) const {
+ int64_t other_delay = other.EndToEndDelay();
+ return other_delay == -1 || EndToEndDelay() > other_delay;
+}
+
+bool TimingFrameInfo::operator<(const TimingFrameInfo& other) const {
+ return other.IsLongerThan(*this);
+}
+
+bool TimingFrameInfo::operator<=(const TimingFrameInfo& other) const {
+ return !IsLongerThan(other);
+}
+
+bool TimingFrameInfo::IsOutlier() const {
+ return !IsInvalid() && (flags & VideoSendTiming::kTriggeredBySize);
+}
+
+bool TimingFrameInfo::IsTimerTriggered() const {
+ return !IsInvalid() && (flags & VideoSendTiming::kTriggeredByTimer);
+}
+
+bool TimingFrameInfo::IsInvalid() const {
+ return flags == VideoSendTiming::kInvalid;
+}
+
+std::string TimingFrameInfo::ToString() const {
+ if (IsInvalid()) {
+ return "";
+ }
+
+ char buf[1024];
+ rtc::SimpleStringBuilder sb(buf);
+
+ sb << rtp_timestamp << ',' << capture_time_ms << ',' << encode_start_ms << ','
+ << encode_finish_ms << ',' << packetization_finish_ms << ','
+ << pacer_exit_ms << ',' << network_timestamp_ms << ','
+ << network2_timestamp_ms << ',' << receive_start_ms << ','
+ << receive_finish_ms << ',' << decode_start_ms << ',' << decode_finish_ms
+ << ',' << render_time_ms << ',' << IsOutlier() << ','
+ << IsTimerTriggered();
+
+ return sb.str();
+}
+
+} // namespace webrtc
diff --git a/webrtc/api/video/video_timing.h b/webrtc/api/video/video_timing.h
new file mode 100644
index 0000000..fbd9225
--- /dev/null
+++ b/webrtc/api/video/video_timing.h
@@ -0,0 +1,129 @@
+/*
+ * 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 API_VIDEO_VIDEO_TIMING_H_
+#define API_VIDEO_VIDEO_TIMING_H_
+
+#include <stdint.h>
+
+#include <limits>
+#include <string>
+
+namespace webrtc {
+
+// Video timing timestamps in ms counted from capture_time_ms of a frame.
+// This structure represents data sent in video-timing RTP header extension.
+struct VideoSendTiming {
+ enum TimingFrameFlags : uint8_t {
+ kNotTriggered = 0, // Timing info valid, but not to be transmitted.
+ // Used on send-side only.
+ kTriggeredByTimer = 1 << 0, // Frame marked for tracing by periodic timer.
+ kTriggeredBySize = 1 << 1, // Frame marked for tracing due to size.
+ kInvalid = std::numeric_limits<uint8_t>::max() // Invalid, ignore!
+ };
+
+ // Returns |time_ms - base_ms| capped at max 16-bit value.
+ // Used to fill this data structure as per
+ // https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores
+ // 16-bit deltas of timestamps from packet capture time.
+ static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms);
+
+ uint16_t encode_start_delta_ms;
+ uint16_t encode_finish_delta_ms;
+ uint16_t packetization_finish_delta_ms;
+ uint16_t pacer_exit_delta_ms;
+ uint16_t network_timestamp_delta_ms;
+ uint16_t network2_timestamp_delta_ms;
+ uint8_t flags;
+};
+
+// Used to report precise timings of a 'timing frames'. Contains all important
+// timestamps for a lifetime of that specific frame. Reported as a string via
+// GetStats(). Only frame which took the longest between two GetStats calls is
+// reported.
+struct TimingFrameInfo {
+ TimingFrameInfo();
+
+ // Returns end-to-end delay of a frame, if sender and receiver timestamps are
+ // synchronized, -1 otherwise.
+ int64_t EndToEndDelay() const;
+
+ // Returns true if current frame took longer to process than |other| frame.
+ // If other frame's clocks are not synchronized, current frame is always
+ // preferred.
+ bool IsLongerThan(const TimingFrameInfo& other) const;
+
+ // Returns true if flags are set to indicate this frame was marked for tracing
+ // due to the size being outside some limit.
+ bool IsOutlier() const;
+
+ // Returns true if flags are set to indicate this frame was marked fro tracing
+ // due to cyclic timer.
+ bool IsTimerTriggered() const;
+
+ // Returns true if the timing data is marked as invalid, in which case it
+ // should be ignored.
+ bool IsInvalid() const;
+
+ std::string ToString() const;
+
+ bool operator<(const TimingFrameInfo& other) const;
+
+ bool operator<=(const TimingFrameInfo& other) const;
+
+ uint32_t rtp_timestamp; // Identifier of a frame.
+ // All timestamps below are in local monotonous clock of a receiver.
+ // If sender clock is not yet estimated, sender timestamps
+ // (capture_time_ms ... pacer_exit_ms) are negative values, still
+ // relatively correct.
+ int64_t capture_time_ms; // Captrue time of a frame.
+ int64_t encode_start_ms; // Encode start time.
+ int64_t encode_finish_ms; // Encode completion time.
+ int64_t packetization_finish_ms; // Time when frame was passed to pacer.
+ int64_t pacer_exit_ms; // Time when last packet was pushed out of pacer.
+ // Two in-network RTP processor timestamps: meaning is application specific.
+ int64_t network_timestamp_ms;
+ int64_t network2_timestamp_ms;
+ int64_t receive_start_ms; // First received packet time.
+ int64_t receive_finish_ms; // Last received packet time.
+ int64_t decode_start_ms; // Decode start time.
+ int64_t decode_finish_ms; // Decode completion time.
+ int64_t render_time_ms; // Proposed render time to insure smooth playback.
+
+ uint8_t flags; // Flags indicating validity and/or why tracing was triggered.
+};
+
+// Minimum and maximum playout delay values from capture to render.
+// These are best effort values.
+//
+// A value < 0 indicates no change from previous valid value.
+//
+// min = max = 0 indicates that the receiver should try and render
+// frame as soon as possible.
+//
+// min = x, max = y indicates that the receiver is free to adapt
+// in the range (x, y) based on network jitter.
+struct VideoPlayoutDelay {
+ VideoPlayoutDelay() = default;
+ VideoPlayoutDelay(int min_ms, int max_ms) : min_ms(min_ms), max_ms(max_ms) {}
+ int min_ms = -1;
+ int max_ms = -1;
+
+ bool operator==(const VideoPlayoutDelay& rhs) const {
+ return min_ms == rhs.min_ms && max_ms == rhs.max_ms;
+ }
+};
+
+// TODO(bugs.webrtc.org/7660): Old name, delete after downstream use is updated.
+using PlayoutDelay = VideoPlayoutDelay;
+
+} // namespace webrtc
+
+#endif // API_VIDEO_VIDEO_TIMING_H_
diff --git a/webrtc/audio/utility/BUILD.gn b/webrtc/audio/utility/BUILD.gn
new file mode 100644
index 0000000..54ca046
--- /dev/null
+++ b/webrtc/audio/utility/BUILD.gn
@@ -0,0 +1,53 @@
+# 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.
+import("../../webrtc.gni")
+
+group("utility") {
+ deps = [ ":audio_frame_operations" ]
+}
+
+rtc_library("audio_frame_operations") {
+ visibility = [ "*" ]
+ sources = [
+ "audio_frame_operations.cc",
+ "audio_frame_operations.h",
+ "channel_mixer.cc",
+ "channel_mixer.h",
+ "channel_mixing_matrix.cc",
+ "channel_mixing_matrix.h",
+ ]
+
+ deps = [
+ "../../api/audio:audio_frame_api",
+ "../../common_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:deprecation",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers:field_trial",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("utility_tests") {
+ testonly = true
+ sources = [
+ "audio_frame_operations_unittest.cc",
+ "channel_mixer_unittest.cc",
+ "channel_mixing_matrix_unittest.cc",
+ ]
+ deps = [
+ ":audio_frame_operations",
+ "../../api/audio:audio_frame_api",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:field_trial",
+ "../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+}
diff --git a/webrtc/audio/utility/audio_frame_operations.cc b/webrtc/audio/utility/audio_frame_operations.cc
new file mode 100644
index 0000000..a9d2cf1
--- /dev/null
+++ b/webrtc/audio/utility/audio_frame_operations.cc
@@ -0,0 +1,294 @@
+/*
+ * 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 "audio/utility/audio_frame_operations.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <utility>
+
+#include "common_audio/include/audio_util.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace {
+
+// 2.7ms @ 48kHz, 4ms @ 32kHz, 8ms @ 16kHz.
+const size_t kMuteFadeFrames = 128;
+const float kMuteFadeInc = 1.0f / kMuteFadeFrames;
+
+} // namespace
+
+void AudioFrameOperations::Add(const AudioFrame& frame_to_add,
+ AudioFrame* result_frame) {
+ // Sanity check.
+ RTC_DCHECK(result_frame);
+ RTC_DCHECK_GT(result_frame->num_channels_, 0);
+ RTC_DCHECK_EQ(result_frame->num_channels_, frame_to_add.num_channels_);
+
+ bool no_previous_data = result_frame->muted();
+ if (result_frame->samples_per_channel_ != frame_to_add.samples_per_channel_) {
+ // Special case we have no data to start with.
+ RTC_DCHECK_EQ(result_frame->samples_per_channel_, 0);
+ result_frame->samples_per_channel_ = frame_to_add.samples_per_channel_;
+ no_previous_data = true;
+ }
+
+ if (result_frame->vad_activity_ == AudioFrame::kVadActive ||
+ frame_to_add.vad_activity_ == AudioFrame::kVadActive) {
+ result_frame->vad_activity_ = AudioFrame::kVadActive;
+ } else if (result_frame->vad_activity_ == AudioFrame::kVadUnknown ||
+ frame_to_add.vad_activity_ == AudioFrame::kVadUnknown) {
+ result_frame->vad_activity_ = AudioFrame::kVadUnknown;
+ }
+
+ if (result_frame->speech_type_ != frame_to_add.speech_type_)
+ result_frame->speech_type_ = AudioFrame::kUndefined;
+
+ if (!frame_to_add.muted()) {
+ const int16_t* in_data = frame_to_add.data();
+ int16_t* out_data = result_frame->mutable_data();
+ size_t length =
+ frame_to_add.samples_per_channel_ * frame_to_add.num_channels_;
+ if (no_previous_data) {
+ std::copy(in_data, in_data + length, out_data);
+ } else {
+ for (size_t i = 0; i < length; i++) {
+ const int32_t wrap_guard = static_cast<int32_t>(out_data[i]) +
+ static_cast<int32_t>(in_data[i]);
+ out_data[i] = rtc::saturated_cast<int16_t>(wrap_guard);
+ }
+ }
+ }
+}
+
+int AudioFrameOperations::MonoToStereo(AudioFrame* frame) {
+ if (frame->num_channels_ != 1) {
+ return -1;
+ }
+ UpmixChannels(2, frame);
+ return 0;
+}
+
+int AudioFrameOperations::StereoToMono(AudioFrame* frame) {
+ if (frame->num_channels_ != 2) {
+ return -1;
+ }
+ DownmixChannels(1, frame);
+ return frame->num_channels_ == 1 ? 0 : -1;
+}
+
+void AudioFrameOperations::QuadToStereo(const int16_t* src_audio,
+ size_t samples_per_channel,
+ int16_t* dst_audio) {
+ for (size_t i = 0; i < samples_per_channel; i++) {
+ dst_audio[i * 2] =
+ (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1]) >> 1;
+ dst_audio[i * 2 + 1] =
+ (static_cast<int32_t>(src_audio[4 * i + 2]) + src_audio[4 * i + 3]) >>
+ 1;
+ }
+}
+
+int AudioFrameOperations::QuadToStereo(AudioFrame* frame) {
+ if (frame->num_channels_ != 4) {
+ return -1;
+ }
+
+ RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
+ AudioFrame::kMaxDataSizeSamples);
+
+ if (!frame->muted()) {
+ QuadToStereo(frame->data(), frame->samples_per_channel_,
+ frame->mutable_data());
+ }
+ frame->num_channels_ = 2;
+
+ return 0;
+}
+
+void AudioFrameOperations::DownmixChannels(const int16_t* src_audio,
+ size_t src_channels,
+ size_t samples_per_channel,
+ size_t dst_channels,
+ int16_t* dst_audio) {
+ if (src_channels > 1 && dst_channels == 1) {
+ DownmixInterleavedToMono(src_audio, samples_per_channel, src_channels,
+ dst_audio);
+ return;
+ } else if (src_channels == 4 && dst_channels == 2) {
+ QuadToStereo(src_audio, samples_per_channel, dst_audio);
+ return;
+ }
+
+ RTC_NOTREACHED() << "src_channels: " << src_channels
+ << ", dst_channels: " << dst_channels;
+}
+
+void AudioFrameOperations::DownmixChannels(size_t dst_channels,
+ AudioFrame* frame) {
+ RTC_DCHECK_LE(frame->samples_per_channel_ * frame->num_channels_,
+ AudioFrame::kMaxDataSizeSamples);
+ if (frame->num_channels_ > 1 && dst_channels == 1) {
+ if (!frame->muted()) {
+ DownmixInterleavedToMono(frame->data(), frame->samples_per_channel_,
+ frame->num_channels_, frame->mutable_data());
+ }
+ frame->num_channels_ = 1;
+ } else if (frame->num_channels_ == 4 && dst_channels == 2) {
+ int err = QuadToStereo(frame);
+ RTC_DCHECK_EQ(err, 0);
+ } else {
+ RTC_NOTREACHED() << "src_channels: " << frame->num_channels_
+ << ", dst_channels: " << dst_channels;
+ }
+}
+
+void AudioFrameOperations::UpmixChannels(size_t target_number_of_channels,
+ AudioFrame* frame) {
+ RTC_DCHECK_EQ(frame->num_channels_, 1);
+ RTC_DCHECK_LE(frame->samples_per_channel_ * target_number_of_channels,
+ AudioFrame::kMaxDataSizeSamples);
+
+ if (frame->num_channels_ != 1 ||
+ frame->samples_per_channel_ * target_number_of_channels >
+ AudioFrame::kMaxDataSizeSamples) {
+ return;
+ }
+
+ if (!frame->muted()) {
+ // Up-mixing done in place. Going backwards through the frame ensure nothing
+ // is irrevocably overwritten.
+ for (int i = frame->samples_per_channel_ - 1; i >= 0; i--) {
+ for (size_t j = 0; j < target_number_of_channels; ++j) {
+ frame->mutable_data()[target_number_of_channels * i + j] =
+ frame->data()[i];
+ }
+ }
+ }
+ frame->num_channels_ = target_number_of_channels;
+}
+
+void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
+ RTC_DCHECK(frame);
+ if (frame->num_channels_ != 2 || frame->muted()) {
+ return;
+ }
+
+ int16_t* frame_data = frame->mutable_data();
+ for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
+ std::swap(frame_data[i], frame_data[i + 1]);
+ }
+}
+
+void AudioFrameOperations::Mute(AudioFrame* frame,
+ bool previous_frame_muted,
+ bool current_frame_muted) {
+ RTC_DCHECK(frame);
+ if (!previous_frame_muted && !current_frame_muted) {
+ // Not muted, don't touch.
+ } else if (previous_frame_muted && current_frame_muted) {
+ // Frame fully muted.
+ size_t total_samples = frame->samples_per_channel_ * frame->num_channels_;
+ RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples, total_samples);
+ frame->Mute();
+ } else {
+ // Fade is a no-op on a muted frame.
+ if (frame->muted()) {
+ return;
+ }
+
+ // Limit number of samples to fade, if frame isn't long enough.
+ size_t count = kMuteFadeFrames;
+ float inc = kMuteFadeInc;
+ if (frame->samples_per_channel_ < kMuteFadeFrames) {
+ count = frame->samples_per_channel_;
+ if (count > 0) {
+ inc = 1.0f / count;
+ }
+ }
+
+ size_t start = 0;
+ size_t end = count;
+ float start_g = 0.0f;
+ if (current_frame_muted) {
+ // Fade out the last |count| samples of frame.
+ RTC_DCHECK(!previous_frame_muted);
+ start = frame->samples_per_channel_ - count;
+ end = frame->samples_per_channel_;
+ start_g = 1.0f;
+ inc = -inc;
+ } else {
+ // Fade in the first |count| samples of frame.
+ RTC_DCHECK(previous_frame_muted);
+ }
+
+ // Perform fade.
+ int16_t* frame_data = frame->mutable_data();
+ size_t channels = frame->num_channels_;
+ for (size_t j = 0; j < channels; ++j) {
+ float g = start_g;
+ for (size_t i = start * channels; i < end * channels; i += channels) {
+ g += inc;
+ frame_data[i + j] *= g;
+ }
+ }
+ }
+}
+
+void AudioFrameOperations::Mute(AudioFrame* frame) {
+ Mute(frame, true, true);
+}
+
+void AudioFrameOperations::ApplyHalfGain(AudioFrame* frame) {
+ RTC_DCHECK(frame);
+ RTC_DCHECK_GT(frame->num_channels_, 0);
+ if (frame->num_channels_ < 1 || frame->muted()) {
+ return;
+ }
+
+ int16_t* frame_data = frame->mutable_data();
+ for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
+ i++) {
+ frame_data[i] = frame_data[i] >> 1;
+ }
+}
+
+int AudioFrameOperations::Scale(float left, float right, AudioFrame* frame) {
+ if (frame->num_channels_ != 2) {
+ return -1;
+ } else if (frame->muted()) {
+ return 0;
+ }
+
+ int16_t* frame_data = frame->mutable_data();
+ for (size_t i = 0; i < frame->samples_per_channel_; i++) {
+ frame_data[2 * i] = static_cast<int16_t>(left * frame_data[2 * i]);
+ frame_data[2 * i + 1] = static_cast<int16_t>(right * frame_data[2 * i + 1]);
+ }
+ return 0;
+}
+
+int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) {
+ if (frame->muted()) {
+ return 0;
+ }
+
+ int16_t* frame_data = frame->mutable_data();
+ for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
+ i++) {
+ frame_data[i] = rtc::saturated_cast<int16_t>(scale * frame_data[i]);
+ }
+ return 0;
+}
+} // namespace webrtc
diff --git a/webrtc/audio/utility/audio_frame_operations.h b/webrtc/audio/utility/audio_frame_operations.h
new file mode 100644
index 0000000..65c310c
--- /dev/null
+++ b/webrtc/audio/utility/audio_frame_operations.h
@@ -0,0 +1,105 @@
+/*
+ * 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 AUDIO_UTILITY_AUDIO_FRAME_OPERATIONS_H_
+#define AUDIO_UTILITY_AUDIO_FRAME_OPERATIONS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "api/audio/audio_frame.h"
+#include "rtc_base/deprecation.h"
+
+namespace webrtc {
+
+// TODO(andrew): consolidate this with utility.h and audio_frame_manipulator.h.
+// Change reference parameters to pointers. Consider using a namespace rather
+// than a class.
+class AudioFrameOperations {
+ public:
+ // Add samples in |frame_to_add| with samples in |result_frame|
+ // putting the results in |results_frame|. The fields
+ // |vad_activity_| and |speech_type_| of the result frame are
+ // updated. If |result_frame| is empty (|samples_per_channel_|==0),
+ // the samples in |frame_to_add| are added to it. The number of
+ // channels and number of samples per channel must match except when
+ // |result_frame| is empty.
+ static void Add(const AudioFrame& frame_to_add, AudioFrame* result_frame);
+
+ // |frame.num_channels_| will be updated. This version checks for sufficient
+ // buffer size and that |num_channels_| is mono. Use UpmixChannels
+ // instead. TODO(bugs.webrtc.org/8649): remove.
+ RTC_DEPRECATED static int MonoToStereo(AudioFrame* frame);
+
+ // |frame.num_channels_| will be updated. This version checks that
+ // |num_channels_| is stereo. Use DownmixChannels
+ // instead. TODO(bugs.webrtc.org/8649): remove.
+ RTC_DEPRECATED static int StereoToMono(AudioFrame* frame);
+
+ // Downmixes 4 channels |src_audio| to stereo |dst_audio|. This is an in-place
+ // operation, meaning |src_audio| and |dst_audio| may point to the same
+ // buffer.
+ static void QuadToStereo(const int16_t* src_audio,
+ size_t samples_per_channel,
+ int16_t* dst_audio);
+
+ // |frame.num_channels_| will be updated. This version checks that
+ // |num_channels_| is 4 channels.
+ static int QuadToStereo(AudioFrame* frame);
+
+ // Downmixes |src_channels| |src_audio| to |dst_channels| |dst_audio|.
+ // This is an in-place operation, meaning |src_audio| and |dst_audio|
+ // may point to the same buffer. Supported channel combinations are
+ // Stereo to Mono, Quad to Mono, and Quad to Stereo.
+ static void DownmixChannels(const int16_t* src_audio,
+ size_t src_channels,
+ size_t samples_per_channel,
+ size_t dst_channels,
+ int16_t* dst_audio);
+
+ // |frame.num_channels_| will be updated. This version checks that
+ // |num_channels_| and |dst_channels| are valid and performs relevant downmix.
+ // Supported channel combinations are N channels to Mono, and Quad to Stereo.
+ static void DownmixChannels(size_t dst_channels, AudioFrame* frame);
+
+ // |frame.num_channels_| will be updated. This version checks that
+ // |num_channels_| and |dst_channels| are valid and performs relevant
+ // downmix. Supported channel combinations are Mono to N
+ // channels. The single channel is replicated.
+ static void UpmixChannels(size_t target_number_of_channels,
+ AudioFrame* frame);
+
+ // Swap the left and right channels of |frame|. Fails silently if |frame| is
+ // not stereo.
+ static void SwapStereoChannels(AudioFrame* frame);
+
+ // Conditionally zero out contents of |frame| for implementing audio mute:
+ // |previous_frame_muted| && |current_frame_muted| - Zero out whole frame.
+ // |previous_frame_muted| && !|current_frame_muted| - Fade-in at frame start.
+ // !|previous_frame_muted| && |current_frame_muted| - Fade-out at frame end.
+ // !|previous_frame_muted| && !|current_frame_muted| - Leave frame untouched.
+ static void Mute(AudioFrame* frame,
+ bool previous_frame_muted,
+ bool current_frame_muted);
+
+ // Zero out contents of frame.
+ static void Mute(AudioFrame* frame);
+
+ // Halve samples in |frame|.
+ static void ApplyHalfGain(AudioFrame* frame);
+
+ static int Scale(float left, float right, AudioFrame* frame);
+
+ static int ScaleWithSat(float scale, AudioFrame* frame);
+};
+
+} // namespace webrtc
+
+#endif // AUDIO_UTILITY_AUDIO_FRAME_OPERATIONS_H_
diff --git a/webrtc/base/BUILD.gn b/webrtc/base/BUILD.gn
deleted file mode 100644
index 11a2664..0000000
--- a/webrtc/base/BUILD.gn
+++ /dev/null
@@ -1,596 +0,0 @@
-# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
-#
-# Use of this source code is governed by a BSD-style license
-# that can be found in the LICENSE file in the root of the source
-# tree. An additional intellectual property rights grant can be found
-# in the file PATENTS. All contributing project authors may
-# be found in the AUTHORS file in the root of the source tree.
-
-import("//build/config/crypto.gni")
-import("//build/config/ui.gni")
-import("../build/webrtc.gni")
-
-config("rtc_base_config") {
- include_dirs = [
- "//third_party/jsoncpp/overrides/include",
- "//third_party/jsoncpp/source/include",
- ]
-
- defines = [
- "FEATURE_ENABLE_SSL",
- "LOGGING=1",
- ]
-
- if (is_posix) {
- # TODO(henrike): issue 3307, make rtc_base build without disabling
- # these flags.
- cflags_cc = [ "-Wno-non-virtual-dtor" ]
- }
-}
-
-config("rtc_base_chromium_config") {
- defines = [ "NO_MAIN_THREAD_WRAPPING" ]
-}
-
-config("openssl_config") {
- defines = [
- "SSL_USE_OPENSSL",
- "HAVE_OPENSSL_SSL_H",
- ]
-}
-
-config("ios_config") {
- libs = [
- "CFNetwork.framework",
-
- #"Foundation.framework", # Already included in //build/config:default_libs.
- "Security.framework",
- "SystemConfiguration.framework",
-
- #"UIKit.framework", # Already included in //build/config:default_libs.
- ]
-}
-
-config("mac_config") {
- libs = [
- "Cocoa.framework",
-
- #"Foundation.framework", # Already included in //build/config:default_libs.
- #"IOKit.framework", # Already included in //build/config:default_libs.
- #"Security.framework", # Already included in //build/config:default_libs.
- "SystemConfiguration.framework",
- ]
-}
-
-config("mac_x86_config") {
- libs = [
- #"Carbon.framework", # Already included in //build/config:default_libs.
- ]
-}
-
-if (is_linux && !build_with_chromium) {
- # Provides the same functionality as the //crypto:platform target, which
- # WebRTC cannot use as we don't sync src/crypto from Chromium.
- group("linux_system_ssl") {
- if (use_openssl) {
- deps = [
- "//third_party/boringssl",
- ]
- }
- }
-}
-
-if (rtc_build_ssl == 0) {
- config("external_ssl_library") {
- assert(rtc_ssl_root != "",
- "You must specify rtc_ssl_root when rtc_build_ssl==0.")
- include_dirs = [ rtc_ssl_root ]
- }
-}
-
-# The subset of rtc_base approved for use outside of libjingle.
-static_library("rtc_base_approved") {
- configs += [ "..:common_config" ]
- public_configs = [ "..:common_inherited_config" ]
-
- sources = [
- "array_view.h",
- "atomicops.h",
- "bitbuffer.cc",
- "bitbuffer.h",
- "buffer.cc",
- "buffer.h",
- "bufferqueue.cc",
- "bufferqueue.h",
- "bytebuffer.cc",
- "bytebuffer.h",
- "byteorder.h",
- "checks.cc",
- "checks.h",
- "criticalsection.cc",
- "criticalsection.h",
- "event.cc",
- "event.h",
- "event_tracer.cc",
- "event_tracer.h",
- "exp_filter.cc",
- "exp_filter.h",
- "maybe.h",
- "md5.cc",
- "md5.h",
- "md5digest.cc",
- "md5digest.h",
- "platform_file.cc",
- "platform_file.h",
- "platform_thread.cc",
- "platform_thread.h",
- "safe_conversions.h",
- "safe_conversions_impl.h",
- "scoped_ptr.h",
- "stringencode.cc",
- "stringencode.h",
- "stringutils.cc",
- "stringutils.h",
- "systeminfo.cc",
- "systeminfo.h",
- "template_util.h",
- "thread_annotations.h",
- "thread_checker.h",
- "thread_checker_impl.cc",
- "thread_checker_impl.h",
- "timeutils.cc",
- "timeutils.h",
- "trace_event.h",
- ]
-
- if (!build_with_chromium) {
- sources += [
- "basictypes.h",
- "constructormagic.h",
- "logging.cc",
- "logging.h",
- ]
- }
-}
-
-static_library("rtc_base") {
- cflags = []
- cflags_cc = []
- libs = []
- deps = [
- ":rtc_base_approved",
- ]
-
- configs += [
- "..:common_config",
- ":rtc_base_config",
- ]
-
- public_configs = [
- "..:common_inherited_config",
- ":rtc_base_config",
- ]
-
- defines = [ "LOGGING=1" ]
-
- sources = [
- "arraysize.h",
- "asyncfile.cc",
- "asyncfile.h",
- "asyncinvoker-inl.h",
- "asyncinvoker.cc",
- "asyncinvoker.h",
- "asyncpacketsocket.cc",
- "asyncpacketsocket.h",
- "asyncresolverinterface.cc",
- "asyncresolverinterface.h",
- "asyncsocket.cc",
- "asyncsocket.h",
- "asynctcpsocket.cc",
- "asynctcpsocket.h",
- "asyncudpsocket.cc",
- "asyncudpsocket.h",
- "autodetectproxy.cc",
- "autodetectproxy.h",
- "base64.cc",
- "base64.h",
- "basicdefs.h",
- "common.cc",
- "common.h",
- "crc32.cc",
- "crc32.h",
- "cryptstring.cc",
- "cryptstring.h",
- "diskcache.cc",
- "diskcache.h",
- "filerotatingstream.cc",
- "filerotatingstream.h",
- "fileutils.cc",
- "fileutils.h",
- "firewallsocketserver.cc",
- "firewallsocketserver.h",
- "flags.cc",
- "flags.h",
- "format_macros.h",
- "gunit_prod.h",
- "helpers.cc",
- "helpers.h",
- "httpbase.cc",
- "httpbase.h",
- "httpclient.cc",
- "httpclient.h",
- "httpcommon-inl.h",
- "httpcommon.cc",
- "httpcommon.h",
- "httprequest.cc",
- "httprequest.h",
- "iosfilesystem.mm",
- "ipaddress.cc",
- "ipaddress.h",
- "linked_ptr.h",
- "mathutils.h",
- "messagedigest.cc",
- "messagedigest.h",
- "messagehandler.cc",
- "messagehandler.h",
- "messagequeue.cc",
- "messagequeue.h",
- "nethelpers.cc",
- "nethelpers.h",
- "network.cc",
- "network.h",
- "networkmonitor.cc",
- "networkmonitor.h",
- "nullsocketserver.h",
- "pathutils.cc",
- "pathutils.h",
- "physicalsocketserver.cc",
- "physicalsocketserver.h",
- "proxydetect.cc",
- "proxydetect.h",
- "proxyinfo.cc",
- "proxyinfo.h",
- "ratelimiter.cc",
- "ratelimiter.h",
- "ratetracker.cc",
- "ratetracker.h",
- "rtccertificate.cc",
- "rtccertificate.h",
- "scoped_autorelease_pool.h",
- "scoped_autorelease_pool.mm",
- "sha1.cc",
- "sha1.h",
- "sha1digest.cc",
- "sha1digest.h",
- "signalthread.cc",
- "signalthread.h",
- "sigslot.cc",
- "sigslot.h",
- "sigslotrepeater.h",
- "socket.h",
- "socketadapters.cc",
- "socketadapters.h",
- "socketaddress.cc",
- "socketaddress.h",
- "socketaddresspair.cc",
- "socketaddresspair.h",
- "socketfactory.h",
- "socketpool.cc",
- "socketpool.h",
- "socketserver.h",
- "socketstream.cc",
- "socketstream.h",
- "ssladapter.cc",
- "ssladapter.h",
- "sslfingerprint.cc",
- "sslfingerprint.h",
- "sslidentity.cc",
- "sslidentity.h",
- "sslsocketfactory.cc",
- "sslsocketfactory.h",
- "sslstreamadapter.cc",
- "sslstreamadapter.h",
- "sslstreamadapterhelper.cc",
- "sslstreamadapterhelper.h",
- "stream.cc",
- "stream.h",
- "task.cc",
- "task.h",
- "taskparent.cc",
- "taskparent.h",
- "taskrunner.cc",
- "taskrunner.h",
- "thread.cc",
- "thread.h",
- "timing.cc",
- "timing.h",
- "urlencode.cc",
- "urlencode.h",
- "worker.cc",
- "worker.h",
- ]
-
- if (is_posix) {
- sources += [
- "unixfilesystem.cc",
- "unixfilesystem.h",
- ]
- }
-
- if (build_with_chromium) {
- sources += [
- "../../webrtc_overrides/webrtc/base/logging.cc",
- "../../webrtc_overrides/webrtc/base/logging.h",
- ]
-
- deps += [ "..:webrtc_common" ]
-
- if (is_win) {
- sources += [ "../../webrtc_overrides/webrtc/base/win32socketinit.cc" ]
- }
-
- include_dirs = [
- "../../webrtc_overrides",
- "../../boringssl/src/include",
- ]
-
- public_configs += [ ":rtc_base_chromium_config" ]
- } else {
- sources += [
- "bandwidthsmoother.cc",
- "bandwidthsmoother.h",
- "bind.h",
- "bind.h.pump",
- "callback.h",
- "callback.h.pump",
- "fileutils_mock.h",
- "genericslot.h",
- "genericslot.h.pump",
- "httpserver.cc",
- "httpserver.h",
- "json.cc",
- "json.h",
- "logsinks.cc",
- "logsinks.h",
- "mathutils.h",
- "multipart.cc",
- "multipart.h",
- "natserver.cc",
- "natserver.h",
- "natsocketfactory.cc",
- "natsocketfactory.h",
- "nattypes.cc",
- "nattypes.h",
- "optionsfile.cc",
- "optionsfile.h",
- "profiler.cc",
- "profiler.h",
- "proxyserver.cc",
- "proxyserver.h",
- "refcount.h",
- "referencecountedsingletonfactory.h",
- "rollingaccumulator.h",
- "scoped_ref_ptr.h",
- "scopedptrcollection.h",
- "sec_buffer.h",
- "sharedexclusivelock.cc",
- "sharedexclusivelock.h",
- "sslconfig.h",
- "sslroots.h",
- "testclient.cc",
- "testclient.h",
- "transformadapter.cc",
- "transformadapter.h",
- "versionparsing.cc",
- "versionparsing.h",
- "virtualsocketserver.cc",
- "virtualsocketserver.h",
- "window.h",
- "windowpicker.h",
- "windowpickerfactory.h",
- ]
-
- deps += [ "..:webrtc_common" ]
-
- if (is_posix) {
- sources += [
- "latebindingsymboltable.cc",
- "latebindingsymboltable.cc.def",
- "latebindingsymboltable.h",
- "latebindingsymboltable.h.def",
- "posix.cc",
- "posix.h",
- ]
- }
-
- if (is_linux) {
- sources += [
- "dbus.cc",
- "dbus.h",
- "libdbusglibsymboltable.cc",
- "libdbusglibsymboltable.h",
- "linuxfdwalk.c",
- "linuxfdwalk.h",
- ]
- }
-
- if (is_mac) {
- sources += [
- "macasyncsocket.cc",
- "macasyncsocket.h",
- "maccocoasocketserver.h",
- "maccocoasocketserver.mm",
- "macsocketserver.cc",
- "macsocketserver.h",
- "macwindowpicker.cc",
- "macwindowpicker.h",
- ]
- }
-
- if (is_win) {
- sources += [
- "diskcache_win32.cc",
- "diskcache_win32.h",
- "win32regkey.cc",
- "win32regkey.h",
- "win32socketinit.cc",
- "win32socketinit.h",
- "win32socketserver.cc",
- "win32socketserver.h",
- ]
- }
- if (rtc_build_json) {
- deps += [ "//third_party/jsoncpp" ]
- } else {
- include_dirs += [ rtc_jsoncpp_root ]
-
- # When defined changes the include path for json.h to where it is
- # expected to be when building json outside of the standalone build.
- defines += [ "WEBRTC_EXTERNAL_JSON" ]
- }
- } # !build_with_chromium
-
- # TODO(henrike): issue 3307, make rtc_base build with the Chromium default
- # compiler settings.
- configs -= [ "//build/config/compiler:chromium_code" ]
- configs += [ "//build/config/compiler:no_chromium_code" ]
- if (!is_win) {
- cflags += [ "-Wno-uninitialized" ]
- cflags_cc += [ "-Wno-non-virtual-dtor" ]
- }
-
- if (use_openssl) {
- public_configs += [ ":openssl_config" ]
- if (rtc_build_ssl) {
- deps += [ "//third_party/boringssl" ]
- } else {
- configs += [ "external_ssl_library" ]
- }
- sources += [
- "openssl.h",
- "openssladapter.cc",
- "openssladapter.h",
- "openssldigest.cc",
- "openssldigest.h",
- "opensslidentity.cc",
- "opensslidentity.h",
- "opensslstreamadapter.cc",
- "opensslstreamadapter.h",
- ]
- }
-
- if (is_android) {
- sources += [
- "ifaddrs-android.cc",
- "ifaddrs-android.h",
- ]
-
- libs += [
- "log",
- "GLESv2",
- ]
- }
-
- if (is_ios) {
- all_dependent_configs = [ ":ios_config" ]
-
- sources += [
- "macconversion.cc",
- "macconversion.h",
- ]
- }
-
- if (use_x11) {
- sources += [
- "x11windowpicker.cc",
- "x11windowpicker.h",
- ]
- libs += [
- "dl",
- "rt",
- "Xext",
- "X11",
- "Xcomposite",
- "Xrender",
- ]
- }
-
- if (is_linux) {
- libs += [
- "dl",
- "rt",
- ]
- }
-
- if (is_mac) {
- sources += [
- "maccocoathreadhelper.h",
- "maccocoathreadhelper.mm",
- "macconversion.cc",
- "macconversion.h",
- "macutils.cc",
- "macutils.h",
- ]
-
- all_dependent_configs = [ ":mac_config" ]
-
- if (current_cpu == "x86") {
- all_dependent_configs += [ ":mac_x86_config" ]
- }
- }
-
- if (is_win) {
- sources += [
- "win32.cc",
- "win32.h",
- "win32filesystem.cc",
- "win32filesystem.h",
- "win32securityerrors.cc",
- "win32window.cc",
- "win32window.h",
- "win32windowpicker.cc",
- "win32windowpicker.h",
- "winfirewall.cc",
- "winfirewall.h",
- "winping.cc",
- "winping.h",
- ]
-
- libs += [
- "crypt32.lib",
- "iphlpapi.lib",
- "secur32.lib",
- ]
-
- cflags += [
- # Suppress warnings about WIN32_LEAN_AND_MEAN.
- "/wd4005",
- "/wd4703",
- ]
-
- defines += [ "_CRT_NONSTDC_NO_DEPRECATE" ]
- }
-
- if (is_posix && is_debug) {
- # The Chromium build/common.gypi defines this for all posix
- # _except_ for ios & mac. We want it there as well, e.g.
- # because ASSERT and friends trigger off of it.
- defines += [ "_DEBUG" ]
- }
-
- if (is_ios || (is_mac && current_cpu != "x86")) {
- defines += [ "CARBON_DEPRECATED=YES" ]
- }
-
- if (is_linux || is_android) {
- sources += [
- "linux.cc",
- "linux.h",
- ]
- }
-
- if (is_nacl) {
- deps += [ "//native_client_sdk/src/libraries/nacl_io" ]
- defines += [ "timezone=_timezone" ]
- }
-}
diff --git a/webrtc/base/basictypes.h b/webrtc/base/basictypes.h
deleted file mode 100644
index 4c3d5d1..0000000
--- a/webrtc/base/basictypes.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_BASE_BASICTYPES_H_
-#define WEBRTC_BASE_BASICTYPES_H_
-
-#include <stddef.h> // for NULL, size_t
-#include <stdint.h> // for uintptr_t and (u)int_t types.
-
-#ifdef HAVE_CONFIG_H
-#include "config.h" // NOLINT
-#endif
-
-// Detect compiler is for x86 or x64.
-#if defined(__x86_64__) || defined(_M_X64) || \
- defined(__i386__) || defined(_M_IX86)
-#define CPU_X86 1
-#endif
-
-// Detect compiler is for arm.
-#if defined(__arm__) || defined(_M_ARM)
-#define CPU_ARM 1
-#endif
-
-#if defined(CPU_X86) && defined(CPU_ARM)
-#error CPU_X86 and CPU_ARM both defined.
-#endif
-
-#if !defined(RTC_ARCH_CPU_BIG_ENDIAN) && !defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
-// x86, arm or GCC provided __BYTE_ORDER__ macros
-#if CPU_X86 || CPU_ARM || \
- (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-#define RTC_ARCH_CPU_LITTLE_ENDIAN
-#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#define RTC_ARCH_CPU_BIG_ENDIAN
-#else
-#error RTC_ARCH_CPU_BIG_ENDIAN or RTC_ARCH_CPU_LITTLE_ENDIAN should be defined.
-#endif
-#endif
-
-#if defined(RTC_ARCH_CPU_BIG_ENDIAN) && defined(RTC_ARCH_CPU_LITTLE_ENDIAN)
-#error RTC_ARCH_CPU_BIG_ENDIAN and RTC_ARCH_CPU_LITTLE_ENDIAN both defined.
-#endif
-
-#if defined(WEBRTC_WIN)
-typedef int socklen_t;
-#endif
-
-// The following only works for C++
-#ifdef __cplusplus
-
-#ifndef ALIGNP
-#define ALIGNP(p, t) \
- (reinterpret_cast<uint8_t*>(((reinterpret_cast<uintptr_t>(p) + \
- ((t) - 1)) & ~((t) - 1))))
-#endif
-
-#define RTC_IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1)))
-
-// Use these to declare and define a static local variable that gets leaked so
-// that its destructors are not called at exit.
-#define RTC_DEFINE_STATIC_LOCAL(type, name, arguments) \
- static type& name = *new type arguments
-
-#endif // __cplusplus
-
-#endif // WEBRTC_BASE_BASICTYPES_H_
diff --git a/webrtc/base/checks.cc b/webrtc/base/checks.cc
deleted file mode 100644
index 49a31f2..0000000
--- a/webrtc/base/checks.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2006 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Most of this was borrowed (with minor modifications) from V8's and Chromium's
-// src/base/logging.cc.
-
-// Use the C++ version to provide __GLIBCXX__.
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-
-#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
-#include <cxxabi.h>
-#include <execinfo.h>
-#endif
-
-#if defined(WEBRTC_ANDROID)
-#define LOG_TAG "rtc"
-#include <android/log.h> // NOLINT
-#endif
-
-#include "webrtc/base/checks.h"
-
-#if defined(_MSC_VER)
-// Warning C4722: destructor never returns, potential memory leak.
-// FatalMessage's dtor very intentionally aborts.
-#pragma warning(disable:4722)
-#endif
-
-namespace rtc {
-
-void VPrintError(const char* format, va_list args) {
-#if defined(WEBRTC_ANDROID)
- __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
-#else
- vfprintf(stderr, format, args);
-#endif
-}
-
-void PrintError(const char* format, ...) {
- va_list args;
- va_start(args, format);
- VPrintError(format, args);
- va_end(args);
-}
-
-// TODO(ajm): This works on Mac (although the parsing fails) but I don't seem
-// to get usable symbols on Linux. This is copied from V8. Chromium has a more
-// advanced stace trace system; also more difficult to copy.
-void DumpBacktrace() {
-#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
- void* trace[100];
- int size = backtrace(trace, sizeof(trace) / sizeof(*trace));
- char** symbols = backtrace_symbols(trace, size);
- PrintError("\n==== C stack trace ===============================\n\n");
- if (size == 0) {
- PrintError("(empty)\n");
- } else if (symbols == NULL) {
- PrintError("(no symbols)\n");
- } else {
- for (int i = 1; i < size; ++i) {
- char mangled[201];
- if (sscanf(symbols[i], "%*[^(]%*[(]%200[^)+]", mangled) == 1) { // NOLINT
- PrintError("%2d: ", i);
- int status;
- size_t length;
- char* demangled = abi::__cxa_demangle(mangled, NULL, &length, &status);
- PrintError("%s\n", demangled != NULL ? demangled : mangled);
- free(demangled);
- } else {
- // If parsing failed, at least print the unparsed symbol.
- PrintError("%s\n", symbols[i]);
- }
- }
- }
- free(symbols);
-#endif
-}
-
-FatalMessage::FatalMessage(const char* file, int line) {
- Init(file, line);
-}
-
-FatalMessage::FatalMessage(const char* file, int line, std::string* result) {
- Init(file, line);
- stream_ << "Check failed: " << *result << std::endl << "# ";
- delete result;
-}
-
-NO_RETURN FatalMessage::~FatalMessage() {
- fflush(stdout);
- fflush(stderr);
- stream_ << std::endl << "#" << std::endl;
- PrintError(stream_.str().c_str());
- DumpBacktrace();
- fflush(stderr);
- abort();
-}
-
-void FatalMessage::Init(const char* file, int line) {
- stream_ << std::endl << std::endl << "#" << std::endl << "# Fatal error in "
- << file << ", line " << line << std::endl << "# ";
-}
-
-// MSVC doesn't like complex extern templates and DLLs.
-#if !defined(COMPILER_MSVC)
-// Explicit instantiations for commonly used comparisons.
-template std::string* MakeCheckOpString<int, int>(
- const int&, const int&, const char* names);
-template std::string* MakeCheckOpString<unsigned long, unsigned long>(
- const unsigned long&, const unsigned long&, const char* names);
-template std::string* MakeCheckOpString<unsigned long, unsigned int>(
- const unsigned long&, const unsigned int&, const char* names);
-template std::string* MakeCheckOpString<unsigned int, unsigned long>(
- const unsigned int&, const unsigned long&, const char* names);
-template std::string* MakeCheckOpString<std::string, std::string>(
- const std::string&, const std::string&, const char* name);
-#endif
-
-} // namespace rtc
diff --git a/webrtc/base/checks.h b/webrtc/base/checks.h
deleted file mode 100644
index 681361a..0000000
--- a/webrtc/base/checks.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright 2006 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can 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 WEBRTC_BASE_CHECKS_H_
-#define WEBRTC_BASE_CHECKS_H_
-
-#include <sstream>
-#include <string>
-
-#include "webrtc/typedefs.h"
-
-// The macros here print a message to stderr and abort under various
-// conditions. All will accept additional stream messages. For example:
-// RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar.";
-//
-// - RTC_CHECK(x) is an assertion that x is always true, and that if it isn't,
-// it's better to terminate the process than to continue. During development,
-// the reason that it's better to terminate might simply be that the error
-// handling code isn't in place yet; in production, the reason might be that
-// the author of the code truly believes that x will always be true, but that
-// she recognizes that if she is wrong, abrupt and unpleasant process
-// termination is still better than carrying on with the assumption violated.
-//
-// RTC_CHECK always evaluates its argument, so it's OK for x to have side
-// effects.
-//
-// - RTC_DCHECK(x) is the same as RTC_CHECK(x)---an assertion that x is always
-// true---except that x will only be evaluated in debug builds; in production
-// builds, x is simply assumed to be true. This is useful if evaluating x is
-// expensive and the expected cost of failing to detect the violated
-// assumption is acceptable. You should not handle cases where a production
-// build fails to spot a violated condition, even those that would result in
-// crashes. If the code needs to cope with the error, make it cope, but don't
-// call RTC_DCHECK; if the condition really can't occur, but you'd sleep
-// better at night knowing that the process will suicide instead of carrying
-// on in case you were wrong, use RTC_CHECK instead of RTC_DCHECK.
-//
-// RTC_DCHECK only evaluates its argument in debug builds, so if x has visible
-// side effects, you need to write e.g.
-// bool w = x; RTC_DCHECK(w);
-//
-// - RTC_CHECK_EQ, _NE, _GT, ..., and RTC_DCHECK_EQ, _NE, _GT, ... are
-// specialized variants of RTC_CHECK and RTC_DCHECK that print prettier
-// messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and
-// RTC_DCHECK.
-//
-// - FATAL() aborts unconditionally.
-//
-// TODO(ajm): Ideally, checks.h would be combined with logging.h, but
-// consolidation with system_wrappers/logging.h should happen first.
-
-namespace rtc {
-
-// Helper macro which avoids evaluating the arguments to a stream if
-// the condition doesn't hold.
-#define RTC_LAZY_STREAM(stream, condition) \
- !(condition) ? static_cast<void>(0) : rtc::FatalMessageVoidify() & (stream)
-
-// The actual stream used isn't important. We reference condition in the code
-// but don't evaluate it; this is to avoid "unused variable" warnings (we do so
-// in a particularly convoluted way with an extra ?: because that appears to be
-// the simplest construct that keeps Visual Studio from complaining about
-// condition being unused).
-#define RTC_EAT_STREAM_PARAMETERS(condition) \
- (true ? true : !(condition)) \
- ? static_cast<void>(0) \
- : rtc::FatalMessageVoidify() & rtc::FatalMessage("", 0).stream()
-
-// RTC_CHECK dies with a fatal error if condition is not true. It is *not*
-// controlled by NDEBUG, so the check will be executed regardless of
-// compilation mode.
-//
-// We make sure RTC_CHECK et al. always evaluates their arguments, as
-// doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom.
-#define RTC_CHECK(condition) \
- RTC_LAZY_STREAM(rtc::FatalMessage(__FILE__, __LINE__).stream(), \
- !(condition)) \
- << "Check failed: " #condition << std::endl << "# "
-
-// Helper macro for binary operators.
-// Don't use this macro directly in your code, use RTC_CHECK_EQ et al below.
-//
-// TODO(akalin): Rewrite this so that constructs like if (...)
-// RTC_CHECK_EQ(...) else { ... } work properly.
-#define RTC_CHECK_OP(name, op, val1, val2) \
- if (std::string* _result = \
- rtc::Check##name##Impl((val1), (val2), #val1 " " #op " " #val2)) \
- rtc::FatalMessage(__FILE__, __LINE__, _result).stream()
-
-// Build the error message string. This is separate from the "Impl"
-// function template because it is not performance critical and so can
-// be out of line, while the "Impl" code should be inline. Caller
-// takes ownership of the returned string.
-template<class t1, class t2>
-std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
- std::ostringstream ss;
- ss << names << " (" << v1 << " vs. " << v2 << ")";
- std::string* msg = new std::string(ss.str());
- return msg;
-}
-
-// MSVC doesn't like complex extern templates and DLLs.
-#if !defined(COMPILER_MSVC)
-// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
-// in logging.cc.
-extern template std::string* MakeCheckOpString<int, int>(
- const int&, const int&, const char* names);
-extern template
-std::string* MakeCheckOpString<unsigned long, unsigned long>(
- const unsigned long&, const unsigned long&, const char* names);
-extern template
-std::string* MakeCheckOpString<unsigned long, unsigned int>(
- const unsigned long&, const unsigned int&, const char* names);
-extern template
-std::string* MakeCheckOpString<unsigned int, unsigned long>(
- const unsigned int&, const unsigned long&, const char* names);
-extern template
-std::string* MakeCheckOpString<std::string, std::string>(
- const std::string&, const std::string&, const char* name);
-#endif
-
-// Helper functions for RTC_CHECK_OP macro.
-// The (int, int) specialization works around the issue that the compiler
-// will not instantiate the template version of the function on values of
-// unnamed enum type - see comment below.
-#define DEFINE_RTC_CHECK_OP_IMPL(name, op) \
- template <class t1, class t2> \
- inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
- const char* names) { \
- if (v1 op v2) \
- return NULL; \
- else \
- return rtc::MakeCheckOpString(v1, v2, names); \
- } \
- inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
- if (v1 op v2) \
- return NULL; \
- else \
- return rtc::MakeCheckOpString(v1, v2, names); \
- }
-DEFINE_RTC_CHECK_OP_IMPL(EQ, ==)
-DEFINE_RTC_CHECK_OP_IMPL(NE, !=)
-DEFINE_RTC_CHECK_OP_IMPL(LE, <=)
-DEFINE_RTC_CHECK_OP_IMPL(LT, < )
-DEFINE_RTC_CHECK_OP_IMPL(GE, >=)
-DEFINE_RTC_CHECK_OP_IMPL(GT, > )
-#undef DEFINE_RTC_CHECK_OP_IMPL
-
-#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(EQ, ==, val1, val2)
-#define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(NE, !=, val1, val2)
-#define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(LE, <=, val1, val2)
-#define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(LT, < , val1, val2)
-#define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(GE, >=, val1, val2)
-#define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(GT, > , val1, val2)
-
-// The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates
-// code in debug builds. It does reference the condition parameter in all cases,
-// though, so callers won't risk getting warnings about unused variables.
-#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
-#define RTC_DCHECK_IS_ON 1
-#define RTC_DCHECK(condition) RTC_CHECK(condition)
-#define RTC_DCHECK_EQ(v1, v2) RTC_CHECK_EQ(v1, v2)
-#define RTC_DCHECK_NE(v1, v2) RTC_CHECK_NE(v1, v2)
-#define RTC_DCHECK_LE(v1, v2) RTC_CHECK_LE(v1, v2)
-#define RTC_DCHECK_LT(v1, v2) RTC_CHECK_LT(v1, v2)
-#define RTC_DCHECK_GE(v1, v2) RTC_CHECK_GE(v1, v2)
-#define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2)
-#else
-#define RTC_DCHECK_IS_ON 0
-#define RTC_DCHECK(condition) RTC_EAT_STREAM_PARAMETERS(condition)
-#define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) == (v2))
-#define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) != (v2))
-#define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) <= (v2))
-#define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) < (v2))
-#define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) >= (v2))
-#define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS((v1) > (v2))
-#endif
-
-// This is identical to LogMessageVoidify but in name.
-class FatalMessageVoidify {
- public:
- FatalMessageVoidify() { }
- // This has to be an operator with a precedence lower than << but
- // higher than ?:
- void operator&(std::ostream&) { }
-};
-
-#define RTC_UNREACHABLE_CODE_HIT false
-#define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)
-
-#define FATAL() rtc::FatalMessage(__FILE__, __LINE__).stream()
-// TODO(ajm): Consider adding RTC_NOTIMPLEMENTED macro when
-// base/logging.h and system_wrappers/logging.h are consolidated such that we
-// can match the Chromium behavior.
-
-// Like a stripped-down LogMessage from logging.h, except that it aborts.
-class FatalMessage {
- public:
- FatalMessage(const char* file, int line);
- // Used for RTC_CHECK_EQ(), etc. Takes ownership of the given string.
- FatalMessage(const char* file, int line, std::string* result);
- NO_RETURN ~FatalMessage();
-
- std::ostream& stream() { return stream_; }
-
- private:
- void Init(const char* file, int line);
-
- std::ostringstream stream_;
-};
-
-// Performs the integer division a/b and returns the result. CHECKs that the
-// remainder is zero.
-template <typename T>
-inline T CheckedDivExact(T a, T b) {
- RTC_CHECK_EQ(a % b, static_cast<T>(0));
- return a / b;
-}
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_CHECKS_H_
diff --git a/webrtc/base/constructormagic.h b/webrtc/base/constructormagic.h
deleted file mode 100644
index 6ef7826..0000000
--- a/webrtc/base/constructormagic.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_BASE_CONSTRUCTORMAGIC_H_
-#define WEBRTC_BASE_CONSTRUCTORMAGIC_H_
-
-// Put this in the declarations for a class to be unassignable.
-#define RTC_DISALLOW_ASSIGN(TypeName) \
- void operator=(const TypeName&) = delete
-
-// A macro to disallow the copy constructor and operator= functions. This should
-// be used in the declarations for a class.
-#define RTC_DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&) = delete; \
- RTC_DISALLOW_ASSIGN(TypeName)
-
-// A macro to disallow all the implicit constructors, namely the default
-// constructor, copy constructor and operator= functions.
-//
-// This should be used in the declarations for a class that wants to prevent
-// anyone from instantiating it. This is especially useful for classes
-// containing only static methods.
-#define RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
- TypeName() = delete; \
- RTC_DISALLOW_COPY_AND_ASSIGN(TypeName)
-
-#endif // WEBRTC_BASE_CONSTRUCTORMAGIC_H_
diff --git a/webrtc/base/criticalsection.cc b/webrtc/base/criticalsection.cc
deleted file mode 100644
index 1f50c23..0000000
--- a/webrtc/base/criticalsection.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 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 "webrtc/base/criticalsection.h"
-
-#include "webrtc/base/checks.h"
-
-namespace rtc {
-
-CriticalSection::CriticalSection() {
-#if defined(WEBRTC_WIN)
- InitializeCriticalSection(&crit_);
-#else
- pthread_mutexattr_t mutex_attribute;
- pthread_mutexattr_init(&mutex_attribute);
- pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&mutex_, &mutex_attribute);
- pthread_mutexattr_destroy(&mutex_attribute);
- CS_DEBUG_CODE(thread_ = 0);
- CS_DEBUG_CODE(recursion_count_ = 0);
-#endif
-}
-
-CriticalSection::~CriticalSection() {
-#if defined(WEBRTC_WIN)
- DeleteCriticalSection(&crit_);
-#else
- pthread_mutex_destroy(&mutex_);
-#endif
-}
-
-void CriticalSection::Enter() EXCLUSIVE_LOCK_FUNCTION() {
-#if defined(WEBRTC_WIN)
- EnterCriticalSection(&crit_);
-#else
- pthread_mutex_lock(&mutex_);
-#if CS_DEBUG_CHECKS
- if (!recursion_count_) {
- RTC_DCHECK(!thread_);
- thread_ = pthread_self();
- } else {
- RTC_DCHECK(CurrentThreadIsOwner());
- }
- ++recursion_count_;
-#endif
-#endif
-}
-
-bool CriticalSection::TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
-#if defined(WEBRTC_WIN)
- return TryEnterCriticalSection(&crit_) != FALSE;
-#else
- if (pthread_mutex_trylock(&mutex_) != 0)
- return false;
-#if CS_DEBUG_CHECKS
- if (!recursion_count_) {
- RTC_DCHECK(!thread_);
- thread_ = pthread_self();
- } else {
- RTC_DCHECK(CurrentThreadIsOwner());
- }
- ++recursion_count_;
-#endif
- return true;
-#endif
-}
-void CriticalSection::Leave() UNLOCK_FUNCTION() {
- RTC_DCHECK(CurrentThreadIsOwner());
-#if defined(WEBRTC_WIN)
- LeaveCriticalSection(&crit_);
-#else
-#if CS_DEBUG_CHECKS
- --recursion_count_;
- RTC_DCHECK(recursion_count_ >= 0);
- if (!recursion_count_)
- thread_ = 0;
-#endif
- pthread_mutex_unlock(&mutex_);
-#endif
-}
-
-bool CriticalSection::CurrentThreadIsOwner() const {
-#if defined(WEBRTC_WIN)
- // OwningThread has type HANDLE but actually contains the Thread ID:
- // http://stackoverflow.com/questions/12675301/why-is-the-owningthread-member-of-critical-section-of-type-handle-when-it-is-de
- // Converting through size_t avoids the VS 2015 warning C4312: conversion from
- // 'type1' to 'type2' of greater size
- return crit_.OwningThread ==
- reinterpret_cast<HANDLE>(static_cast<size_t>(GetCurrentThreadId()));
-#else
-#if CS_DEBUG_CHECKS
- return pthread_equal(thread_, pthread_self());
-#else
- return true;
-#endif // CS_DEBUG_CHECKS
-#endif
-}
-
-bool CriticalSection::IsLocked() const {
-#if defined(WEBRTC_WIN)
- return crit_.LockCount != -1;
-#else
-#if CS_DEBUG_CHECKS
- return thread_ != 0;
-#else
- return true;
-#endif
-#endif
-}
-
-CritScope::CritScope(CriticalSection* cs) : cs_(cs) { cs_->Enter(); }
-CritScope::~CritScope() { cs_->Leave(); }
-
-TryCritScope::TryCritScope(CriticalSection* cs)
- : cs_(cs), locked_(cs->TryEnter()) {
- CS_DEBUG_CODE(lock_was_called_ = false);
-}
-
-TryCritScope::~TryCritScope() {
- CS_DEBUG_CODE(RTC_DCHECK(lock_was_called_));
- if (locked_)
- cs_->Leave();
-}
-
-bool TryCritScope::locked() const {
- CS_DEBUG_CODE(lock_was_called_ = true);
- return locked_;
-}
-
-void GlobalLockPod::Lock() {
-#if !defined(WEBRTC_WIN)
- const struct timespec ts_null = {0};
-#endif
-
- while (AtomicOps::CompareAndSwap(&lock_acquired, 0, 1)) {
-#if defined(WEBRTC_WIN)
- ::Sleep(0);
-#else
- nanosleep(&ts_null, nullptr);
-#endif
- }
-}
-
-void GlobalLockPod::Unlock() {
- int old_value = AtomicOps::CompareAndSwap(&lock_acquired, 1, 0);
- RTC_DCHECK_EQ(1, old_value) << "Unlock called without calling Lock first";
-}
-
-GlobalLock::GlobalLock() {
- lock_acquired = 0;
-}
-
-GlobalLockScope::GlobalLockScope(GlobalLockPod* lock)
- : lock_(lock) {
- lock_->Lock();
-}
-
-GlobalLockScope::~GlobalLockScope() {
- lock_->Unlock();
-}
-
-} // namespace rtc
diff --git a/webrtc/base/criticalsection.h b/webrtc/base/criticalsection.h
deleted file mode 100644
index ddbf857..0000000
--- a/webrtc/base/criticalsection.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_BASE_CRITICALSECTION_H_
-#define WEBRTC_BASE_CRITICALSECTION_H_
-
-#include "webrtc/base/atomicops.h"
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/base/thread_annotations.h"
-
-#if defined(WEBRTC_WIN)
-// Include winsock2.h before including <windows.h> to maintain consistency with
-// win32.h. We can't include win32.h directly here since it pulls in
-// headers such as basictypes.h which causes problems in Chromium where webrtc
-// exists as two separate projects, webrtc and libjingle.
-#include <winsock2.h>
-#include <windows.h>
-#include <sal.h> // must come after windows headers.
-#endif // defined(WEBRTC_WIN)
-
-#if defined(WEBRTC_POSIX)
-#include <pthread.h>
-#endif
-
-#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
-#define CS_DEBUG_CHECKS 1
-#endif
-
-#if CS_DEBUG_CHECKS
-#define CS_DEBUG_CODE(x) x
-#else // !CS_DEBUG_CHECKS
-#define CS_DEBUG_CODE(x)
-#endif // !CS_DEBUG_CHECKS
-
-namespace rtc {
-
-class LOCKABLE CriticalSection {
- public:
- CriticalSection();
- ~CriticalSection();
-
- void Enter() EXCLUSIVE_LOCK_FUNCTION();
- bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true);
- void Leave() UNLOCK_FUNCTION();
-
- // Use only for RTC_DCHECKing.
- bool CurrentThreadIsOwner() const;
- // Use only for RTC_DCHECKing.
- bool IsLocked() const;
-
- private:
-#if defined(WEBRTC_WIN)
- CRITICAL_SECTION crit_;
-#elif defined(WEBRTC_POSIX)
- pthread_mutex_t mutex_;
- CS_DEBUG_CODE(pthread_t thread_);
- CS_DEBUG_CODE(int recursion_count_);
-#endif
-};
-
-// CritScope, for serializing execution through a scope.
-class SCOPED_LOCKABLE CritScope {
- public:
- explicit CritScope(CriticalSection* cs) EXCLUSIVE_LOCK_FUNCTION(cs);
- ~CritScope() UNLOCK_FUNCTION();
- private:
- CriticalSection* const cs_;
- RTC_DISALLOW_COPY_AND_ASSIGN(CritScope);
-};
-
-// Tries to lock a critical section on construction via
-// CriticalSection::TryEnter, and unlocks on destruction if the
-// lock was taken. Never blocks.
-//
-// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
-// subsequent code. Users *must* check locked() to determine if the
-// lock was taken. If you're not calling locked(), you're doing it wrong!
-class TryCritScope {
- public:
- explicit TryCritScope(CriticalSection* cs);
- ~TryCritScope();
-#if defined(WEBRTC_WIN)
- _Check_return_ bool locked() const;
-#else
- bool locked() const __attribute__((warn_unused_result));
-#endif
- private:
- CriticalSection* const cs_;
- const bool locked_;
- CS_DEBUG_CODE(mutable bool lock_was_called_);
- RTC_DISALLOW_COPY_AND_ASSIGN(TryCritScope);
-};
-
-// A POD lock used to protect global variables. Do NOT use for other purposes.
-// No custom constructor or private data member should be added.
-class LOCKABLE GlobalLockPod {
- public:
- void Lock() EXCLUSIVE_LOCK_FUNCTION();
-
- void Unlock() UNLOCK_FUNCTION();
-
- volatile int lock_acquired;
-};
-
-class GlobalLock : public GlobalLockPod {
- public:
- GlobalLock();
-};
-
-// GlobalLockScope, for serializing execution through a scope.
-class SCOPED_LOCKABLE GlobalLockScope {
- public:
- explicit GlobalLockScope(GlobalLockPod* lock) EXCLUSIVE_LOCK_FUNCTION(lock);
- ~GlobalLockScope() UNLOCK_FUNCTION();
- private:
- GlobalLockPod* const lock_;
- RTC_DISALLOW_COPY_AND_ASSIGN(GlobalLockScope);
-};
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_CRITICALSECTION_H_
diff --git a/webrtc/base/event.cc b/webrtc/base/event.cc
deleted file mode 100644
index a9af208..0000000
--- a/webrtc/base/event.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/base/event.h"
-
-#if defined(WEBRTC_WIN)
-#include <windows.h>
-#elif defined(WEBRTC_POSIX)
-#include <pthread.h>
-#include <sys/time.h>
-#include <time.h>
-#else
-#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
-#endif
-
-#include "webrtc/base/checks.h"
-
-namespace rtc {
-
-#if defined(WEBRTC_WIN)
-
-Event::Event(bool manual_reset, bool initially_signaled) {
- event_handle_ = ::CreateEvent(NULL, // Security attributes.
- manual_reset,
- initially_signaled,
- NULL); // Name.
- RTC_CHECK(event_handle_);
-}
-
-Event::~Event() {
- CloseHandle(event_handle_);
-}
-
-void Event::Set() {
- SetEvent(event_handle_);
-}
-
-void Event::Reset() {
- ResetEvent(event_handle_);
-}
-
-bool Event::Wait(int milliseconds) {
- DWORD ms = (milliseconds == kForever) ? INFINITE : milliseconds;
- return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
-}
-
-#elif defined(WEBRTC_POSIX)
-
-Event::Event(bool manual_reset, bool initially_signaled)
- : is_manual_reset_(manual_reset),
- event_status_(initially_signaled) {
- RTC_CHECK(pthread_mutex_init(&event_mutex_, NULL) == 0);
- RTC_CHECK(pthread_cond_init(&event_cond_, NULL) == 0);
-}
-
-Event::~Event() {
- pthread_mutex_destroy(&event_mutex_);
- pthread_cond_destroy(&event_cond_);
-}
-
-void Event::Set() {
- pthread_mutex_lock(&event_mutex_);
- event_status_ = true;
- pthread_cond_broadcast(&event_cond_);
- pthread_mutex_unlock(&event_mutex_);
-}
-
-void Event::Reset() {
- pthread_mutex_lock(&event_mutex_);
- event_status_ = false;
- pthread_mutex_unlock(&event_mutex_);
-}
-
-bool Event::Wait(int milliseconds) {
- pthread_mutex_lock(&event_mutex_);
- int error = 0;
-
- if (milliseconds != kForever) {
- // Converting from seconds and microseconds (1e-6) plus
- // milliseconds (1e-3) to seconds and nanoseconds (1e-9).
-
- struct timespec ts;
-#if HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
- // Use relative time version, which tends to be more efficient for
- // pthread implementations where provided (like on Android).
- ts.tv_sec = milliseconds / 1000;
- ts.tv_nsec = (milliseconds % 1000) * 1000000;
-#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
-
- ts.tv_sec = tv.tv_sec + (milliseconds / 1000);
- ts.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;
-
- // Handle overflow.
- if (ts.tv_nsec >= 1000000000) {
- ts.tv_sec++;
- ts.tv_nsec -= 1000000000;
- }
-#endif
-
- while (!event_status_ && error == 0) {
-#if HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
- error = pthread_cond_timedwait_relative_np(
- &event_cond_, &event_mutex_, &ts);
-#else
- error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
-#endif
- }
- } else {
- while (!event_status_ && error == 0)
- error = pthread_cond_wait(&event_cond_, &event_mutex_);
- }
-
- // NOTE(liulk): Exactly one thread will auto-reset this event. All
- // the other threads will think it's unsignaled. This seems to be
- // consistent with auto-reset events in WEBRTC_WIN
- if (error == 0 && !is_manual_reset_)
- event_status_ = false;
-
- pthread_mutex_unlock(&event_mutex_);
-
- return (error == 0);
-}
-
-#endif
-
-} // namespace rtc
diff --git a/webrtc/base/event.h b/webrtc/base/event.h
deleted file mode 100644
index 5237151..0000000
--- a/webrtc/base/event.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_BASE_EVENT_H__
-#define WEBRTC_BASE_EVENT_H__
-
-#if defined(WEBRTC_WIN)
-#include "webrtc/base/win32.h" // NOLINT: consider this a system header.
-#elif defined(WEBRTC_POSIX)
-#include <pthread.h>
-#else
-#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
-#endif
-
-#include "webrtc/base/basictypes.h"
-
-namespace rtc {
-
-class Event {
- public:
- static const int kForever = -1;
-
- Event(bool manual_reset, bool initially_signaled);
- ~Event();
-
- void Set();
- void Reset();
-
- // Wait for the event to become signaled, for the specified number of
- // |milliseconds|. To wait indefinetly, pass kForever.
- bool Wait(int milliseconds);
-
- private:
-#if defined(WEBRTC_WIN)
- HANDLE event_handle_;
-#elif defined(WEBRTC_POSIX)
- pthread_mutex_t event_mutex_;
- pthread_cond_t event_cond_;
- const bool is_manual_reset_;
- bool event_status_;
-#endif
-};
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_EVENT_H__
diff --git a/webrtc/base/maybe.h b/webrtc/base/maybe.h
deleted file mode 100644
index 1df94de..0000000
--- a/webrtc/base/maybe.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 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 WEBRTC_BASE_MAYBE_H_
-#define WEBRTC_BASE_MAYBE_H_
-
-#include <algorithm>
-#include <utility>
-
-#include "webrtc/base/checks.h"
-
-namespace rtc {
-
-// Simple std::experimental::optional-wannabe. It either contains a T or not.
-// In order to keep the implementation simple and portable, this implementation
-// actually contains a (default-constructed) T even when it supposedly doesn't
-// contain a value; use e.g. rtc::scoped_ptr<T> instead if that's too
-// expensive.
-//
-// A moved-from Maybe<T> may only be destroyed, and assigned to if T allows
-// being assigned to after having been moved from. Specifically, you may not
-// assume that it just doesn't contain a value anymore.
-//
-// TODO(kwiberg): Get rid of this class when the standard library has
-// std::optional (and we're allowed to use it).
-template <typename T>
-class Maybe final {
- public:
- // Construct an empty Maybe.
- Maybe() : has_value_(false) {}
-
- // Construct a Maybe that contains a value.
- explicit Maybe(const T& val) : value_(val), has_value_(true) {}
- explicit Maybe(T&& val) : value_(static_cast<T&&>(val)), has_value_(true) {}
-
- // Copy and move constructors.
- // TODO(kwiberg): =default the move constructor when MSVC supports it.
- Maybe(const Maybe&) = default;
- Maybe(Maybe&& m)
- : value_(static_cast<T&&>(m.value_)), has_value_(m.has_value_) {}
-
- // Assignment.
- // TODO(kwiberg): =default the move assignment op when MSVC supports it.
- Maybe& operator=(const Maybe&) = default;
- Maybe& operator=(Maybe&& m) {
- value_ = static_cast<T&&>(m.value_);
- has_value_ = m.has_value_;
- return *this;
- }
-
- friend void swap(Maybe& m1, Maybe& m2) {
- using std::swap;
- swap(m1.value_, m2.value_);
- swap(m1.has_value_, m2.has_value_);
- }
-
- // Conversion to bool to test if we have a value.
- explicit operator bool() const { return has_value_; }
-
- // Dereferencing. Only allowed if we have a value.
- const T* operator->() const {
- RTC_DCHECK(has_value_);
- return &value_;
- }
- T* operator->() {
- RTC_DCHECK(has_value_);
- return &value_;
- }
- const T& operator*() const {
- RTC_DCHECK(has_value_);
- return value_;
- }
- T& operator*() {
- RTC_DCHECK(has_value_);
- return value_;
- }
-
- // Dereference with a default value in case we don't have a value.
- const T& value_or(const T& default_val) const {
- return has_value_ ? value_ : default_val;
- }
-
- // Equality tests. Two Maybes are equal if they contain equivalent values, or
- // if they're both empty.
- friend bool operator==(const Maybe& m1, const Maybe& m2) {
- return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_
- : m1.has_value_ == m2.has_value_;
- }
- friend bool operator!=(const Maybe& m1, const Maybe& m2) {
- return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_
- : m1.has_value_ != m2.has_value_;
- }
-
- private:
- // Invariant: Unless *this has been moved from, value_ is default-initialized
- // (or copied or moved from a default-initialized T) if !has_value_.
- T value_;
- bool has_value_;
-};
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_MAYBE_H_
diff --git a/webrtc/base/meson.build b/webrtc/base/meson.build
deleted file mode 100644
index 2f634a3..0000000
--- a/webrtc/base/meson.build
+++ /dev/null
@@ -1,34 +0,0 @@
-base_sources = [
- 'criticalsection.cc',
- 'checks.cc',
- 'event.cc',
- 'platform_thread.cc',
- 'platform_file.cc',
- 'stringutils.cc',
- 'thread_checker_impl.cc',
-]
-
-base_headers = [
- 'arraysize.h',
- 'checks.h',
- 'constructormagic.h',
- 'basictypes.h',
- 'maybe.h',
- 'platform_file.h',
-]
-
-install_headers(base_headers,
- subdir: 'webrtc_audio_processing/webrtc/base'
-)
-
-libbase = static_library('libbase',
- base_sources,
- dependencies: common_deps,
- include_directories: webrtc_inc,
- cpp_args : common_cxxflags
-)
-
-base_dep = declare_dependency(
- link_with: libbase
-)
-
diff --git a/webrtc/base/platform_file.cc b/webrtc/base/platform_file.cc
deleted file mode 100644
index d518b74..0000000
--- a/webrtc/base/platform_file.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 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 "webrtc/base/platform_file.h"
-
-#if defined(WEBRTC_WIN)
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-namespace rtc {
-
-#if defined(WEBRTC_WIN)
-const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
-
-FILE* FdopenPlatformFileForWriting(PlatformFile file) {
- if (file == kInvalidPlatformFileValue)
- return NULL;
- int fd = _open_osfhandle(reinterpret_cast<intptr_t>(file), 0);
- if (fd < 0)
- return NULL;
-
- return _fdopen(fd, "w");
-}
-
-bool ClosePlatformFile(PlatformFile file) {
- return CloseHandle(file) != 0;
-}
-#else
-const PlatformFile kInvalidPlatformFileValue = -1;
-
-FILE* FdopenPlatformFileForWriting(PlatformFile file) {
- return fdopen(file, "w");
-}
-
-bool ClosePlatformFile(PlatformFile file) {
- return close(file);
-}
-#endif
-
-} // namespace rtc
diff --git a/webrtc/base/platform_file.h b/webrtc/base/platform_file.h
deleted file mode 100644
index 12e08e9..0000000
--- a/webrtc/base/platform_file.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 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 WEBRTC_BASE_PLATFORM_FILE_H_
-#define WEBRTC_BASE_PLATFORM_FILE_H_
-
-#include <stdio.h>
-
-#if defined(WEBRTC_WIN)
-#include <windows.h>
-#endif
-
-namespace rtc {
-
-#if defined(WEBRTC_WIN)
-typedef HANDLE PlatformFile;
-#elif defined(WEBRTC_POSIX)
-typedef int PlatformFile;
-#else
-#error Unsupported platform
-#endif
-
-extern const PlatformFile kInvalidPlatformFileValue;
-
-// Associates a standard FILE stream with an existing PlatformFile.
-// Note that after this function has returned a valid FILE stream,
-// the PlatformFile should no longer be used.
-FILE* FdopenPlatformFileForWriting(PlatformFile file);
-
-// Closes a PlatformFile.
-// Don't use ClosePlatformFile to close a file opened with FdopenPlatformFile.
-// Use fclose instead.
-bool ClosePlatformFile(PlatformFile file);
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_PLATFORM_FILE_H_
diff --git a/webrtc/base/platform_thread.cc b/webrtc/base/platform_thread.cc
deleted file mode 100644
index 707ccf8..0000000
--- a/webrtc/base/platform_thread.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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 "webrtc/base/platform_thread.h"
-
-#include <string.h>
-
-#include "webrtc/base/checks.h"
-
-#if defined(WEBRTC_LINUX)
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#elif defined(WEBRTC_GNU)
-#include <sys/syscall.h>
-#endif
-
-namespace rtc {
-
-PlatformThreadId CurrentThreadId() {
- PlatformThreadId ret;
-#if defined(WEBRTC_WIN)
- ret = GetCurrentThreadId();
-#elif defined(WEBRTC_POSIX)
-#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
- ret = pthread_mach_thread_np(pthread_self());
-#elif defined(WEBRTC_LINUX)
- ret = syscall(__NR_gettid);
-#elif defined(WEBRTC_ANDROID)
- ret = gettid();
-#elif defined(WEBRTC_GNU)
- ret = pthread_self();
-#else
- // Default implementation for nacl and solaris.
- ret = reinterpret_cast<pid_t>(pthread_self());
-#endif
-#endif // defined(WEBRTC_POSIX)
- RTC_DCHECK(ret);
- return ret;
-}
-
-PlatformThreadRef CurrentThreadRef() {
-#if defined(WEBRTC_WIN)
- return GetCurrentThreadId();
-#elif defined(WEBRTC_POSIX)
- return pthread_self();
-#endif
-}
-
-bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
-#if defined(WEBRTC_WIN)
- return a == b;
-#elif defined(WEBRTC_POSIX)
- return pthread_equal(a, b);
-#endif
-}
-
-void SetCurrentThreadName(const char* name) {
- RTC_DCHECK(strlen(name) < 64);
-#if defined(WEBRTC_WIN)
- struct {
- DWORD dwType;
- LPCSTR szName;
- DWORD dwThreadID;
- DWORD dwFlags;
- } threadname_info = {0x1000, name, static_cast<DWORD>(-1), 0};
-
- __try {
- ::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(DWORD),
- reinterpret_cast<ULONG_PTR*>(&threadname_info));
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- }
-#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
- prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name));
-#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
- pthread_setname_np(name);
-#endif
-}
-
-} // namespace rtc
diff --git a/webrtc/base/scoped_ptr.h b/webrtc/base/scoped_ptr.h
deleted file mode 100644
index 203a001..0000000
--- a/webrtc/base/scoped_ptr.h
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
- * Copyright 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.
- */
-
-// Borrowed from Chromium's src/base/memory/scoped_ptr.h.
-
-// Scopers help you manage ownership of a pointer, helping you easily manage a
-// pointer within a scope, and automatically destroying the pointer at the end
-// of a scope. There are two main classes you will use, which correspond to the
-// operators new/delete and new[]/delete[].
-//
-// Example usage (scoped_ptr<T>):
-// {
-// scoped_ptr<Foo> foo(new Foo("wee"));
-// } // foo goes out of scope, releasing the pointer with it.
-//
-// {
-// scoped_ptr<Foo> foo; // No pointer managed.
-// foo.reset(new Foo("wee")); // Now a pointer is managed.
-// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed.
-// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed.
-// foo->Method(); // Foo::Method() called.
-// foo.get()->Method(); // Foo::Method() called.
-// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer
-// // manages a pointer.
-// foo.reset(new Foo("wee4")); // foo manages a pointer again.
-// foo.reset(); // Foo("wee4") destroyed, foo no longer
-// // manages a pointer.
-// } // foo wasn't managing a pointer, so nothing was destroyed.
-//
-// Example usage (scoped_ptr<T[]>):
-// {
-// scoped_ptr<Foo[]> foo(new Foo[100]);
-// foo.get()->Method(); // Foo::Method on the 0th element.
-// foo[10].Method(); // Foo::Method on the 10th element.
-// }
-//
-// These scopers also implement part of the functionality of C++11 unique_ptr
-// in that they are "movable but not copyable." You can use the scopers in
-// the parameter and return types of functions to signify ownership transfer
-// in to and out of a function. When calling a function that has a scoper
-// as the argument type, it must be called with the result of an analogous
-// scoper's Pass() function or another function that generates a temporary;
-// passing by copy will NOT work. Here is an example using scoped_ptr:
-//
-// void TakesOwnership(scoped_ptr<Foo> arg) {
-// // Do something with arg
-// }
-// scoped_ptr<Foo> CreateFoo() {
-// // No need for calling Pass() because we are constructing a temporary
-// // for the return value.
-// return scoped_ptr<Foo>(new Foo("new"));
-// }
-// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
-// return arg.Pass();
-// }
-//
-// {
-// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
-// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
-// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
-// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
-// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr.
-// }
-//
-// Notice that if you do not call Pass() when returning from PassThru(), or
-// when invoking TakesOwnership(), the code will not compile because scopers
-// are not copyable; they only implement move semantics which require calling
-// the Pass() function to signify a destructive transfer of state. CreateFoo()
-// is different though because we are constructing a temporary on the return
-// line and thus can avoid needing to call Pass().
-//
-// Pass() properly handles upcast in initialization, i.e. you can use a
-// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
-//
-// scoped_ptr<Foo> foo(new Foo());
-// scoped_ptr<FooParent> parent(foo.Pass());
-//
-// PassAs<>() should be used to upcast return value in return statement:
-//
-// scoped_ptr<Foo> CreateFoo() {
-// scoped_ptr<FooChild> result(new FooChild());
-// return result.PassAs<Foo>();
-// }
-//
-// Note that PassAs<>() is implemented only for scoped_ptr<T>, but not for
-// scoped_ptr<T[]>. This is because casting array pointers may not be safe.
-
-#ifndef WEBRTC_BASE_SCOPED_PTR_H__
-#define WEBRTC_BASE_SCOPED_PTR_H__
-
-// This is an implementation designed to match the anticipated future TR2
-// implementation of the scoped_ptr class.
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-#include <algorithm> // For std::swap().
-
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/base/template_util.h"
-#include "webrtc/typedefs.h"
-
-namespace rtc {
-
-// Function object which deletes its parameter, which must be a pointer.
-// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
-// invokes 'delete'. The default deleter for scoped_ptr<T>.
-template <class T>
-struct DefaultDeleter {
- DefaultDeleter() {}
- template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
- // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
- // if U* is implicitly convertible to T* and U is not an array type.
- //
- // Correct implementation should use SFINAE to disable this
- // constructor. However, since there are no other 1-argument constructors,
- // using a static_assert based on is_convertible<> and requiring
- // complete types is simpler and will cause compile failures for equivalent
- // misuses.
- //
- // Note, the is_convertible<U*, T*> check also ensures that U is not an
- // array. T is guaranteed to be a non-array, so any U* where U is an array
- // cannot convert to T*.
- enum { T_must_be_complete = sizeof(T) };
- enum { U_must_be_complete = sizeof(U) };
- static_assert(rtc::is_convertible<U*, T*>::value,
- "U* must implicitly convert to T*");
- }
- inline void operator()(T* ptr) const {
- enum { type_must_be_complete = sizeof(T) };
- delete ptr;
- }
-};
-
-// Specialization of DefaultDeleter for array types.
-template <class T>
-struct DefaultDeleter<T[]> {
- inline void operator()(T* ptr) const {
- enum { type_must_be_complete = sizeof(T) };
- delete[] ptr;
- }
-
- private:
- // Disable this operator for any U != T because it is undefined to execute
- // an array delete when the static type of the array mismatches the dynamic
- // type.
- //
- // References:
- // C++98 [expr.delete]p3
- // http://cplusplus.github.com/LWG/lwg-defects.html#938
- template <typename U> void operator()(U* array) const;
-};
-
-template <class T, int n>
-struct DefaultDeleter<T[n]> {
- // Never allow someone to declare something like scoped_ptr<int[10]>.
- static_assert(sizeof(T) == -1, "do not use array with size as type");
-};
-
-// Function object which invokes 'free' on its parameter, which must be
-// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
-//
-// scoped_ptr<int, rtc::FreeDeleter> foo_ptr(
-// static_cast<int*>(malloc(sizeof(int))));
-struct FreeDeleter {
- inline void operator()(void* ptr) const {
- free(ptr);
- }
-};
-
-namespace internal {
-
-template <typename T>
-struct ShouldAbortOnSelfReset {
- template <typename U>
- static rtc::internal::NoType Test(const typename U::AllowSelfReset*);
-
- template <typename U>
- static rtc::internal::YesType Test(...);
-
- static const bool value =
- sizeof(Test<T>(0)) == sizeof(rtc::internal::YesType);
-};
-
-// Minimal implementation of the core logic of scoped_ptr, suitable for
-// reuse in both scoped_ptr and its specializations.
-template <class T, class D>
-class scoped_ptr_impl {
- public:
- explicit scoped_ptr_impl(T* p) : data_(p) {}
-
- // Initializer for deleters that have data parameters.
- scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
-
- // Templated constructor that destructively takes the value from another
- // scoped_ptr_impl.
- template <typename U, typename V>
- scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
- : data_(other->release(), other->get_deleter()) {
- // We do not support move-only deleters. We could modify our move
- // emulation to have rtc::subtle::move() and rtc::subtle::forward()
- // functions that are imperfect emulations of their C++11 equivalents,
- // but until there's a requirement, just assume deleters are copyable.
- }
-
- template <typename U, typename V>
- void TakeState(scoped_ptr_impl<U, V>* other) {
- // See comment in templated constructor above regarding lack of support
- // for move-only deleters.
- reset(other->release());
- get_deleter() = other->get_deleter();
- }
-
- ~scoped_ptr_impl() {
- if (data_.ptr != nullptr) {
- // Not using get_deleter() saves one function call in non-optimized
- // builds.
- static_cast<D&>(data_)(data_.ptr);
- }
- }
-
- void reset(T* p) {
- // This is a self-reset, which is no longer allowed for default deleters:
- // https://crbug.com/162971
- assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
-
- // Note that running data_.ptr = p can lead to undefined behavior if
- // get_deleter()(get()) deletes this. In order to prevent this, reset()
- // should update the stored pointer before deleting its old value.
- //
- // However, changing reset() to use that behavior may cause current code to
- // break in unexpected ways. If the destruction of the owned object
- // dereferences the scoped_ptr when it is destroyed by a call to reset(),
- // then it will incorrectly dispatch calls to |p| rather than the original
- // value of |data_.ptr|.
- //
- // During the transition period, set the stored pointer to nullptr while
- // deleting the object. Eventually, this safety check will be removed to
- // prevent the scenario initially described from occurring and
- // http://crbug.com/176091 can be closed.
- T* old = data_.ptr;
- data_.ptr = nullptr;
- if (old != nullptr)
- static_cast<D&>(data_)(old);
- data_.ptr = p;
- }
-
- T* get() const { return data_.ptr; }
-
- D& get_deleter() { return data_; }
- const D& get_deleter() const { return data_; }
-
- void swap(scoped_ptr_impl& p2) {
- // Standard swap idiom: 'using std::swap' ensures that std::swap is
- // present in the overload set, but we call swap unqualified so that
- // any more-specific overloads can be used, if available.
- using std::swap;
- swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
- swap(data_.ptr, p2.data_.ptr);
- }
-
- T* release() {
- T* old_ptr = data_.ptr;
- data_.ptr = nullptr;
- return old_ptr;
- }
-
- T** accept() {
- reset(nullptr);
- return &(data_.ptr);
- }
-
- T** use() {
- return &(data_.ptr);
- }
-
- private:
- // Needed to allow type-converting constructor.
- template <typename U, typename V> friend class scoped_ptr_impl;
-
- // Use the empty base class optimization to allow us to have a D
- // member, while avoiding any space overhead for it when D is an
- // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good
- // discussion of this technique.
- struct Data : public D {
- explicit Data(T* ptr_in) : ptr(ptr_in) {}
- Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
- T* ptr;
- };
-
- Data data_;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
-};
-
-} // namespace internal
-
-// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
-// automatically deletes the pointer it holds (if any).
-// That is, scoped_ptr<T> owns the T object that it points to.
-// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T
-// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you
-// dereference it, you get the thread safety guarantees of T.
-//
-// The size of scoped_ptr is small. On most compilers, when using the
-// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
-// increase the size proportional to whatever state they need to have. See
-// comments inside scoped_ptr_impl<> for details.
-//
-// Current implementation targets having a strict subset of C++11's
-// unique_ptr<> features. Known deficiencies include not supporting move-only
-// deleters, function pointers as deleters, and deleters with reference
-// types.
-template <class T, class D = rtc::DefaultDeleter<T> >
-class scoped_ptr {
-
- // TODO(ajm): If we ever import RefCountedBase, this check needs to be
- // enabled.
- //static_assert(rtc::internal::IsNotRefCounted<T>::value,
- // "T is refcounted type and needs scoped refptr");
-
- public:
- // The element and deleter types.
- typedef T element_type;
- typedef D deleter_type;
-
- // Constructor. Defaults to initializing with nullptr.
- scoped_ptr() : impl_(nullptr) {}
-
- // Constructor. Takes ownership of p.
- explicit scoped_ptr(element_type* p) : impl_(p) {}
-
- // Constructor. Allows initialization of a stateful deleter.
- scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
-
- // Constructor. Allows construction from a nullptr.
- scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
-
- // Constructor. Allows construction from a scoped_ptr rvalue for a
- // convertible type and deleter.
- //
- // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
- // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
- // has different post-conditions if D is a reference type. Since this
- // implementation does not support deleters with reference type,
- // we do not need a separate move constructor allowing us to avoid one
- // use of SFINAE. You only need to care about this if you modify the
- // implementation of scoped_ptr.
- template <typename U, typename V>
- scoped_ptr(scoped_ptr<U, V>&& other)
- : impl_(&other.impl_) {
- static_assert(!rtc::is_array<U>::value, "U cannot be an array");
- }
-
- // operator=. Allows assignment from a scoped_ptr rvalue for a convertible
- // type and deleter.
- //
- // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
- // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
- // form has different requirements on for move-only Deleters. Since this
- // implementation does not support move-only Deleters, we do not need a
- // separate move assignment operator allowing us to avoid one use of SFINAE.
- // You only need to care about this if you modify the implementation of
- // scoped_ptr.
- template <typename U, typename V>
- scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
- static_assert(!rtc::is_array<U>::value, "U cannot be an array");
- impl_.TakeState(&rhs.impl_);
- return *this;
- }
-
- // operator=. Allows assignment from a nullptr. Deletes the currently owned
- // object, if any.
- scoped_ptr& operator=(decltype(nullptr)) {
- reset();
- return *this;
- }
-
- // Deleted copy constructor and copy assignment, to make the type move-only.
- scoped_ptr(const scoped_ptr& other) = delete;
- scoped_ptr& operator=(const scoped_ptr& other) = delete;
-
- // Get an rvalue reference. (sp.Pass() does the same thing as std::move(sp).)
- scoped_ptr&& Pass() { return static_cast<scoped_ptr&&>(*this); }
-
- // Reset. Deletes the currently owned object, if any.
- // Then takes ownership of a new object, if given.
- void reset(element_type* p = nullptr) { impl_.reset(p); }
-
- // Accessors to get the owned object.
- // operator* and operator-> will assert() if there is no current object.
- element_type& operator*() const {
- assert(impl_.get() != nullptr);
- return *impl_.get();
- }
- element_type* operator->() const {
- assert(impl_.get() != nullptr);
- return impl_.get();
- }
- element_type* get() const { return impl_.get(); }
-
- // Access to the deleter.
- deleter_type& get_deleter() { return impl_.get_deleter(); }
- const deleter_type& get_deleter() const { return impl_.get_deleter(); }
-
- // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
- // implicitly convertible to a real bool (which is dangerous).
- //
- // Note that this trick is only safe when the == and != operators
- // are declared explicitly, as otherwise "scoped_ptr1 ==
- // scoped_ptr2" will compile but do the wrong thing (i.e., convert
- // to Testable and then do the comparison).
- private:
- typedef rtc::internal::scoped_ptr_impl<element_type, deleter_type>
- scoped_ptr::*Testable;
-
- public:
- operator Testable() const {
- return impl_.get() ? &scoped_ptr::impl_ : nullptr;
- }
-
- // Comparison operators.
- // These return whether two scoped_ptr refer to the same object, not just to
- // two different but equal objects.
- bool operator==(const element_type* p) const { return impl_.get() == p; }
- bool operator!=(const element_type* p) const { return impl_.get() != p; }
-
- // Swap two scoped pointers.
- void swap(scoped_ptr& p2) {
- impl_.swap(p2.impl_);
- }
-
- // Release a pointer.
- // The return value is the current pointer held by this object. If this object
- // holds a nullptr, the return value is nullptr. After this operation, this
- // object will hold a nullptr, and will not own the object any more.
- element_type* release() WARN_UNUSED_RESULT {
- return impl_.release();
- }
-
- // Delete the currently held pointer and return a pointer
- // to allow overwriting of the current pointer address.
- element_type** accept() WARN_UNUSED_RESULT {
- return impl_.accept();
- }
-
- // Return a pointer to the current pointer address.
- element_type** use() WARN_UNUSED_RESULT {
- return impl_.use();
- }
-
- private:
- // Needed to reach into |impl_| in the constructor.
- template <typename U, typename V> friend class scoped_ptr;
- rtc::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
-
- // Forbidden for API compatibility with std::unique_ptr.
- explicit scoped_ptr(int disallow_construction_from_null);
-
- // Forbid comparison of scoped_ptr types. If U != T, it totally
- // doesn't make sense, and if U == T, it still doesn't make sense
- // because you should never have the same object owned by two different
- // scoped_ptrs.
- template <class U> bool operator==(scoped_ptr<U> const& p2) const;
- template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
-};
-
-template <class T, class D>
-class scoped_ptr<T[], D> {
- public:
- // The element and deleter types.
- typedef T element_type;
- typedef D deleter_type;
-
- // Constructor. Defaults to initializing with nullptr.
- scoped_ptr() : impl_(nullptr) {}
-
- // Constructor. Stores the given array. Note that the argument's type
- // must exactly match T*. In particular:
- // - it cannot be a pointer to a type derived from T, because it is
- // inherently unsafe in the general case to access an array through a
- // pointer whose dynamic type does not match its static type (eg., if
- // T and the derived types had different sizes access would be
- // incorrectly calculated). Deletion is also always undefined
- // (C++98 [expr.delete]p3). If you're doing this, fix your code.
- // - it cannot be const-qualified differently from T per unique_ptr spec
- // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
- // to work around this may use implicit_cast<const T*>().
- // However, because of the first bullet in this comment, users MUST
- // NOT use implicit_cast<Base*>() to upcast the static type of the array.
- explicit scoped_ptr(element_type* array) : impl_(array) {}
-
- // Constructor. Allows construction from a nullptr.
- scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
-
- // Constructor. Allows construction from a scoped_ptr rvalue.
- scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
-
- // operator=. Allows assignment from a scoped_ptr rvalue.
- scoped_ptr& operator=(scoped_ptr&& rhs) {
- impl_.TakeState(&rhs.impl_);
- return *this;
- }
-
- // operator=. Allows assignment from a nullptr. Deletes the currently owned
- // array, if any.
- scoped_ptr& operator=(decltype(nullptr)) {
- reset();
- return *this;
- }
-
- // Deleted copy constructor and copy assignment, to make the type move-only.
- scoped_ptr(const scoped_ptr& other) = delete;
- scoped_ptr& operator=(const scoped_ptr& other) = delete;
-
- // Get an rvalue reference. (sp.Pass() does the same thing as std::move(sp).)
- scoped_ptr&& Pass() { return static_cast<scoped_ptr&&>(*this); }
-
- // Reset. Deletes the currently owned array, if any.
- // Then takes ownership of a new object, if given.
- void reset(element_type* array = nullptr) { impl_.reset(array); }
-
- // Accessors to get the owned array.
- element_type& operator[](size_t i) const {
- assert(impl_.get() != nullptr);
- return impl_.get()[i];
- }
- element_type* get() const { return impl_.get(); }
-
- // Access to the deleter.
- deleter_type& get_deleter() { return impl_.get_deleter(); }
- const deleter_type& get_deleter() const { return impl_.get_deleter(); }
-
- // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
- // implicitly convertible to a real bool (which is dangerous).
- private:
- typedef rtc::internal::scoped_ptr_impl<element_type, deleter_type>
- scoped_ptr::*Testable;
-
- public:
- operator Testable() const {
- return impl_.get() ? &scoped_ptr::impl_ : nullptr;
- }
-
- // Comparison operators.
- // These return whether two scoped_ptr refer to the same object, not just to
- // two different but equal objects.
- bool operator==(element_type* array) const { return impl_.get() == array; }
- bool operator!=(element_type* array) const { return impl_.get() != array; }
-
- // Swap two scoped pointers.
- void swap(scoped_ptr& p2) {
- impl_.swap(p2.impl_);
- }
-
- // Release a pointer.
- // The return value is the current pointer held by this object. If this object
- // holds a nullptr, the return value is nullptr. After this operation, this
- // object will hold a nullptr, and will not own the object any more.
- element_type* release() WARN_UNUSED_RESULT {
- return impl_.release();
- }
-
- // Delete the currently held pointer and return a pointer
- // to allow overwriting of the current pointer address.
- element_type** accept() WARN_UNUSED_RESULT {
- return impl_.accept();
- }
-
- // Return a pointer to the current pointer address.
- element_type** use() WARN_UNUSED_RESULT {
- return impl_.use();
- }
-
- private:
- // Force element_type to be a complete type.
- enum { type_must_be_complete = sizeof(element_type) };
-
- // Actually hold the data.
- rtc::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
-
- // Disable initialization from any type other than element_type*, by
- // providing a constructor that matches such an initialization, but is
- // private and has no definition. This is disabled because it is not safe to
- // call delete[] on an array whose static type does not match its dynamic
- // type.
- template <typename U> explicit scoped_ptr(U* array);
- explicit scoped_ptr(int disallow_construction_from_null);
-
- // Disable reset() from any type other than element_type*, for the same
- // reasons as the constructor above.
- template <typename U> void reset(U* array);
- void reset(int disallow_reset_from_null);
-
- // Forbid comparison of scoped_ptr types. If U != T, it totally
- // doesn't make sense, and if U == T, it still doesn't make sense
- // because you should never have the same object owned by two different
- // scoped_ptrs.
- template <class U> bool operator==(scoped_ptr<U> const& p2) const;
- template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
-};
-
-template <class T, class D>
-void swap(rtc::scoped_ptr<T, D>& p1, rtc::scoped_ptr<T, D>& p2) {
- p1.swap(p2);
-}
-
-} // namespace rtc
-
-template <class T, class D>
-bool operator==(T* p1, const rtc::scoped_ptr<T, D>& p2) {
- return p1 == p2.get();
-}
-
-template <class T, class D>
-bool operator!=(T* p1, const rtc::scoped_ptr<T, D>& p2) {
- return p1 != p2.get();
-}
-
-// A function to convert T* into scoped_ptr<T>
-// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
-// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
-template <typename T>
-rtc::scoped_ptr<T> rtc_make_scoped_ptr(T* ptr) {
- return rtc::scoped_ptr<T>(ptr);
-}
-
-#endif // #ifndef WEBRTC_BASE_SCOPED_PTR_H__
diff --git a/webrtc/base/stringutils.cc b/webrtc/base/stringutils.cc
deleted file mode 100644
index 9580253..0000000
--- a/webrtc/base/stringutils.cc
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/stringutils.h"
-
-namespace rtc {
-
-bool memory_check(const void* memory, int c, size_t count) {
- const char* char_memory = static_cast<const char*>(memory);
- char char_c = static_cast<char>(c);
- for (size_t i = 0; i < count; ++i) {
- if (char_memory[i] != char_c) {
- return false;
- }
- }
- return true;
-}
-
-bool string_match(const char* target, const char* pattern) {
- while (*pattern) {
- if (*pattern == '*') {
- if (!*++pattern) {
- return true;
- }
- while (*target) {
- if ((toupper(*pattern) == toupper(*target))
- && string_match(target + 1, pattern + 1)) {
- return true;
- }
- ++target;
- }
- return false;
- } else {
- if (toupper(*pattern) != toupper(*target)) {
- return false;
- }
- ++target;
- ++pattern;
- }
- }
- return !*target;
-}
-
-#if defined(WEBRTC_WIN)
-int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n,
- CharacterTransformation transformation) {
- wchar_t c1, c2;
- while (true) {
- if (n-- == 0) return 0;
- c1 = transformation(*s1);
- // Double check that characters are not UTF-8
- RTC_DCHECK_LT(static_cast<unsigned char>(*s2), 128);
- // Note: *s2 gets implicitly promoted to wchar_t
- c2 = transformation(*s2);
- if (c1 != c2) return (c1 < c2) ? -1 : 1;
- if (!c1) return 0;
- ++s1;
- ++s2;
- }
-}
-
-size_t asccpyn(wchar_t* buffer, size_t buflen,
- const char* source, size_t srclen) {
- if (buflen <= 0)
- return 0;
-
- if (srclen == SIZE_UNKNOWN) {
- srclen = strlenn(source, buflen - 1);
- } else if (srclen >= buflen) {
- srclen = buflen - 1;
- }
-#if !defined(NDEBUG)
- // Double check that characters are not UTF-8
- for (size_t pos = 0; pos < srclen; ++pos)
- RTC_DCHECK_LT(static_cast<unsigned char>(source[pos]), 128);
-#endif
- std::copy(source, source + srclen, buffer);
- buffer[srclen] = 0;
- return srclen;
-}
-
-#endif // WEBRTC_WIN
-
-void replace_substrs(const char *search,
- size_t search_len,
- const char *replace,
- size_t replace_len,
- std::string *s) {
- size_t pos = 0;
- while ((pos = s->find(search, pos, search_len)) != std::string::npos) {
- s->replace(pos, search_len, replace, replace_len);
- pos += replace_len;
- }
-}
-
-bool starts_with(const char *s1, const char *s2) {
- return strncmp(s1, s2, strlen(s2)) == 0;
-}
-
-bool ends_with(const char *s1, const char *s2) {
- size_t s1_length = strlen(s1);
- size_t s2_length = strlen(s2);
-
- if (s2_length > s1_length) {
- return false;
- }
-
- const char* start = s1 + (s1_length - s2_length);
- return strncmp(start, s2, s2_length) == 0;
-}
-
-static const char kWhitespace[] = " \n\r\t";
-
-std::string string_trim(const std::string& s) {
- std::string::size_type first = s.find_first_not_of(kWhitespace);
- std::string::size_type last = s.find_last_not_of(kWhitespace);
-
- if (first == std::string::npos || last == std::string::npos) {
- return std::string("");
- }
-
- return s.substr(first, last - first + 1);
-}
-
-} // namespace rtc
diff --git a/webrtc/base/stringutils.h b/webrtc/base/stringutils.h
deleted file mode 100644
index 5a6f42a..0000000
--- a/webrtc/base/stringutils.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_BASE_STRINGUTILS_H__
-#define WEBRTC_BASE_STRINGUTILS_H__
-
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#if defined(WEBRTC_WIN)
-#include <malloc.h>
-#include <wchar.h>
-#define alloca _alloca
-#endif // WEBRTC_WIN
-
-#if defined(WEBRTC_POSIX)
-#ifdef BSD
-#include <stdlib.h>
-#else // BSD
-#include <alloca.h>
-#endif // !BSD
-#endif // WEBRTC_POSIX
-
-#include <string>
-
-#include "webrtc/base/basictypes.h"
-
-///////////////////////////////////////////////////////////////////////////////
-// Generic string/memory utilities
-///////////////////////////////////////////////////////////////////////////////
-
-#define STACK_ARRAY(TYPE, LEN) static_cast<TYPE*>(::alloca((LEN)*sizeof(TYPE)))
-
-namespace rtc {
-
-// Complement to memset. Verifies memory consists of count bytes of value c.
-bool memory_check(const void* memory, int c, size_t count);
-
-// Determines whether the simple wildcard pattern matches target.
-// Alpha characters in pattern match case-insensitively.
-// Asterisks in pattern match 0 or more characters.
-// Ex: string_match("www.TEST.GOOGLE.COM", "www.*.com") -> true
-bool string_match(const char* target, const char* pattern);
-
-} // namespace rtc
-
-///////////////////////////////////////////////////////////////////////////////
-// Rename a bunch of common string functions so they are consistent across
-// platforms and between char and wchar_t variants.
-// Here is the full list of functions that are unified:
-// strlen, strcmp, stricmp, strncmp, strnicmp
-// strchr, vsnprintf, strtoul, tolowercase
-// tolowercase is like tolower, but not compatible with end-of-file value
-//
-// It's not clear if we will ever use wchar_t strings on unix. In theory,
-// all strings should be Utf8 all the time, except when interfacing with Win32
-// APIs that require Utf16.
-///////////////////////////////////////////////////////////////////////////////
-
-inline char tolowercase(char c) {
- return static_cast<char>(tolower(c));
-}
-
-#if defined(WEBRTC_WIN)
-
-inline size_t strlen(const wchar_t* s) {
- return wcslen(s);
-}
-inline int strcmp(const wchar_t* s1, const wchar_t* s2) {
- return wcscmp(s1, s2);
-}
-inline int stricmp(const wchar_t* s1, const wchar_t* s2) {
- return _wcsicmp(s1, s2);
-}
-inline int strncmp(const wchar_t* s1, const wchar_t* s2, size_t n) {
- return wcsncmp(s1, s2, n);
-}
-inline int strnicmp(const wchar_t* s1, const wchar_t* s2, size_t n) {
- return _wcsnicmp(s1, s2, n);
-}
-inline const wchar_t* strchr(const wchar_t* s, wchar_t c) {
- return wcschr(s, c);
-}
-inline const wchar_t* strstr(const wchar_t* haystack, const wchar_t* needle) {
- return wcsstr(haystack, needle);
-}
-#ifndef vsnprintf
-inline int vsnprintf(wchar_t* buf, size_t n, const wchar_t* fmt, va_list args) {
- return _vsnwprintf(buf, n, fmt, args);
-}
-#endif // !vsnprintf
-inline unsigned long strtoul(const wchar_t* snum, wchar_t** end, int base) {
- return wcstoul(snum, end, base);
-}
-inline wchar_t tolowercase(wchar_t c) {
- return static_cast<wchar_t>(towlower(c));
-}
-
-#endif // WEBRTC_WIN
-
-#if defined(WEBRTC_POSIX)
-
-inline int _stricmp(const char* s1, const char* s2) {
- return strcasecmp(s1, s2);
-}
-inline int _strnicmp(const char* s1, const char* s2, size_t n) {
- return strncasecmp(s1, s2, n);
-}
-
-#endif // WEBRTC_POSIX
-
-///////////////////////////////////////////////////////////////////////////////
-// Traits simplifies porting string functions to be CTYPE-agnostic
-///////////////////////////////////////////////////////////////////////////////
-
-namespace rtc {
-
-const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
-
-template<class CTYPE>
-struct Traits {
- // STL string type
- //typedef XXX string;
- // Null-terminated string
- //inline static const CTYPE* empty_str();
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// String utilities which work with char or wchar_t
-///////////////////////////////////////////////////////////////////////////////
-
-template<class CTYPE>
-inline const CTYPE* nonnull(const CTYPE* str, const CTYPE* def_str = NULL) {
- return str ? str : (def_str ? def_str : Traits<CTYPE>::empty_str());
-}
-
-template<class CTYPE>
-const CTYPE* strchr(const CTYPE* str, const CTYPE* chs) {
- for (size_t i=0; str[i]; ++i) {
- for (size_t j=0; chs[j]; ++j) {
- if (str[i] == chs[j]) {
- return str + i;
- }
- }
- }
- return 0;
-}
-
-template<class CTYPE>
-const CTYPE* strchrn(const CTYPE* str, size_t slen, CTYPE ch) {
- for (size_t i=0; i<slen && str[i]; ++i) {
- if (str[i] == ch) {
- return str + i;
- }
- }
- return 0;
-}
-
-template<class CTYPE>
-size_t strlenn(const CTYPE* buffer, size_t buflen) {
- size_t bufpos = 0;
- while (buffer[bufpos] && (bufpos < buflen)) {
- ++bufpos;
- }
- return bufpos;
-}
-
-// Safe versions of strncpy, strncat, snprintf and vsnprintf that always
-// null-terminate.
-
-template<class CTYPE>
-size_t strcpyn(CTYPE* buffer, size_t buflen,
- const CTYPE* source, size_t srclen = SIZE_UNKNOWN) {
- if (buflen <= 0)
- return 0;
-
- if (srclen == SIZE_UNKNOWN) {
- srclen = strlenn(source, buflen - 1);
- } else if (srclen >= buflen) {
- srclen = buflen - 1;
- }
- memcpy(buffer, source, srclen * sizeof(CTYPE));
- buffer[srclen] = 0;
- return srclen;
-}
-
-template<class CTYPE>
-size_t strcatn(CTYPE* buffer, size_t buflen,
- const CTYPE* source, size_t srclen = SIZE_UNKNOWN) {
- if (buflen <= 0)
- return 0;
-
- size_t bufpos = strlenn(buffer, buflen - 1);
- return bufpos + strcpyn(buffer + bufpos, buflen - bufpos, source, srclen);
-}
-
-// Some compilers (clang specifically) require vsprintfn be defined before
-// sprintfn.
-template<class CTYPE>
-size_t vsprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format,
- va_list args) {
- int len = vsnprintf(buffer, buflen, format, args);
- if ((len < 0) || (static_cast<size_t>(len) >= buflen)) {
- len = static_cast<int>(buflen - 1);
- buffer[len] = 0;
- }
- return len;
-}
-
-template<class CTYPE>
-size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...);
-template<class CTYPE>
-size_t sprintfn(CTYPE* buffer, size_t buflen, const CTYPE* format, ...) {
- va_list args;
- va_start(args, format);
- size_t len = vsprintfn(buffer, buflen, format, args);
- va_end(args);
- return len;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Allow safe comparing and copying ascii (not UTF-8) with both wide and
-// non-wide character strings.
-///////////////////////////////////////////////////////////////////////////////
-
-inline int asccmp(const char* s1, const char* s2) {
- return strcmp(s1, s2);
-}
-inline int ascicmp(const char* s1, const char* s2) {
- return _stricmp(s1, s2);
-}
-inline int ascncmp(const char* s1, const char* s2, size_t n) {
- return strncmp(s1, s2, n);
-}
-inline int ascnicmp(const char* s1, const char* s2, size_t n) {
- return _strnicmp(s1, s2, n);
-}
-inline size_t asccpyn(char* buffer, size_t buflen,
- const char* source, size_t srclen = SIZE_UNKNOWN) {
- return strcpyn(buffer, buflen, source, srclen);
-}
-
-#if defined(WEBRTC_WIN)
-
-typedef wchar_t(*CharacterTransformation)(wchar_t);
-inline wchar_t identity(wchar_t c) { return c; }
-int ascii_string_compare(const wchar_t* s1, const char* s2, size_t n,
- CharacterTransformation transformation);
-
-inline int asccmp(const wchar_t* s1, const char* s2) {
- return ascii_string_compare(s1, s2, static_cast<size_t>(-1), identity);
-}
-inline int ascicmp(const wchar_t* s1, const char* s2) {
- return ascii_string_compare(s1, s2, static_cast<size_t>(-1), tolowercase);
-}
-inline int ascncmp(const wchar_t* s1, const char* s2, size_t n) {
- return ascii_string_compare(s1, s2, n, identity);
-}
-inline int ascnicmp(const wchar_t* s1, const char* s2, size_t n) {
- return ascii_string_compare(s1, s2, n, tolowercase);
-}
-size_t asccpyn(wchar_t* buffer, size_t buflen,
- const char* source, size_t srclen = SIZE_UNKNOWN);
-
-#endif // WEBRTC_WIN
-
-///////////////////////////////////////////////////////////////////////////////
-// Traits<char> specializations
-///////////////////////////////////////////////////////////////////////////////
-
-template<>
-struct Traits<char> {
- typedef std::string string;
- inline static const char* empty_str() { return ""; }
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Traits<wchar_t> specializations (Windows only, currently)
-///////////////////////////////////////////////////////////////////////////////
-
-#if defined(WEBRTC_WIN)
-
-template<>
-struct Traits<wchar_t> {
- typedef std::wstring string;
- inline static const wchar_t* empty_str() { return L""; }
-};
-
-#endif // WEBRTC_WIN
-
-// Replaces all occurrences of "search" with "replace".
-void replace_substrs(const char *search,
- size_t search_len,
- const char *replace,
- size_t replace_len,
- std::string *s);
-
-// True iff s1 starts with s2.
-bool starts_with(const char *s1, const char *s2);
-
-// True iff s1 ends with s2.
-bool ends_with(const char *s1, const char *s2);
-
-// Remove leading and trailing whitespaces.
-std::string string_trim(const std::string& s);
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_STRINGUTILS_H__
diff --git a/webrtc/base/template_util.h b/webrtc/base/template_util.h
deleted file mode 100644
index 31464cf..0000000
--- a/webrtc/base/template_util.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Borrowed from Chromium's src/base/template_util.h.
-
-#ifndef WEBRTC_BASE_TEMPLATE_UTIL_H_
-#define WEBRTC_BASE_TEMPLATE_UTIL_H_
-
-#include <stddef.h> // For size_t.
-
-namespace rtc {
-
-// Template definitions from tr1.
-
-template<class T, T v>
-struct integral_constant {
- static const T value = v;
- typedef T value_type;
- typedef integral_constant<T, v> type;
-};
-
-template <class T, T v> const T integral_constant<T, v>::value;
-
-typedef integral_constant<bool, true> true_type;
-typedef integral_constant<bool, false> false_type;
-
-template <class T> struct is_pointer : false_type {};
-template <class T> struct is_pointer<T*> : true_type {};
-
-template <class T, class U> struct is_same : public false_type {};
-template <class T> struct is_same<T, T> : true_type {};
-
-template<class> struct is_array : public false_type {};
-template<class T, size_t n> struct is_array<T[n]> : public true_type {};
-template<class T> struct is_array<T[]> : public true_type {};
-
-template <class T> struct is_non_const_reference : false_type {};
-template <class T> struct is_non_const_reference<T&> : true_type {};
-template <class T> struct is_non_const_reference<const T&> : false_type {};
-
-template <class T> struct is_void : false_type {};
-template <> struct is_void<void> : true_type {};
-
-template <class T>
-struct remove_reference {
- typedef T type;
-};
-template <class T>
-struct remove_reference<T&> {
- typedef T type;
-};
-template <class T>
-struct remove_reference<T&&> {
- typedef T type;
-};
-
-namespace internal {
-
-// Types YesType and NoType are guaranteed such that sizeof(YesType) <
-// sizeof(NoType).
-typedef char YesType;
-
-struct NoType {
- YesType dummy[2];
-};
-
-// This class is an implementation detail for is_convertible, and you
-// don't need to know how it works to use is_convertible. For those
-// who care: we declare two different functions, one whose argument is
-// of type To and one with a variadic argument list. We give them
-// return types of different size, so we can use sizeof to trick the
-// compiler into telling us which function it would have chosen if we
-// had called it with an argument of type From. See Alexandrescu's
-// _Modern C++ Design_ for more details on this sort of trick.
-
-struct ConvertHelper {
- template <typename To>
- static YesType Test(To);
-
- template <typename To>
- static NoType Test(...);
-
- template <typename From>
- static From& Create();
-};
-
-// Used to determine if a type is a struct/union/class. Inspired by Boost's
-// is_class type_trait implementation.
-struct IsClassHelper {
- template <typename C>
- static YesType Test(void(C::*)(void));
-
- template <typename C>
- static NoType Test(...);
-};
-
-} // namespace internal
-
-// Inherits from true_type if From is convertible to To, false_type otherwise.
-//
-// Note that if the type is convertible, this will be a true_type REGARDLESS
-// of whether or not the conversion would emit a warning.
-template <typename From, typename To>
-struct is_convertible
- : integral_constant<bool,
- sizeof(internal::ConvertHelper::Test<To>(
- internal::ConvertHelper::Create<From>())) ==
- sizeof(internal::YesType)> {
-};
-
-template <typename T>
-struct is_class
- : integral_constant<bool,
- sizeof(internal::IsClassHelper::Test<T>(0)) ==
- sizeof(internal::YesType)> {
-};
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_TEMPLATE_UTIL_H_
diff --git a/webrtc/base/thread_annotations.h b/webrtc/base/thread_annotations.h
deleted file mode 100644
index 612242d..0000000
--- a/webrtc/base/thread_annotations.h
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-//
-// Borrowed from
-// https://code.google.com/p/gperftools/source/browse/src/base/thread_annotations.h
-// but adapted for clang attributes instead of the gcc.
-//
-// This header file contains the macro definitions for thread safety
-// annotations that allow the developers to document the locking policies
-// of their multi-threaded code. The annotations can also help program
-// analysis tools to identify potential thread safety issues.
-
-#ifndef BASE_THREAD_ANNOTATIONS_H_
-#define BASE_THREAD_ANNOTATIONS_H_
-
-#if defined(__clang__) && (!defined(SWIG))
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
-#else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
-#endif
-
-// Document if a shared variable/field needs to be protected by a lock.
-// GUARDED_BY allows the user to specify a particular lock that should be
-// held when accessing the annotated variable, while GUARDED_VAR only
-// indicates a shared variable should be guarded (by any lock). GUARDED_VAR
-// is primarily used when the client cannot express the name of the lock.
-#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
-#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded)
-
-// Document if the memory location pointed to by a pointer should be guarded
-// by a lock when dereferencing the pointer. Similar to GUARDED_VAR,
-// PT_GUARDED_VAR is primarily used when the client cannot express the name
-// of the lock. Note that a pointer variable to a shared memory location
-// could itself be a shared variable. For example, if a shared global pointer
-// q, which is guarded by mu1, points to a shared memory location that is
-// guarded by mu2, q should be annotated as follows:
-// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
-#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded_by(x))
-#define PT_GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded)
-
-// Document the acquisition order between locks that can be held
-// simultaneously by a thread. For any two locks that need to be annotated
-// to establish an acquisition order, only one of them needs the annotation.
-// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
-// and ACQUIRED_BEFORE.)
-#define ACQUIRED_AFTER(x) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x))
-#define ACQUIRED_BEFORE(x) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x))
-
-// The following three annotations document the lock requirements for
-// functions/methods.
-
-// Document if a function expects certain locks to be held before it is called
-#define EXCLUSIVE_LOCKS_REQUIRED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
-
-#define SHARED_LOCKS_REQUIRED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
-
-// Document the locks acquired in the body of the function. These locks
-// cannot be held when calling this function (as google3's Mutex locks are
-// non-reentrant).
-#define LOCKS_EXCLUDED(x) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(x))
-
-// Document the lock the annotated function returns without acquiring it.
-#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
-
-// Document if a class/type is a lockable type (such as the Mutex class).
-#define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable)
-
-// Document if a class is a scoped lockable type (such as the MutexLock class).
-#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
-
-// The following annotations specify lock and unlock primitives.
-#define EXCLUSIVE_LOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
-
-#define SHARED_LOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
-
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
-
-#define SHARED_TRYLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
-
-#define UNLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
-
-// An escape hatch for thread safety analysis to ignore the annotated function.
-#define NO_THREAD_SAFETY_ANALYSIS \
- THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
-
-#endif // BASE_THREAD_ANNOTATIONS_H_
diff --git a/webrtc/base/thread_checker.h b/webrtc/base/thread_checker.h
deleted file mode 100644
index 6cd7d7b..0000000
--- a/webrtc/base/thread_checker.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Borrowed from Chromium's src/base/threading/thread_checker.h.
-
-#ifndef WEBRTC_BASE_THREAD_CHECKER_H_
-#define WEBRTC_BASE_THREAD_CHECKER_H_
-
-// Apart from debug builds, we also enable the thread checker in
-// builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots
-// with this define will get the same level of thread checking as
-// debug bots.
-//
-// Note that this does not perfectly match situations where RTC_DCHECK is
-// enabled. For example a non-official release build may have
-// DCHECK_ALWAYS_ON undefined (and therefore ThreadChecker would be
-// disabled) but have RTC_DCHECKs enabled at runtime.
-#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
-#define ENABLE_THREAD_CHECKER 1
-#else
-#define ENABLE_THREAD_CHECKER 0
-#endif
-
-#include "webrtc/base/thread_checker_impl.h"
-
-namespace rtc {
-
-// Do nothing implementation, for use in release mode.
-//
-// Note: You should almost always use the ThreadChecker class to get the
-// right version for your build configuration.
-class ThreadCheckerDoNothing {
- public:
- bool CalledOnValidThread() const {
- return true;
- }
-
- void DetachFromThread() {}
-};
-
-// ThreadChecker is a helper class used to help verify that some methods of a
-// class are called from the same thread. It provides identical functionality to
-// base::NonThreadSafe, but it is meant to be held as a member variable, rather
-// than inherited from base::NonThreadSafe.
-//
-// While inheriting from base::NonThreadSafe may give a clear indication about
-// the thread-safety of a class, it may also lead to violations of the style
-// guide with regard to multiple inheritance. The choice between having a
-// ThreadChecker member and inheriting from base::NonThreadSafe should be based
-// on whether:
-// - Derived classes need to know the thread they belong to, as opposed to
-// having that functionality fully encapsulated in the base class.
-// - Derived classes should be able to reassign the base class to another
-// thread, via DetachFromThread.
-//
-// If neither of these are true, then having a ThreadChecker member and calling
-// CalledOnValidThread is the preferable solution.
-//
-// Example:
-// class MyClass {
-// public:
-// void Foo() {
-// RTC_DCHECK(thread_checker_.CalledOnValidThread());
-// ... (do stuff) ...
-// }
-//
-// private:
-// ThreadChecker thread_checker_;
-// }
-//
-// In Release mode, CalledOnValidThread will always return true.
-#if ENABLE_THREAD_CHECKER
-class ThreadChecker : public ThreadCheckerImpl {
-};
-#else
-class ThreadChecker : public ThreadCheckerDoNothing {
-};
-#endif // ENABLE_THREAD_CHECKER
-
-#undef ENABLE_THREAD_CHECKER
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_THREAD_CHECKER_H_
diff --git a/webrtc/base/thread_checker_impl.cc b/webrtc/base/thread_checker_impl.cc
deleted file mode 100644
index ea88308..0000000
--- a/webrtc/base/thread_checker_impl.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Borrowed from Chromium's src/base/threading/thread_checker_impl.cc.
-
-#include "webrtc/base/thread_checker_impl.h"
-
-namespace rtc {
-
-ThreadCheckerImpl::ThreadCheckerImpl() : valid_thread_(CurrentThreadRef()) {
-}
-
-ThreadCheckerImpl::~ThreadCheckerImpl() {
-}
-
-bool ThreadCheckerImpl::CalledOnValidThread() const {
- const PlatformThreadRef current_thread = CurrentThreadRef();
- CritScope scoped_lock(&lock_);
- if (!valid_thread_) // Set if previously detached.
- valid_thread_ = current_thread;
- return IsThreadRefEqual(valid_thread_, current_thread);
-}
-
-void ThreadCheckerImpl::DetachFromThread() {
- CritScope scoped_lock(&lock_);
- valid_thread_ = 0;
-}
-
-} // namespace rtc
diff --git a/webrtc/base/thread_checker_impl.h b/webrtc/base/thread_checker_impl.h
deleted file mode 100644
index 7b39ada..0000000
--- a/webrtc/base/thread_checker_impl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Borrowed from Chromium's src/base/threading/thread_checker_impl.h.
-
-#ifndef WEBRTC_BASE_THREAD_CHECKER_IMPL_H_
-#define WEBRTC_BASE_THREAD_CHECKER_IMPL_H_
-
-#include "webrtc/base/criticalsection.h"
-#include "webrtc/base/platform_thread.h"
-
-namespace rtc {
-
-// Real implementation of ThreadChecker, for use in debug mode, or
-// for temporary use in release mode (e.g. to RTC_CHECK on a threading issue
-// seen only in the wild).
-//
-// Note: You should almost always use the ThreadChecker class to get the
-// right version for your build configuration.
-class ThreadCheckerImpl {
- public:
- ThreadCheckerImpl();
- ~ThreadCheckerImpl();
-
- bool CalledOnValidThread() const;
-
- // Changes the thread that is checked for in CalledOnValidThread. This may
- // be useful when an object may be created on one thread and then used
- // exclusively on another thread.
- void DetachFromThread();
-
- private:
- mutable CriticalSection lock_;
- // This is mutable so that CalledOnValidThread can set it.
- // It's guarded by |lock_|.
- mutable PlatformThreadRef valid_thread_;
-};
-
-} // namespace rtc
-
-#endif // WEBRTC_BASE_THREAD_CHECKER_IMPL_H_
diff --git a/webrtc/base/win32.h b/webrtc/base/win32.h
deleted file mode 100644
index 6969c10..0000000
--- a/webrtc/base/win32.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2004 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-#ifndef WEBRTC_BASE_WIN32_H_
-#define WEBRTC_BASE_WIN32_H_
-#if defined(WEBRTC_WIN)
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
-// Make sure we don't get min/max macros
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include <winsock2.h>
-#include <windows.h>
-#ifndef SECURITY_MANDATORY_LABEL_AUTHORITY
-// Add defines that we use if we are compiling against older sdks
-#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
-#define TokenIntegrityLevel static_cast<TOKEN_INFORMATION_CLASS>(0x19)
-typedef struct _TOKEN_MANDATORY_LABEL {
- SID_AND_ATTRIBUTES Label;
-} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
-#endif // SECURITY_MANDATORY_LABEL_AUTHORITY
-#undef SetPort
-#include <string>
-#include "webrtc/base/stringutils.h"
-#include "webrtc/base/basictypes.h"
-namespace rtc {
-const char* win32_inet_ntop(int af, const void *src, char* dst, socklen_t size);
-int win32_inet_pton(int af, const char* src, void *dst);
-inline std::wstring ToUtf16(const char* utf8, size_t len) {
- int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len),
- NULL, 0);
- wchar_t* ws = STACK_ARRAY(wchar_t, len16);
- ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len), ws, len16);
- return std::wstring(ws, len16);
-}
-inline std::wstring ToUtf16(const std::string& str) {
- return ToUtf16(str.data(), str.length());
-}
-inline std::string ToUtf8(const wchar_t* wide, size_t len) {
- int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len),
- NULL, 0, NULL, NULL);
- char* ns = STACK_ARRAY(char, len8);
- ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len), ns, len8,
- NULL, NULL);
- return std::string(ns, len8);
-}
-inline std::string ToUtf8(const wchar_t* wide) {
- return ToUtf8(wide, wcslen(wide));
-}
-inline std::string ToUtf8(const std::wstring& wstr) {
- return ToUtf8(wstr.data(), wstr.length());
-}
-// Convert FILETIME to time_t
-void FileTimeToUnixTime(const FILETIME& ft, time_t* ut);
-// Convert time_t to FILETIME
-void UnixTimeToFileTime(const time_t& ut, FILETIME * ft);
-// Convert a Utf8 path representation to a non-length-limited Unicode pathname.
-bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename);
-// Convert a FILETIME to a UInt64
-inline uint64_t ToUInt64(const FILETIME& ft) {
- ULARGE_INTEGER r = {{ft.dwLowDateTime, ft.dwHighDateTime}};
- return r.QuadPart;
-}
-enum WindowsMajorVersions {
- kWindows2000 = 5,
- kWindowsVista = 6,
-};
-bool GetOsVersion(int* major, int* minor, int* build);
-inline bool IsWindowsVistaOrLater() {
- int major;
- return (GetOsVersion(&major, NULL, NULL) && major >= kWindowsVista);
-}
-inline bool IsWindowsXpOrLater() {
- int major, minor;
- return (GetOsVersion(&major, &minor, NULL) &&
- (major >= kWindowsVista ||
- (major == kWindows2000 && minor >= 1)));
-}
-inline bool IsWindows8OrLater() {
- int major, minor;
- return (GetOsVersion(&major, &minor, NULL) &&
- (major > kWindowsVista ||
- (major == kWindowsVista && minor >= 2)));
-}
-// Determine the current integrity level of the process.
-bool GetCurrentProcessIntegrityLevel(int* level);
-inline bool IsCurrentProcessLowIntegrity() {
- int level;
- return (GetCurrentProcessIntegrityLevel(&level) &&
- level < SECURITY_MANDATORY_MEDIUM_RID);
-}
-bool AdjustCurrentProcessPrivilege(const TCHAR* privilege, bool to_enable);
-} // namespace rtc
-#endif // WEBRTC_WIN
-#endif // WEBRTC_BASE_WIN32_H_
diff --git a/webrtc/common_audio/BUILD.gn b/webrtc/common_audio/BUILD.gn
index b01b318..a03e9ab 100644
--- a/webrtc/common_audio/BUILD.gn
+++ b/webrtc/common_audio/BUILD.gn
@@ -6,37 +6,19 @@
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
-import("//build/config/arm.gni")
-import("../build/webrtc.gni")
-
-config("common_audio_config") {
- include_dirs = [
- "resampler/include",
- "signal_processing/include",
- "vad/include",
- ]
-}
+import("../webrtc.gni")
+
+visibility = [ ":*" ]
-source_set("common_audio") {
+rtc_library("common_audio") {
+ visibility += [ "*" ]
sources = [
"audio_converter.cc",
"audio_converter.h",
- "audio_ring_buffer.cc",
- "audio_ring_buffer.h",
"audio_util.cc",
- "blocker.cc",
- "blocker.h",
"channel_buffer.cc",
"channel_buffer.h",
- "fft4g.c",
- "fft4g.h",
- "fir_filter.cc",
- "fir_filter.h",
- "fir_filter_neon.h",
- "fir_filter_sse.h",
"include/audio_util.h",
- "lapped_transform.cc",
- "lapped_transform.h",
"real_fourier.cc",
"real_fourier.h",
"real_fourier_ooura.cc",
@@ -48,7 +30,77 @@ source_set("common_audio") {
"resampler/push_sinc_resampler.h",
"resampler/resampler.cc",
"resampler/sinc_resampler.cc",
- "resampler/sinc_resampler.h",
+ "smoothing_filter.cc",
+ "smoothing_filter.h",
+ "vad/include/vad.h",
+ "vad/vad.cc",
+ "wav_file.cc",
+ "wav_file.h",
+ "wav_header.cc",
+ "wav_header.h",
+ "window_generator.cc",
+ "window_generator.h",
+ ]
+
+ deps = [
+ ":common_audio_c",
+ ":sinc_resampler",
+ "../api:array_view",
+ "../rtc_base:checks",
+ "../rtc_base:gtest_prod",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base:sanitizer",
+ "../rtc_base/memory:aligned_malloc",
+ "../rtc_base/system:arch",
+ "../rtc_base/system:file_wrapper",
+ "../system_wrappers",
+ "third_party/ooura:fft_size_256",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+
+ defines = []
+
+ if (rtc_build_with_neon) {
+ deps += [ ":common_audio_neon" ]
+ }
+
+ if (current_cpu == "x86" || current_cpu == "x64") {
+ deps += [ ":common_audio_sse2" ]
+ deps += [ ":common_audio_avx2" ]
+ }
+}
+
+rtc_source_set("mock_common_audio") {
+ visibility += webrtc_default_visibility
+ testonly = true
+ sources = [
+ "mocks/mock_smoothing_filter.h",
+ "vad/mock/mock_vad.h",
+ ]
+ deps = [
+ ":common_audio",
+ "../test:test_support",
+ ]
+}
+
+rtc_source_set("common_audio_c_arm_asm") {
+ sources = []
+ deps = []
+ if (current_cpu == "arm") {
+ sources += [ "signal_processing/complex_bit_reverse_arm.S" ]
+
+ if (arm_version >= 7) {
+ sources += [ "signal_processing/filter_ar_fast_q12_armv7.S" ]
+ } else {
+ sources += [ "signal_processing/filter_ar_fast_q12.c" ]
+ }
+ deps += [ "../rtc_base/system:asm_defines" ]
+ }
+}
+
+rtc_library("common_audio_c") {
+ visibility += webrtc_default_visibility
+ sources = [
"ring_buffer.c",
"ring_buffer.h",
"signal_processing/auto_corr_to_refl_coef.c",
@@ -57,7 +109,6 @@ source_set("common_audio") {
"signal_processing/copy_set_operations.c",
"signal_processing/cross_correlation.c",
"signal_processing/division_operations.c",
- "signal_processing/dot_product_with_scale.c",
"signal_processing/downsample_fast.c",
"signal_processing/energy.c",
"signal_processing/filter_ar.c",
@@ -68,6 +119,7 @@ source_set("common_audio") {
"signal_processing/include/real_fft.h",
"signal_processing/include/signal_processing_library.h",
"signal_processing/include/spl_inl.h",
+ "signal_processing/include/spl_inl_armv7.h",
"signal_processing/levinson_durbin.c",
"signal_processing/lpc_to_refl_coef.c",
"signal_processing/min_max_operations.c",
@@ -81,15 +133,12 @@ source_set("common_audio") {
"signal_processing/resample_by_2_internal.h",
"signal_processing/resample_fractional.c",
"signal_processing/spl_init.c",
+ "signal_processing/spl_inl.c",
"signal_processing/spl_sqrt.c",
"signal_processing/splitting_filter.c",
"signal_processing/sqrt_of_one_minus_x_squared.c",
"signal_processing/vector_scaling_operations.c",
- "sparse_fir_filter.cc",
- "sparse_fir_filter.h",
- "vad/include/vad.h",
"vad/include/webrtc_vad.h",
- "vad/vad.cc",
"vad/vad_core.c",
"vad/vad_core.h",
"vad/vad_filterbank.c",
@@ -99,47 +148,8 @@ source_set("common_audio") {
"vad/vad_sp.c",
"vad/vad_sp.h",
"vad/webrtc_vad.c",
- "wav_file.cc",
- "wav_file.h",
- "wav_header.cc",
- "wav_header.h",
- "window_generator.cc",
- "window_generator.h",
]
- deps = [
- "../system_wrappers",
- ]
-
- defines = []
- if (rtc_use_openmax_dl) {
- sources += [
- "real_fourier_openmax.cc",
- "real_fourier_openmax.h",
- ]
- defines += [ "RTC_USE_OPENMAX_DL" ]
- if (rtc_build_openmax_dl) {
- deps += [ "//third_party/openmax_dl/dl" ]
- }
- }
-
- if (current_cpu == "arm") {
- sources += [
- "signal_processing/complex_bit_reverse_arm.S",
- "signal_processing/spl_sqrt_floor_arm.S",
- ]
-
- if (arm_version >= 7) {
- sources += [ "signal_processing/filter_ar_fast_q12_armv7.S" ]
- } else {
- sources += [ "signal_processing/filter_ar_fast_q12.c" ]
- }
- }
-
- if (rtc_build_with_neon) {
- deps += [ ":common_audio_neon" ]
- }
-
if (current_cpu == "mipsel") {
sources += [
"signal_processing/complex_bit_reverse_mips.c",
@@ -150,7 +160,6 @@ source_set("common_audio") {
"signal_processing/include/spl_inl_mips.h",
"signal_processing/min_max_operations_mips.c",
"signal_processing/resample_by_2_mips.c",
- "signal_processing/spl_sqrt_floor_mips.c",
]
if (mips_dsp_rev > 0) {
sources += [ "signal_processing/vector_scaling_operations_mips.c" ]
@@ -163,81 +172,227 @@ source_set("common_audio") {
sources += [
"signal_processing/complex_bit_reverse.c",
"signal_processing/filter_ar_fast_q12.c",
- "signal_processing/spl_sqrt_floor.c",
]
}
- if (is_win) {
- cflags = [ "/wd4334" ] # Ignore warning on shift operator promotion.
- }
+ deps = [
+ ":common_audio_c_arm_asm",
+ ":common_audio_cc",
+ "../rtc_base:checks",
+ "../rtc_base:compile_assert_c",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base:sanitizer",
+ "../rtc_base/system:arch",
+ "../system_wrappers",
+ "third_party/ooura:fft_size_256",
+ "third_party/spl_sqrt_floor",
+ ]
+}
+
+rtc_library("common_audio_cc") {
+ sources = [
+ "signal_processing/dot_product_with_scale.cc",
+ "signal_processing/dot_product_with_scale.h",
+ ]
- configs += [ "..:common_config" ]
+ deps = [
+ "../rtc_base:rtc_base_approved",
+ "../system_wrappers",
+ ]
+}
- public_configs = [
- "..:common_inherited_config",
- ":common_audio_config",
+rtc_source_set("sinc_resampler") {
+ sources = [ "resampler/sinc_resampler.h" ]
+ deps = [
+ "../rtc_base:gtest_prod",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base/memory:aligned_malloc",
+ "../rtc_base/system:arch",
+ "../system_wrappers",
]
+}
- if (is_clang) {
- # Suppress warnings from Chrome's Clang plugins.
- # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
- configs -= [ "//build/config/clang:find_bad_constructs" ]
- }
+rtc_source_set("fir_filter") {
+ visibility += webrtc_default_visibility
+ sources = [ "fir_filter.h" ]
+}
+rtc_library("fir_filter_factory") {
+ visibility += webrtc_default_visibility
+ sources = [
+ "fir_filter_c.cc",
+ "fir_filter_c.h",
+ "fir_filter_factory.cc",
+ "fir_filter_factory.h",
+ ]
+ deps = [
+ ":fir_filter",
+ "../rtc_base:checks",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base/system:arch",
+ "../system_wrappers",
+ ]
if (current_cpu == "x86" || current_cpu == "x64") {
deps += [ ":common_audio_sse2" ]
+ deps += [ ":common_audio_avx2" ]
+ }
+ if (rtc_build_with_neon) {
+ deps += [ ":common_audio_neon" ]
}
}
if (current_cpu == "x86" || current_cpu == "x64") {
- source_set("common_audio_sse2") {
+ rtc_library("common_audio_sse2") {
sources = [
"fir_filter_sse.cc",
+ "fir_filter_sse.h",
"resampler/sinc_resampler_sse.cc",
]
- if (is_posix) {
+ if (is_posix || is_fuchsia) {
cflags = [ "-msse2" ]
}
- configs += [ "..:common_inherited_config" ]
+ deps = [
+ ":fir_filter",
+ ":sinc_resampler",
+ "../rtc_base:checks",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base/memory:aligned_malloc",
+ ]
+ }
- if (is_clang) {
- # Suppress warnings from Chrome's Clang plugins.
- # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
- configs -= [ "//build/config/clang:find_bad_constructs" ]
+ rtc_library("common_audio_avx2") {
+ sources = [
+ "fir_filter_avx2.cc",
+ "fir_filter_avx2.h",
+ "resampler/sinc_resampler_avx2.cc",
+ ]
+
+ if (is_win) {
+ cflags = [ "/arch:AVX2" ]
+ } else {
+ cflags = [
+ "-mavx2",
+ "-mfma",
+ ]
}
+
+ deps = [
+ ":fir_filter",
+ ":sinc_resampler",
+ "../rtc_base:checks",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base/memory:aligned_malloc",
+ ]
}
}
if (rtc_build_with_neon) {
- source_set("common_audio_neon") {
+ rtc_library("common_audio_neon") {
sources = [
"fir_filter_neon.cc",
+ "fir_filter_neon.h",
"resampler/sinc_resampler_neon.cc",
+ ]
+
+ if (current_cpu != "arm64") {
+ # Enable compilation for the NEON instruction set.
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags = [ "-mfpu=neon" ]
+ }
+
+ deps = [
+ ":common_audio_neon_c",
+ ":fir_filter",
+ ":sinc_resampler",
+ "../rtc_base:checks",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base/memory:aligned_malloc",
+ ]
+ }
+
+ rtc_library("common_audio_neon_c") {
+ visibility += webrtc_default_visibility
+ sources = [
"signal_processing/cross_correlation_neon.c",
"signal_processing/downsample_fast_neon.c",
"signal_processing/min_max_operations_neon.c",
]
if (current_cpu != "arm64") {
- # Enable compilation for the NEON instruction set. This is needed
- # since //build/config/arm.gni only enables NEON for iOS, not Android.
- # This provides the same functionality as webrtc/build/arm_neon.gypi.
- configs -= [ "//build/config/compiler:compiler_arm_fpu" ]
+ # Enable compilation for the NEON instruction set.
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
cflags = [ "-mfpu=neon" ]
}
- # Disable LTO on NEON targets due to compiler bug.
- # TODO(fdegans): Enable this. See crbug.com/408997.
- if (rtc_use_lto) {
- cflags -= [
- "-flto",
- "-ffat-lto-objects",
- ]
+ deps = [
+ ":common_audio_c",
+ "../rtc_base:checks",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base/system:arch",
+ ]
+ }
+}
+
+if (rtc_include_tests) {
+ rtc_test("common_audio_unittests") {
+ visibility += webrtc_default_visibility
+ testonly = true
+
+ sources = [
+ "audio_converter_unittest.cc",
+ "audio_util_unittest.cc",
+ "channel_buffer_unittest.cc",
+ "fir_filter_unittest.cc",
+ "real_fourier_unittest.cc",
+ "resampler/push_resampler_unittest.cc",
+ "resampler/push_sinc_resampler_unittest.cc",
+ "resampler/resampler_unittest.cc",
+ "resampler/sinusoidal_linear_chirp_source.cc",
+ "resampler/sinusoidal_linear_chirp_source.h",
+ "ring_buffer_unittest.cc",
+ "signal_processing/real_fft_unittest.cc",
+ "signal_processing/signal_processing_unittest.cc",
+ "smoothing_filter_unittest.cc",
+ "vad/vad_core_unittest.cc",
+ "vad/vad_filterbank_unittest.cc",
+ "vad/vad_gmm_unittest.cc",
+ "vad/vad_sp_unittest.cc",
+ "vad/vad_unittest.cc",
+ "vad/vad_unittest.h",
+ "wav_file_unittest.cc",
+ "wav_header_unittest.cc",
+ "window_generator_unittest.cc",
+ ]
+
+ # Does not compile on iOS for arm: webrtc:5544.
+ if (!is_ios || target_cpu != "arm") {
+ sources += [ "resampler/sinc_resampler_unittest.cc" ]
}
- configs += [ "..:common_config" ]
- public_configs = [ "..:common_inherited_config" ]
+ deps = [
+ ":common_audio",
+ ":common_audio_c",
+ ":fir_filter",
+ ":fir_filter_factory",
+ ":sinc_resampler",
+ "../rtc_base:checks",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base:rtc_base_tests_utils",
+ "../rtc_base/system:arch",
+ "../system_wrappers",
+ "../test:fileutils",
+ "../test:rtc_expect_death",
+ "../test:test_main",
+ "../test:test_support",
+ "//testing/gtest",
+ ]
+
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_support" ]
+
+ shard_timeout = 900
+ }
}
}
diff --git a/webrtc/common_audio/audio_converter.cc b/webrtc/common_audio/audio_converter.cc
index f1709ae..485ec80 100644
--- a/webrtc/common_audio/audio_converter.cc
+++ b/webrtc/common_audio/audio_converter.cc
@@ -8,32 +8,36 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/audio_converter.h"
+#include "common_audio/audio_converter.h"
#include <cstring>
+#include <memory>
+#include <utility>
+#include <vector>
-#include "webrtc/base/checks.h"
-#include "webrtc/base/safe_conversions.h"
-#include "webrtc/common_audio/channel_buffer.h"
-#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
-#include "webrtc/system_wrappers/include/scoped_vector.h"
-
-using rtc::checked_cast;
+#include "common_audio/channel_buffer.h"
+#include "common_audio/resampler/push_sinc_resampler.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
class CopyConverter : public AudioConverter {
public:
- CopyConverter(int src_channels, size_t src_frames, int dst_channels,
+ CopyConverter(size_t src_channels,
+ size_t src_frames,
+ size_t dst_channels,
size_t dst_frames)
: AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
- ~CopyConverter() override {};
+ ~CopyConverter() override {}
- void Convert(const float* const* src, size_t src_size, float* const* dst,
+ void Convert(const float* const* src,
+ size_t src_size,
+ float* const* dst,
size_t dst_capacity) override {
CheckSizes(src_size, dst_capacity);
if (src != dst) {
- for (int i = 0; i < src_channels(); ++i)
+ for (size_t i = 0; i < src_channels(); ++i)
std::memcpy(dst[i], src[i], dst_frames() * sizeof(*dst[i]));
}
}
@@ -41,17 +45,21 @@ class CopyConverter : public AudioConverter {
class UpmixConverter : public AudioConverter {
public:
- UpmixConverter(int src_channels, size_t src_frames, int dst_channels,
+ UpmixConverter(size_t src_channels,
+ size_t src_frames,
+ size_t dst_channels,
size_t dst_frames)
: AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
- ~UpmixConverter() override {};
+ ~UpmixConverter() override {}
- void Convert(const float* const* src, size_t src_size, float* const* dst,
+ void Convert(const float* const* src,
+ size_t src_size,
+ float* const* dst,
size_t dst_capacity) override {
CheckSizes(src_size, dst_capacity);
for (size_t i = 0; i < dst_frames(); ++i) {
const float value = src[0][i];
- for (int j = 0; j < dst_channels(); ++j)
+ for (size_t j = 0; j < dst_channels(); ++j)
dst[j][i] = value;
}
}
@@ -59,19 +67,22 @@ class UpmixConverter : public AudioConverter {
class DownmixConverter : public AudioConverter {
public:
- DownmixConverter(int src_channels, size_t src_frames, int dst_channels,
+ DownmixConverter(size_t src_channels,
+ size_t src_frames,
+ size_t dst_channels,
size_t dst_frames)
- : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {
- }
- ~DownmixConverter() override {};
+ : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {}
+ ~DownmixConverter() override {}
- void Convert(const float* const* src, size_t src_size, float* const* dst,
+ void Convert(const float* const* src,
+ size_t src_size,
+ float* const* dst,
size_t dst_capacity) override {
CheckSizes(src_size, dst_capacity);
float* dst_mono = dst[0];
for (size_t i = 0; i < src_frames(); ++i) {
float sum = 0;
- for (int j = 0; j < src_channels(); ++j)
+ for (size_t j = 0; j < src_channels(); ++j)
sum += src[j][i];
dst_mono[i] = sum / src_channels();
}
@@ -80,16 +91,21 @@ class DownmixConverter : public AudioConverter {
class ResampleConverter : public AudioConverter {
public:
- ResampleConverter(int src_channels, size_t src_frames, int dst_channels,
+ ResampleConverter(size_t src_channels,
+ size_t src_frames,
+ size_t dst_channels,
size_t dst_frames)
: AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {
resamplers_.reserve(src_channels);
- for (int i = 0; i < src_channels; ++i)
- resamplers_.push_back(new PushSincResampler(src_frames, dst_frames));
+ for (size_t i = 0; i < src_channels; ++i)
+ resamplers_.push_back(std::unique_ptr<PushSincResampler>(
+ new PushSincResampler(src_frames, dst_frames)));
}
- ~ResampleConverter() override {};
+ ~ResampleConverter() override {}
- void Convert(const float* const* src, size_t src_size, float* const* dst,
+ void Convert(const float* const* src,
+ size_t src_size,
+ float* const* dst,
size_t dst_capacity) override {
CheckSizes(src_size, dst_capacity);
for (size_t i = 0; i < resamplers_.size(); ++i)
@@ -97,69 +113,73 @@ class ResampleConverter : public AudioConverter {
}
private:
- ScopedVector<PushSincResampler> resamplers_;
+ std::vector<std::unique_ptr<PushSincResampler>> resamplers_;
};
// Apply a vector of converters in serial, in the order given. At least two
// converters must be provided.
class CompositionConverter : public AudioConverter {
public:
- CompositionConverter(ScopedVector<AudioConverter> converters)
- : converters_(converters.Pass()) {
- RTC_CHECK_GE(converters_.size(), 2u);
+ explicit CompositionConverter(
+ std::vector<std::unique_ptr<AudioConverter>> converters)
+ : converters_(std::move(converters)) {
+ RTC_CHECK_GE(converters_.size(), 2);
// We need an intermediate buffer after every converter.
for (auto it = converters_.begin(); it != converters_.end() - 1; ++it)
- buffers_.push_back(new ChannelBuffer<float>((*it)->dst_frames(),
- (*it)->dst_channels()));
+ buffers_.push_back(
+ std::unique_ptr<ChannelBuffer<float>>(new ChannelBuffer<float>(
+ (*it)->dst_frames(), (*it)->dst_channels())));
}
- ~CompositionConverter() override {};
+ ~CompositionConverter() override {}
- void Convert(const float* const* src, size_t src_size, float* const* dst,
+ void Convert(const float* const* src,
+ size_t src_size,
+ float* const* dst,
size_t dst_capacity) override {
converters_.front()->Convert(src, src_size, buffers_.front()->channels(),
buffers_.front()->size());
for (size_t i = 2; i < converters_.size(); ++i) {
- auto src_buffer = buffers_[i - 2];
- auto dst_buffer = buffers_[i - 1];
- converters_[i]->Convert(src_buffer->channels(),
- src_buffer->size(),
- dst_buffer->channels(),
- dst_buffer->size());
+ auto& src_buffer = buffers_[i - 2];
+ auto& dst_buffer = buffers_[i - 1];
+ converters_[i]->Convert(src_buffer->channels(), src_buffer->size(),
+ dst_buffer->channels(), dst_buffer->size());
}
converters_.back()->Convert(buffers_.back()->channels(),
buffers_.back()->size(), dst, dst_capacity);
}
private:
- ScopedVector<AudioConverter> converters_;
- ScopedVector<ChannelBuffer<float>> buffers_;
+ std::vector<std::unique_ptr<AudioConverter>> converters_;
+ std::vector<std::unique_ptr<ChannelBuffer<float>>> buffers_;
};
-rtc::scoped_ptr<AudioConverter> AudioConverter::Create(int src_channels,
+std::unique_ptr<AudioConverter> AudioConverter::Create(size_t src_channels,
size_t src_frames,
- int dst_channels,
+ size_t dst_channels,
size_t dst_frames) {
- rtc::scoped_ptr<AudioConverter> sp;
+ std::unique_ptr<AudioConverter> sp;
if (src_channels > dst_channels) {
if (src_frames != dst_frames) {
- ScopedVector<AudioConverter> converters;
- converters.push_back(new DownmixConverter(src_channels, src_frames,
- dst_channels, src_frames));
- converters.push_back(new ResampleConverter(dst_channels, src_frames,
- dst_channels, dst_frames));
- sp.reset(new CompositionConverter(converters.Pass()));
+ std::vector<std::unique_ptr<AudioConverter>> converters;
+ converters.push_back(std::unique_ptr<AudioConverter>(new DownmixConverter(
+ src_channels, src_frames, dst_channels, src_frames)));
+ converters.push_back(
+ std::unique_ptr<AudioConverter>(new ResampleConverter(
+ dst_channels, src_frames, dst_channels, dst_frames)));
+ sp.reset(new CompositionConverter(std::move(converters)));
} else {
sp.reset(new DownmixConverter(src_channels, src_frames, dst_channels,
dst_frames));
}
} else if (src_channels < dst_channels) {
if (src_frames != dst_frames) {
- ScopedVector<AudioConverter> converters;
- converters.push_back(new ResampleConverter(src_channels, src_frames,
- src_channels, dst_frames));
- converters.push_back(new UpmixConverter(src_channels, dst_frames,
- dst_channels, dst_frames));
- sp.reset(new CompositionConverter(converters.Pass()));
+ std::vector<std::unique_ptr<AudioConverter>> converters;
+ converters.push_back(
+ std::unique_ptr<AudioConverter>(new ResampleConverter(
+ src_channels, src_frames, src_channels, dst_frames)));
+ converters.push_back(std::unique_ptr<AudioConverter>(new UpmixConverter(
+ src_channels, dst_frames, dst_channels, dst_frames)));
+ sp.reset(new CompositionConverter(std::move(converters)));
} else {
sp.reset(new UpmixConverter(src_channels, src_frames, dst_channels,
dst_frames));
@@ -168,22 +188,21 @@ rtc::scoped_ptr<AudioConverter> AudioConverter::Create(int src_channels,
sp.reset(new ResampleConverter(src_channels, src_frames, dst_channels,
dst_frames));
} else {
- sp.reset(new CopyConverter(src_channels, src_frames, dst_channels,
- dst_frames));
+ sp.reset(
+ new CopyConverter(src_channels, src_frames, dst_channels, dst_frames));
}
- return sp.Pass();
+ return sp;
}
// For CompositionConverter.
AudioConverter::AudioConverter()
- : src_channels_(0),
- src_frames_(0),
- dst_channels_(0),
- dst_frames_(0) {}
+ : src_channels_(0), src_frames_(0), dst_channels_(0), dst_frames_(0) {}
-AudioConverter::AudioConverter(int src_channels, size_t src_frames,
- int dst_channels, size_t dst_frames)
+AudioConverter::AudioConverter(size_t src_channels,
+ size_t src_frames,
+ size_t dst_channels,
+ size_t dst_frames)
: src_channels_(src_channels),
src_frames_(src_frames),
dst_channels_(dst_channels),
diff --git a/webrtc/common_audio/audio_converter.h b/webrtc/common_audio/audio_converter.h
index 7d1513b..481ac08 100644
--- a/webrtc/common_audio/audio_converter.h
+++ b/webrtc/common_audio/audio_converter.h
@@ -8,11 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_AUDIO_CONVERTER_H_
-#define WEBRTC_COMMON_AUDIO_AUDIO_CONVERTER_H_
+#ifndef COMMON_AUDIO_AUDIO_CONVERTER_H_
+#define COMMON_AUDIO_AUDIO_CONVERTER_H_
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/base/scoped_ptr.h"
+#include <stddef.h>
+
+#include <memory>
+
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -26,36 +29,40 @@ class AudioConverter {
public:
// Returns a new AudioConverter, which will use the supplied format for its
// lifetime. Caller is responsible for the memory.
- static rtc::scoped_ptr<AudioConverter> Create(int src_channels,
+ static std::unique_ptr<AudioConverter> Create(size_t src_channels,
size_t src_frames,
- int dst_channels,
+ size_t dst_channels,
size_t dst_frames);
- virtual ~AudioConverter() {};
+ virtual ~AudioConverter() {}
// Convert |src|, containing |src_size| samples, to |dst|, having a sample
// capacity of |dst_capacity|. Both point to a series of buffers containing
// the samples for each channel. The sizes must correspond to the format
// passed to Create().
- virtual void Convert(const float* const* src, size_t src_size,
- float* const* dst, size_t dst_capacity) = 0;
+ virtual void Convert(const float* const* src,
+ size_t src_size,
+ float* const* dst,
+ size_t dst_capacity) = 0;
- int src_channels() const { return src_channels_; }
+ size_t src_channels() const { return src_channels_; }
size_t src_frames() const { return src_frames_; }
- int dst_channels() const { return dst_channels_; }
+ size_t dst_channels() const { return dst_channels_; }
size_t dst_frames() const { return dst_frames_; }
protected:
AudioConverter();
- AudioConverter(int src_channels, size_t src_frames, int dst_channels,
+ AudioConverter(size_t src_channels,
+ size_t src_frames,
+ size_t dst_channels,
size_t dst_frames);
// Helper to RTC_CHECK that inputs are correctly sized.
void CheckSizes(size_t src_size, size_t dst_capacity) const;
private:
- const int src_channels_;
+ const size_t src_channels_;
const size_t src_frames_;
- const int dst_channels_;
+ const size_t dst_channels_;
const size_t dst_frames_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioConverter);
@@ -63,4 +70,4 @@ class AudioConverter {
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_AUDIO_CONVERTER_H_
+#endif // COMMON_AUDIO_AUDIO_CONVERTER_H_
diff --git a/webrtc/common_audio/audio_ring_buffer.cc b/webrtc/common_audio/audio_ring_buffer.cc
deleted file mode 100644
index a29e53a..0000000
--- a/webrtc/common_audio/audio_ring_buffer.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 "webrtc/common_audio/audio_ring_buffer.h"
-
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/ring_buffer.h"
-
-// This is a simple multi-channel wrapper over the ring_buffer.h C interface.
-
-namespace webrtc {
-
-AudioRingBuffer::AudioRingBuffer(size_t channels, size_t max_frames) {
- buffers_.reserve(channels);
- for (size_t i = 0; i < channels; ++i)
- buffers_.push_back(WebRtc_CreateBuffer(max_frames, sizeof(float)));
-}
-
-AudioRingBuffer::~AudioRingBuffer() {
- for (auto buf : buffers_)
- WebRtc_FreeBuffer(buf);
-}
-
-void AudioRingBuffer::Write(const float* const* data, size_t channels,
- size_t frames) {
- RTC_DCHECK_EQ(buffers_.size(), channels);
- for (size_t i = 0; i < channels; ++i) {
- const size_t written = WebRtc_WriteBuffer(buffers_[i], data[i], frames);
- RTC_CHECK_EQ(written, frames);
- }
-}
-
-void AudioRingBuffer::Read(float* const* data, size_t channels, size_t frames) {
- RTC_DCHECK_EQ(buffers_.size(), channels);
- for (size_t i = 0; i < channels; ++i) {
- const size_t read =
- WebRtc_ReadBuffer(buffers_[i], nullptr, data[i], frames);
- RTC_CHECK_EQ(read, frames);
- }
-}
-
-size_t AudioRingBuffer::ReadFramesAvailable() const {
- // All buffers have the same amount available.
- return WebRtc_available_read(buffers_[0]);
-}
-
-size_t AudioRingBuffer::WriteFramesAvailable() const {
- // All buffers have the same amount available.
- return WebRtc_available_write(buffers_[0]);
-}
-
-void AudioRingBuffer::MoveReadPositionForward(size_t frames) {
- for (auto buf : buffers_) {
- const size_t moved =
- static_cast<size_t>(WebRtc_MoveReadPtr(buf, static_cast<int>(frames)));
- RTC_CHECK_EQ(moved, frames);
- }
-}
-
-void AudioRingBuffer::MoveReadPositionBackward(size_t frames) {
- for (auto buf : buffers_) {
- const size_t moved = static_cast<size_t>(
- -WebRtc_MoveReadPtr(buf, -static_cast<int>(frames)));
- RTC_CHECK_EQ(moved, frames);
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/common_audio/audio_ring_buffer.h b/webrtc/common_audio/audio_ring_buffer.h
deleted file mode 100644
index 58e543a..0000000
--- a/webrtc/common_audio/audio_ring_buffer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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 WEBRTC_COMMON_AUDIO_AUDIO_RING_BUFFER_H_
-#define WEBRTC_COMMON_AUDIO_AUDIO_RING_BUFFER_H_
-
-#include <stddef.h>
-#include <vector>
-
-struct RingBuffer;
-
-namespace webrtc {
-
-// A ring buffer tailored for float deinterleaved audio. Any operation that
-// cannot be performed as requested will cause a crash (e.g. insufficient data
-// in the buffer to fulfill a read request.)
-class AudioRingBuffer final {
- public:
- // Specify the number of channels and maximum number of frames the buffer will
- // contain.
- AudioRingBuffer(size_t channels, size_t max_frames);
- ~AudioRingBuffer();
-
- // Copies |data| to the buffer and advances the write pointer. |channels| must
- // be the same as at creation time.
- void Write(const float* const* data, size_t channels, size_t frames);
-
- // Copies from the buffer to |data| and advances the read pointer. |channels|
- // must be the same as at creation time.
- void Read(float* const* data, size_t channels, size_t frames);
-
- size_t ReadFramesAvailable() const;
- size_t WriteFramesAvailable() const;
-
- // Moves the read position. The forward version advances the read pointer
- // towards the write pointer and the backward verison withdraws the read
- // pointer away from the write pointer (i.e. flushing and stuffing the buffer
- // respectively.)
- void MoveReadPositionForward(size_t frames);
- void MoveReadPositionBackward(size_t frames);
-
- private:
- // We don't use a ScopedVector because it doesn't support a specialized
- // deleter (like scoped_ptr for instance.)
- std::vector<RingBuffer*> buffers_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_COMMON_AUDIO_AUDIO_RING_BUFFER_H_
diff --git a/webrtc/common_audio/audio_util.cc b/webrtc/common_audio/audio_util.cc
index 2ce2eba..b1e4d9a 100644
--- a/webrtc/common_audio/audio_util.cc
+++ b/webrtc/common_audio/audio_util.cc
@@ -8,9 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/include/audio_util.h"
-
-#include "webrtc/typedefs.h"
+#include "common_audio/include/audio_util.h"
namespace webrtc {
@@ -24,6 +22,11 @@ void S16ToFloat(const int16_t* src, size_t size, float* dest) {
dest[i] = S16ToFloat(src[i]);
}
+void S16ToFloatS16(const int16_t* src, size_t size, float* dest) {
+ for (size_t i = 0; i < size; ++i)
+ dest[i] = src[i];
+}
+
void FloatS16ToS16(const float* src, size_t size, int16_t* dest) {
for (size_t i = 0; i < size; ++i)
dest[i] = FloatS16ToS16(src[i]);
diff --git a/webrtc/common_audio/blocker.cc b/webrtc/common_audio/blocker.cc
deleted file mode 100644
index 0133550..0000000
--- a/webrtc/common_audio/blocker.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/common_audio/blocker.h"
-
-#include <string.h>
-
-#include "webrtc/base/checks.h"
-
-namespace {
-
-// Adds |a| and |b| frame by frame into |result| (basically matrix addition).
-void AddFrames(const float* const* a,
- size_t a_start_index,
- const float* const* b,
- int b_start_index,
- size_t num_frames,
- int num_channels,
- float* const* result,
- size_t result_start_index) {
- for (int i = 0; i < num_channels; ++i) {
- for (size_t j = 0; j < num_frames; ++j) {
- result[i][j + result_start_index] =
- a[i][j + a_start_index] + b[i][j + b_start_index];
- }
- }
-}
-
-// Copies |src| into |dst| channel by channel.
-void CopyFrames(const float* const* src,
- size_t src_start_index,
- size_t num_frames,
- int num_channels,
- float* const* dst,
- size_t dst_start_index) {
- for (int i = 0; i < num_channels; ++i) {
- memcpy(&dst[i][dst_start_index],
- &src[i][src_start_index],
- num_frames * sizeof(dst[i][dst_start_index]));
- }
-}
-
-// Moves |src| into |dst| channel by channel.
-void MoveFrames(const float* const* src,
- size_t src_start_index,
- size_t num_frames,
- int num_channels,
- float* const* dst,
- size_t dst_start_index) {
- for (int i = 0; i < num_channels; ++i) {
- memmove(&dst[i][dst_start_index],
- &src[i][src_start_index],
- num_frames * sizeof(dst[i][dst_start_index]));
- }
-}
-
-void ZeroOut(float* const* buffer,
- size_t starting_idx,
- size_t num_frames,
- int num_channels) {
- for (int i = 0; i < num_channels; ++i) {
- memset(&buffer[i][starting_idx], 0,
- num_frames * sizeof(buffer[i][starting_idx]));
- }
-}
-
-// Pointwise multiplies each channel of |frames| with |window|. Results are
-// stored in |frames|.
-void ApplyWindow(const float* window,
- size_t num_frames,
- int num_channels,
- float* const* frames) {
- for (int i = 0; i < num_channels; ++i) {
- for (size_t j = 0; j < num_frames; ++j) {
- frames[i][j] = frames[i][j] * window[j];
- }
- }
-}
-
-size_t gcd(size_t a, size_t b) {
- size_t tmp;
- while (b) {
- tmp = a;
- a = b;
- b = tmp % b;
- }
- return a;
-}
-
-} // namespace
-
-namespace webrtc {
-
-Blocker::Blocker(size_t chunk_size,
- size_t block_size,
- int num_input_channels,
- int num_output_channels,
- const float* window,
- size_t shift_amount,
- BlockerCallback* callback)
- : chunk_size_(chunk_size),
- block_size_(block_size),
- num_input_channels_(num_input_channels),
- num_output_channels_(num_output_channels),
- initial_delay_(block_size_ - gcd(chunk_size, shift_amount)),
- frame_offset_(0),
- input_buffer_(num_input_channels_, chunk_size_ + initial_delay_),
- output_buffer_(chunk_size_ + initial_delay_, num_output_channels_),
- input_block_(block_size_, num_input_channels_),
- output_block_(block_size_, num_output_channels_),
- window_(new float[block_size_]),
- shift_amount_(shift_amount),
- callback_(callback) {
- RTC_CHECK_LE(num_output_channels_, num_input_channels_);
- RTC_CHECK_LE(shift_amount_, block_size_);
-
- memcpy(window_.get(), window, block_size_ * sizeof(*window_.get()));
- input_buffer_.MoveReadPositionBackward(initial_delay_);
-}
-
-// When block_size < chunk_size the input and output buffers look like this:
-//
-// delay* chunk_size chunk_size + delay*
-// buffer: <-------------|---------------------|---------------|>
-// _a_ _b_ _c_
-//
-// On each call to ProcessChunk():
-// 1. New input gets read into sections _b_ and _c_ of the input buffer.
-// 2. We block starting from frame_offset.
-// 3. We block until we reach a block |bl| that doesn't contain any frames
-// from sections _a_ or _b_ of the input buffer.
-// 4. We window the current block, fire the callback for processing, window
-// again, and overlap/add to the output buffer.
-// 5. We copy sections _a_ and _b_ of the output buffer into output.
-// 6. For both the input and the output buffers, we copy section _c_ into
-// section _a_.
-// 7. We set the new frame_offset to be the difference between the first frame
-// of |bl| and the border between sections _b_ and _c_.
-//
-// When block_size > chunk_size the input and output buffers look like this:
-//
-// chunk_size delay* chunk_size + delay*
-// buffer: <-------------|---------------------|---------------|>
-// _a_ _b_ _c_
-//
-// On each call to ProcessChunk():
-// The procedure is the same as above, except for:
-// 1. New input gets read into section _c_ of the input buffer.
-// 3. We block until we reach a block |bl| that doesn't contain any frames
-// from section _a_ of the input buffer.
-// 5. We copy section _a_ of the output buffer into output.
-// 6. For both the input and the output buffers, we copy sections _b_ and _c_
-// into section _a_ and _b_.
-// 7. We set the new frame_offset to be the difference between the first frame
-// of |bl| and the border between sections _a_ and _b_.
-//
-// * delay here refers to inintial_delay_
-//
-// TODO(claguna): Look at using ring buffers to eliminate some copies.
-void Blocker::ProcessChunk(const float* const* input,
- size_t chunk_size,
- int num_input_channels,
- int num_output_channels,
- float* const* output) {
- RTC_CHECK_EQ(chunk_size, chunk_size_);
- RTC_CHECK_EQ(num_input_channels, num_input_channels_);
- RTC_CHECK_EQ(num_output_channels, num_output_channels_);
-
- input_buffer_.Write(input, num_input_channels, chunk_size_);
- size_t first_frame_in_block = frame_offset_;
-
- // Loop through blocks.
- while (first_frame_in_block < chunk_size_) {
- input_buffer_.Read(input_block_.channels(), num_input_channels,
- block_size_);
- input_buffer_.MoveReadPositionBackward(block_size_ - shift_amount_);
-
- ApplyWindow(window_.get(),
- block_size_,
- num_input_channels_,
- input_block_.channels());
- callback_->ProcessBlock(input_block_.channels(),
- block_size_,
- num_input_channels_,
- num_output_channels_,
- output_block_.channels());
- ApplyWindow(window_.get(),
- block_size_,
- num_output_channels_,
- output_block_.channels());
-
- AddFrames(output_buffer_.channels(),
- first_frame_in_block,
- output_block_.channels(),
- 0,
- block_size_,
- num_output_channels_,
- output_buffer_.channels(),
- first_frame_in_block);
-
- first_frame_in_block += shift_amount_;
- }
-
- // Copy output buffer to output
- CopyFrames(output_buffer_.channels(),
- 0,
- chunk_size_,
- num_output_channels_,
- output,
- 0);
-
- // Copy output buffer [chunk_size_, chunk_size_ + initial_delay]
- // to output buffer [0, initial_delay], zero the rest.
- MoveFrames(output_buffer_.channels(),
- chunk_size,
- initial_delay_,
- num_output_channels_,
- output_buffer_.channels(),
- 0);
- ZeroOut(output_buffer_.channels(),
- initial_delay_,
- chunk_size_,
- num_output_channels_);
-
- // Calculate new starting frames.
- frame_offset_ = first_frame_in_block - chunk_size_;
-}
-
-} // namespace webrtc
diff --git a/webrtc/common_audio/blocker.h b/webrtc/common_audio/blocker.h
deleted file mode 100644
index 025638a..0000000
--- a/webrtc/common_audio/blocker.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_INTERNAL_BEAMFORMER_BLOCKER_H_
-#define WEBRTC_INTERNAL_BEAMFORMER_BLOCKER_H_
-
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/audio_ring_buffer.h"
-#include "webrtc/common_audio/channel_buffer.h"
-
-namespace webrtc {
-
-// The callback function to process audio in the time domain. Input has already
-// been windowed, and output will be windowed. The number of input channels
-// must be >= the number of output channels.
-class BlockerCallback {
- public:
- virtual ~BlockerCallback() {}
-
- virtual void ProcessBlock(const float* const* input,
- size_t num_frames,
- int num_input_channels,
- int num_output_channels,
- float* const* output) = 0;
-};
-
-// The main purpose of Blocker is to abstract away the fact that often we
-// receive a different number of audio frames than our transform takes. For
-// example, most FFTs work best when the fft-size is a power of 2, but suppose
-// we receive 20ms of audio at a sample rate of 48000. That comes to 960 frames
-// of audio, which is not a power of 2. Blocker allows us to specify the
-// transform and all other necessary processing via the Process() callback
-// function without any constraints on the transform-size
-// (read: |block_size_|) or received-audio-size (read: |chunk_size_|).
-// We handle this for the multichannel audio case, allowing for different
-// numbers of input and output channels (for example, beamforming takes 2 or
-// more input channels and returns 1 output channel). Audio signals are
-// represented as deinterleaved floats in the range [-1, 1].
-//
-// Blocker is responsible for:
-// - blocking audio while handling potential discontinuities on the edges
-// of chunks
-// - windowing blocks before sending them to Process()
-// - windowing processed blocks, and overlap-adding them together before
-// sending back a processed chunk
-//
-// To use blocker:
-// 1. Impelment a BlockerCallback object |bc|.
-// 2. Instantiate a Blocker object |b|, passing in |bc|.
-// 3. As you receive audio, call b.ProcessChunk() to get processed audio.
-//
-// A small amount of delay is added to the first received chunk to deal with
-// the difference in chunk/block sizes. This delay is <= chunk_size.
-//
-// Ownership of window is retained by the caller. That is, Blocker makes a
-// copy of window and does not attempt to delete it.
-class Blocker {
- public:
- Blocker(size_t chunk_size,
- size_t block_size,
- int num_input_channels,
- int num_output_channels,
- const float* window,
- size_t shift_amount,
- BlockerCallback* callback);
-
- void ProcessChunk(const float* const* input,
- size_t chunk_size,
- int num_input_channels,
- int num_output_channels,
- float* const* output);
-
- private:
- const size_t chunk_size_;
- const size_t block_size_;
- const int num_input_channels_;
- const int num_output_channels_;
-
- // The number of frames of delay to add at the beginning of the first chunk.
- const size_t initial_delay_;
-
- // The frame index into the input buffer where the first block should be read
- // from. This is necessary because shift_amount_ is not necessarily a
- // multiple of chunk_size_, so blocks won't line up at the start of the
- // buffer.
- size_t frame_offset_;
-
- // Since blocks nearly always overlap, there are certain blocks that require
- // frames from the end of one chunk and the beginning of the next chunk. The
- // input and output buffers are responsible for saving those frames between
- // calls to ProcessChunk().
- //
- // Both contain |initial delay| + |chunk_size| frames. The input is a fairly
- // standard FIFO, but due to the overlap-add it's harder to use an
- // AudioRingBuffer for the output.
- AudioRingBuffer input_buffer_;
- ChannelBuffer<float> output_buffer_;
-
- // Space for the input block (can't wrap because of windowing).
- ChannelBuffer<float> input_block_;
-
- // Space for the output block (can't wrap because of overlap/add).
- ChannelBuffer<float> output_block_;
-
- rtc::scoped_ptr<float[]> window_;
-
- // The amount of frames between the start of contiguous blocks. For example,
- // |shift_amount_| = |block_size_| / 2 for a Hann window.
- size_t shift_amount_;
-
- BlockerCallback* callback_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_INTERNAL_BEAMFORMER_BLOCKER_H_
diff --git a/webrtc/common_audio/channel_buffer.cc b/webrtc/common_audio/channel_buffer.cc
index d3dc7c0..b9b8c25 100644
--- a/webrtc/common_audio/channel_buffer.cc
+++ b/webrtc/common_audio/channel_buffer.cc
@@ -8,18 +8,25 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/channel_buffer.h"
+#include "common_audio/channel_buffer.h"
+
+#include <cstdint>
+
+#include "common_audio/include/audio_util.h"
+#include "rtc_base/checks.h"
namespace webrtc {
IFChannelBuffer::IFChannelBuffer(size_t num_frames,
- int num_channels,
+ size_t num_channels,
size_t num_bands)
: ivalid_(true),
ibuf_(num_frames, num_channels, num_bands),
fvalid_(true),
fbuf_(num_frames, num_channels, num_bands) {}
+IFChannelBuffer::~IFChannelBuffer() = default;
+
ChannelBuffer<int16_t>* IFChannelBuffer::ibuf() {
RefreshI();
fvalid_ = false;
@@ -44,10 +51,11 @@ const ChannelBuffer<float>* IFChannelBuffer::fbuf_const() const {
void IFChannelBuffer::RefreshF() const {
if (!fvalid_) {
- assert(ivalid_);
+ RTC_DCHECK(ivalid_);
+ fbuf_.set_num_channels(ibuf_.num_channels());
const int16_t* const* int_channels = ibuf_.channels();
float* const* float_channels = fbuf_.channels();
- for (int i = 0; i < ibuf_.num_channels(); ++i) {
+ for (size_t i = 0; i < ibuf_.num_channels(); ++i) {
for (size_t j = 0; j < ibuf_.num_frames(); ++j) {
float_channels[i][j] = int_channels[i][j];
}
@@ -58,13 +66,12 @@ void IFChannelBuffer::RefreshF() const {
void IFChannelBuffer::RefreshI() const {
if (!ivalid_) {
- assert(fvalid_);
+ RTC_DCHECK(fvalid_);
int16_t* const* int_channels = ibuf_.channels();
+ ibuf_.set_num_channels(fbuf_.num_channels());
const float* const* float_channels = fbuf_.channels();
- for (int i = 0; i < ibuf_.num_channels(); ++i) {
- FloatS16ToS16(float_channels[i],
- ibuf_.num_frames(),
- int_channels[i]);
+ for (size_t i = 0; i < fbuf_.num_channels(); ++i) {
+ FloatS16ToS16(float_channels[i], ibuf_.num_frames(), int_channels[i]);
}
ivalid_ = true;
}
diff --git a/webrtc/common_audio/channel_buffer.h b/webrtc/common_audio/channel_buffer.h
index a308d7b..f027080 100644
--- a/webrtc/common_audio/channel_buffer.h
+++ b/webrtc/common_audio/channel_buffer.h
@@ -8,17 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_CHANNEL_BUFFER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_CHANNEL_BUFFER_H_
+#ifndef COMMON_AUDIO_CHANNEL_BUFFER_H_
+#define COMMON_AUDIO_CHANNEL_BUFFER_H_
#include <string.h>
-#include "webrtc/base/checks.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/include/audio_util.h"
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
-#include "webrtc/test/testsupport/gtest_prod_util.h"
-#endif
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "common_audio/include/audio_util.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/gtest_prod_util.h"
namespace webrtc {
@@ -41,49 +42,68 @@ namespace webrtc {
template <typename T>
class ChannelBuffer {
public:
- ChannelBuffer(size_t num_frames,
- int num_channels,
- size_t num_bands = 1)
+ ChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1)
: data_(new T[num_frames * num_channels]()),
channels_(new T*[num_channels * num_bands]),
bands_(new T*[num_channels * num_bands]),
num_frames_(num_frames),
num_frames_per_band_(num_frames / num_bands),
+ num_allocated_channels_(num_channels),
num_channels_(num_channels),
- num_bands_(num_bands) {
- for (int i = 0; i < num_channels_; ++i) {
- for (size_t j = 0; j < num_bands_; ++j) {
- channels_[j * num_channels_ + i] =
- &data_[i * num_frames_ + j * num_frames_per_band_];
- bands_[i * num_bands_ + j] = channels_[j * num_channels_ + i];
+ num_bands_(num_bands),
+ bands_view_(num_allocated_channels_,
+ std::vector<rtc::ArrayView<T>>(num_bands_)),
+ channels_view_(
+ num_bands_,
+ std::vector<rtc::ArrayView<T>>(num_allocated_channels_)) {
+ // Temporarily cast away const_ness to allow populating the array views.
+ auto* bands_view =
+ const_cast<std::vector<std::vector<rtc::ArrayView<T>>>*>(&bands_view_);
+ auto* channels_view =
+ const_cast<std::vector<std::vector<rtc::ArrayView<T>>>*>(
+ &channels_view_);
+
+ for (size_t ch = 0; ch < num_allocated_channels_; ++ch) {
+ for (size_t band = 0; band < num_bands_; ++band) {
+ (*channels_view)[band][ch] = rtc::ArrayView<T>(
+ &data_[ch * num_frames_ + band * num_frames_per_band_],
+ num_frames_per_band_);
+ (*bands_view)[ch][band] = channels_view_[band][ch];
+ channels_[band * num_allocated_channels_ + ch] =
+ channels_view_[band][ch].data();
+ bands_[ch * num_bands_ + band] =
+ channels_[band * num_allocated_channels_ + ch];
}
}
}
- // Returns a pointer array to the full-band channels (or lower band channels).
- // Usage:
- // channels()[channel][sample].
- // Where:
- // 0 <= channel < |num_channels_|
- // 0 <= sample < |num_frames_|
- T* const* channels() { return channels(0); }
- const T* const* channels() const { return channels(0); }
-
- // Returns a pointer array to the channels for a specific band.
- // Usage:
- // channels(band)[channel][sample].
+ // Returns a pointer array to the channels.
+ // If band is explicitly specificed, the channels for a specific band are
+ // returned and the usage becomes: channels(band)[channel][sample].
// Where:
// 0 <= band < |num_bands_|
- // 0 <= channel < |num_channels_|
+ // 0 <= channel < |num_allocated_channels_|
// 0 <= sample < |num_frames_per_band_|
- const T* const* channels(size_t band) const {
+
+ // If band is not explicitly specified, the full-band channels (or lower band
+ // channels) are returned and the usage becomes: channels()[channel][sample].
+ // Where:
+ // 0 <= channel < |num_allocated_channels_|
+ // 0 <= sample < |num_frames_|
+ const T* const* channels(size_t band = 0) const {
RTC_DCHECK_LT(band, num_bands_);
- return &channels_[band * num_channels_];
+ return &channels_[band * num_allocated_channels_];
}
- T* const* channels(size_t band) {
+ T* const* channels(size_t band = 0) {
const ChannelBuffer<T>* t = this;
return const_cast<T* const*>(t->channels(band));
}
+ rtc::ArrayView<const rtc::ArrayView<T>> channels_view(size_t band = 0) {
+ return channels_view_[band];
+ }
+ rtc::ArrayView<const rtc::ArrayView<T>> channels_view(size_t band = 0) const {
+ return channels_view_[band];
+ }
// Returns a pointer array to the bands for a specific channel.
// Usage:
@@ -92,21 +112,28 @@ class ChannelBuffer {
// 0 <= channel < |num_channels_|
// 0 <= band < |num_bands_|
// 0 <= sample < |num_frames_per_band_|
- const T* const* bands(int channel) const {
+ const T* const* bands(size_t channel) const {
RTC_DCHECK_LT(channel, num_channels_);
RTC_DCHECK_GE(channel, 0);
return &bands_[channel * num_bands_];
}
- T* const* bands(int channel) {
+ T* const* bands(size_t channel) {
const ChannelBuffer<T>* t = this;
return const_cast<T* const*>(t->bands(channel));
}
+ rtc::ArrayView<const rtc::ArrayView<T>> bands_view(size_t channel) {
+ return bands_view_[channel];
+ }
+ rtc::ArrayView<const rtc::ArrayView<T>> bands_view(size_t channel) const {
+ return bands_view_[channel];
+ }
+
// Sets the |slice| pointers to the |start_frame| position for each channel.
// Returns |slice| for convenience.
const T* const* Slice(T** slice, size_t start_frame) const {
RTC_DCHECK_LT(start_frame, num_frames_);
- for (int i = 0; i < num_channels_; ++i)
+ for (size_t i = 0; i < num_channels_; ++i)
slice[i] = &channels_[i][start_frame];
return slice;
}
@@ -117,9 +144,14 @@ class ChannelBuffer {
size_t num_frames() const { return num_frames_; }
size_t num_frames_per_band() const { return num_frames_per_band_; }
- int num_channels() const { return num_channels_; }
+ size_t num_channels() const { return num_channels_; }
size_t num_bands() const { return num_bands_; }
- size_t size() const {return num_frames_ * num_channels_; }
+ size_t size() const { return num_frames_ * num_allocated_channels_; }
+
+ void set_num_channels(size_t num_channels) {
+ RTC_DCHECK_LE(num_channels, num_allocated_channels_);
+ num_channels_ = num_channels;
+ }
void SetDataForTesting(const T* data, size_t size) {
RTC_CHECK_EQ(size, this->size());
@@ -127,13 +159,18 @@ class ChannelBuffer {
}
private:
- rtc::scoped_ptr<T[]> data_;
- rtc::scoped_ptr<T* []> channels_;
- rtc::scoped_ptr<T* []> bands_;
+ std::unique_ptr<T[]> data_;
+ std::unique_ptr<T*[]> channels_;
+ std::unique_ptr<T*[]> bands_;
const size_t num_frames_;
const size_t num_frames_per_band_;
- const int num_channels_;
+ // Number of channels the internal buffer holds.
+ const size_t num_allocated_channels_;
+ // Number of channels the user sees.
+ size_t num_channels_;
const size_t num_bands_;
+ const std::vector<std::vector<rtc::ArrayView<T>>> bands_view_;
+ const std::vector<std::vector<rtc::ArrayView<T>>> channels_view_;
};
// One int16_t and one float ChannelBuffer that are kept in sync. The sync is
@@ -144,7 +181,8 @@ class ChannelBuffer {
// fbuf() until the next call to any of the other functions.
class IFChannelBuffer {
public:
- IFChannelBuffer(size_t num_frames, int num_channels, size_t num_bands = 1);
+ IFChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1);
+ ~IFChannelBuffer();
ChannelBuffer<int16_t>* ibuf();
ChannelBuffer<float>* fbuf();
@@ -153,7 +191,13 @@ class IFChannelBuffer {
size_t num_frames() const { return ibuf_.num_frames(); }
size_t num_frames_per_band() const { return ibuf_.num_frames_per_band(); }
- int num_channels() const { return ibuf_.num_channels(); }
+ size_t num_channels() const {
+ return ivalid_ ? ibuf_.num_channels() : fbuf_.num_channels();
+ }
+ void set_num_channels(size_t num_channels) {
+ ibuf_.set_num_channels(num_channels);
+ fbuf_.set_num_channels(num_channels);
+ }
size_t num_bands() const { return ibuf_.num_bands(); }
private:
@@ -168,4 +212,4 @@ class IFChannelBuffer {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_CHANNEL_BUFFER_H_
+#endif // COMMON_AUDIO_CHANNEL_BUFFER_H_
diff --git a/webrtc/common_audio/fft4g.c b/webrtc/common_audio/fft4g.c
deleted file mode 100644
index 9cf7b9f..0000000
--- a/webrtc/common_audio/fft4g.c
+++ /dev/null
@@ -1,1332 +0,0 @@
-/*
- * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
- * Copyright Takuya OOURA, 1996-2001
- *
- * You may use, copy, modify and distribute this code for any purpose (include
- * commercial use) and without fee. Please refer to this package when you modify
- * this code.
- *
- * Changes:
- * Trivial type modifications by the WebRTC authors.
- */
-
-/*
-Fast Fourier/Cosine/Sine Transform
- dimension :one
- data length :power of 2
- decimation :frequency
- radix :4, 2
- data :inplace
- table :use
-functions
- cdft: Complex Discrete Fourier Transform
- rdft: Real Discrete Fourier Transform
- ddct: Discrete Cosine Transform
- ddst: Discrete Sine Transform
- dfct: Cosine Transform of RDFT (Real Symmetric DFT)
- dfst: Sine Transform of RDFT (Real Anti-symmetric DFT)
-function prototypes
- void cdft(int, int, float *, int *, float *);
- void rdft(size_t, int, float *, size_t *, float *);
- void ddct(int, int, float *, int *, float *);
- void ddst(int, int, float *, int *, float *);
- void dfct(int, float *, float *, int *, float *);
- void dfst(int, float *, float *, int *, float *);
-
-
--------- Complex DFT (Discrete Fourier Transform) --------
- [definition]
- <case1>
- X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n
- <case2>
- X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n
- (notes: sum_j=0^n-1 is a summation from j=0 to n-1)
- [usage]
- <case1>
- ip[0] = 0; // first time only
- cdft(2*n, 1, a, ip, w);
- <case2>
- ip[0] = 0; // first time only
- cdft(2*n, -1, a, ip, w);
- [parameters]
- 2*n :data length (int)
- n >= 1, n = power of 2
- a[0...2*n-1] :input/output data (float *)
- input data
- a[2*j] = Re(x[j]),
- a[2*j+1] = Im(x[j]), 0<=j<n
- output data
- a[2*k] = Re(X[k]),
- a[2*k+1] = Im(X[k]), 0<=k<n
- ip[0...*] :work area for bit reversal (int *)
- length of ip >= 2+sqrt(n)
- strictly,
- length of ip >=
- 2+(1<<(int)(log(n+0.5)/log(2))/2).
- ip[0],ip[1] are pointers of the cos/sin table.
- w[0...n/2-1] :cos/sin table (float *)
- w[],ip[] are initialized if ip[0] == 0.
- [remark]
- Inverse of
- cdft(2*n, -1, a, ip, w);
- is
- cdft(2*n, 1, a, ip, w);
- for (j = 0; j <= 2 * n - 1; j++) {
- a[j] *= 1.0 / n;
- }
- .
-
-
--------- Real DFT / Inverse of Real DFT --------
- [definition]
- <case1> RDFT
- R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2
- I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2
- <case2> IRDFT (excluding scale)
- a[k] = (R[0] + R[n/2]*cos(pi*k))/2 +
- sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) +
- sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n
- [usage]
- <case1>
- ip[0] = 0; // first time only
- rdft(n, 1, a, ip, w);
- <case2>
- ip[0] = 0; // first time only
- rdft(n, -1, a, ip, w);
- [parameters]
- n :data length (size_t)
- n >= 2, n = power of 2
- a[0...n-1] :input/output data (float *)
- <case1>
- output data
- a[2*k] = R[k], 0<=k<n/2
- a[2*k+1] = I[k], 0<k<n/2
- a[1] = R[n/2]
- <case2>
- input data
- a[2*j] = R[j], 0<=j<n/2
- a[2*j+1] = I[j], 0<j<n/2
- a[1] = R[n/2]
- ip[0...*] :work area for bit reversal (size_t *)
- length of ip >= 2+sqrt(n/2)
- strictly,
- length of ip >=
- 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
- ip[0],ip[1] are pointers of the cos/sin table.
- w[0...n/2-1] :cos/sin table (float *)
- w[],ip[] are initialized if ip[0] == 0.
- [remark]
- Inverse of
- rdft(n, 1, a, ip, w);
- is
- rdft(n, -1, a, ip, w);
- for (j = 0; j <= n - 1; j++) {
- a[j] *= 2.0 / n;
- }
- .
-
-
--------- DCT (Discrete Cosine Transform) / Inverse of DCT --------
- [definition]
- <case1> IDCT (excluding scale)
- C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n
- <case2> DCT
- C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n
- [usage]
- <case1>
- ip[0] = 0; // first time only
- ddct(n, 1, a, ip, w);
- <case2>
- ip[0] = 0; // first time only
- ddct(n, -1, a, ip, w);
- [parameters]
- n :data length (int)
- n >= 2, n = power of 2
- a[0...n-1] :input/output data (float *)
- output data
- a[k] = C[k], 0<=k<n
- ip[0...*] :work area for bit reversal (int *)
- length of ip >= 2+sqrt(n/2)
- strictly,
- length of ip >=
- 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
- ip[0],ip[1] are pointers of the cos/sin table.
- w[0...n*5/4-1] :cos/sin table (float *)
- w[],ip[] are initialized if ip[0] == 0.
- [remark]
- Inverse of
- ddct(n, -1, a, ip, w);
- is
- a[0] *= 0.5;
- ddct(n, 1, a, ip, w);
- for (j = 0; j <= n - 1; j++) {
- a[j] *= 2.0 / n;
- }
- .
-
-
--------- DST (Discrete Sine Transform) / Inverse of DST --------
- [definition]
- <case1> IDST (excluding scale)
- S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n
- <case2> DST
- S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n
- [usage]
- <case1>
- ip[0] = 0; // first time only
- ddst(n, 1, a, ip, w);
- <case2>
- ip[0] = 0; // first time only
- ddst(n, -1, a, ip, w);
- [parameters]
- n :data length (int)
- n >= 2, n = power of 2
- a[0...n-1] :input/output data (float *)
- <case1>
- input data
- a[j] = A[j], 0<j<n
- a[0] = A[n]
- output data
- a[k] = S[k], 0<=k<n
- <case2>
- output data
- a[k] = S[k], 0<k<n
- a[0] = S[n]
- ip[0...*] :work area for bit reversal (int *)
- length of ip >= 2+sqrt(n/2)
- strictly,
- length of ip >=
- 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
- ip[0],ip[1] are pointers of the cos/sin table.
- w[0...n*5/4-1] :cos/sin table (float *)
- w[],ip[] are initialized if ip[0] == 0.
- [remark]
- Inverse of
- ddst(n, -1, a, ip, w);
- is
- a[0] *= 0.5;
- ddst(n, 1, a, ip, w);
- for (j = 0; j <= n - 1; j++) {
- a[j] *= 2.0 / n;
- }
- .
-
-
--------- Cosine Transform of RDFT (Real Symmetric DFT) --------
- [definition]
- C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n
- [usage]
- ip[0] = 0; // first time only
- dfct(n, a, t, ip, w);
- [parameters]
- n :data length - 1 (int)
- n >= 2, n = power of 2
- a[0...n] :input/output data (float *)
- output data
- a[k] = C[k], 0<=k<=n
- t[0...n/2] :work area (float *)
- ip[0...*] :work area for bit reversal (int *)
- length of ip >= 2+sqrt(n/4)
- strictly,
- length of ip >=
- 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
- ip[0],ip[1] are pointers of the cos/sin table.
- w[0...n*5/8-1] :cos/sin table (float *)
- w[],ip[] are initialized if ip[0] == 0.
- [remark]
- Inverse of
- a[0] *= 0.5;
- a[n] *= 0.5;
- dfct(n, a, t, ip, w);
- is
- a[0] *= 0.5;
- a[n] *= 0.5;
- dfct(n, a, t, ip, w);
- for (j = 0; j <= n; j++) {
- a[j] *= 2.0 / n;
- }
- .
-
-
--------- Sine Transform of RDFT (Real Anti-symmetric DFT) --------
- [definition]
- S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n
- [usage]
- ip[0] = 0; // first time only
- dfst(n, a, t, ip, w);
- [parameters]
- n :data length + 1 (int)
- n >= 2, n = power of 2
- a[0...n-1] :input/output data (float *)
- output data
- a[k] = S[k], 0<k<n
- (a[0] is used for work area)
- t[0...n/2-1] :work area (float *)
- ip[0...*] :work area for bit reversal (int *)
- length of ip >= 2+sqrt(n/4)
- strictly,
- length of ip >=
- 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
- ip[0],ip[1] are pointers of the cos/sin table.
- w[0...n*5/8-1] :cos/sin table (float *)
- w[],ip[] are initialized if ip[0] == 0.
- [remark]
- Inverse of
- dfst(n, a, t, ip, w);
- is
- dfst(n, a, t, ip, w);
- for (j = 1; j <= n - 1; j++) {
- a[j] *= 2.0 / n;
- }
- .
-
-
-Appendix :
- The cos/sin table is recalculated when the larger table required.
- w[] and ip[] are compatible with all routines.
-*/
-
-#include <stddef.h>
-
-static void makewt(size_t nw, size_t *ip, float *w);
-static void makect(size_t nc, size_t *ip, float *c);
-static void bitrv2(size_t n, size_t *ip, float *a);
-#if 0 // Not used.
-static void bitrv2conj(int n, int *ip, float *a);
-#endif
-static void cftfsub(size_t n, float *a, float *w);
-static void cftbsub(size_t n, float *a, float *w);
-static void cft1st(size_t n, float *a, float *w);
-static void cftmdl(size_t n, size_t l, float *a, float *w);
-static void rftfsub(size_t n, float *a, size_t nc, float *c);
-static void rftbsub(size_t n, float *a, size_t nc, float *c);
-#if 0 // Not used.
-static void dctsub(int n, float *a, int nc, float *c)
-static void dstsub(int n, float *a, int nc, float *c)
-#endif
-
-
-#if 0 // Not used.
-void WebRtc_cdft(int n, int isgn, float *a, int *ip, float *w)
-{
- if (n > (ip[0] << 2)) {
- makewt(n >> 2, ip, w);
- }
- if (n > 4) {
- if (isgn >= 0) {
- bitrv2(n, ip + 2, a);
- cftfsub(n, a, w);
- } else {
- bitrv2conj(n, ip + 2, a);
- cftbsub(n, a, w);
- }
- } else if (n == 4) {
- cftfsub(n, a, w);
- }
-}
-#endif
-
-
-void WebRtc_rdft(size_t n, int isgn, float *a, size_t *ip, float *w)
-{
- size_t nw, nc;
- float xi;
-
- nw = ip[0];
- if (n > (nw << 2)) {
- nw = n >> 2;
- makewt(nw, ip, w);
- }
- nc = ip[1];
- if (n > (nc << 2)) {
- nc = n >> 2;
- makect(nc, ip, w + nw);
- }
- if (isgn >= 0) {
- if (n > 4) {
- bitrv2(n, ip + 2, a);
- cftfsub(n, a, w);
- rftfsub(n, a, nc, w + nw);
- } else if (n == 4) {
- cftfsub(n, a, w);
- }
- xi = a[0] - a[1];
- a[0] += a[1];
- a[1] = xi;
- } else {
- a[1] = 0.5f * (a[0] - a[1]);
- a[0] -= a[1];
- if (n > 4) {
- rftbsub(n, a, nc, w + nw);
- bitrv2(n, ip + 2, a);
- cftbsub(n, a, w);
- } else if (n == 4) {
- cftfsub(n, a, w);
- }
- }
-}
-
-#if 0 // Not used.
-static void ddct(int n, int isgn, float *a, int *ip, float *w)
-{
- int j, nw, nc;
- float xr;
-
- nw = ip[0];
- if (n > (nw << 2)) {
- nw = n >> 2;
- makewt(nw, ip, w);
- }
- nc = ip[1];
- if (n > nc) {
- nc = n;
- makect(nc, ip, w + nw);
- }
- if (isgn < 0) {
- xr = a[n - 1];
- for (j = n - 2; j >= 2; j -= 2) {
- a[j + 1] = a[j] - a[j - 1];
- a[j] += a[j - 1];
- }
- a[1] = a[0] - xr;
- a[0] += xr;
- if (n > 4) {
- rftbsub(n, a, nc, w + nw);
- bitrv2(n, ip + 2, a);
- cftbsub(n, a, w);
- } else if (n == 4) {
- cftfsub(n, a, w);
- }
- }
- dctsub(n, a, nc, w + nw);
- if (isgn >= 0) {
- if (n > 4) {
- bitrv2(n, ip + 2, a);
- cftfsub(n, a, w);
- rftfsub(n, a, nc, w + nw);
- } else if (n == 4) {
- cftfsub(n, a, w);
- }
- xr = a[0] - a[1];
- a[0] += a[1];
- for (j = 2; j < n; j += 2) {
- a[j - 1] = a[j] - a[j + 1];
- a[j] += a[j + 1];
- }
- a[n - 1] = xr;
- }
-}
-
-
-static void ddst(int n, int isgn, float *a, int *ip, float *w)
-{
- int j, nw, nc;
- float xr;
-
- nw = ip[0];
- if (n > (nw << 2)) {
- nw = n >> 2;
- makewt(nw, ip, w);
- }
- nc = ip[1];
- if (n > nc) {
- nc = n;
- makect(nc, ip, w + nw);
- }
- if (isgn < 0) {
- xr = a[n - 1];
- for (j = n - 2; j >= 2; j -= 2) {
- a[j + 1] = -a[j] - a[j - 1];
- a[j] -= a[j - 1];
- }
- a[1] = a[0] + xr;
- a[0] -= xr;
- if (n > 4) {
- rftbsub(n, a, nc, w + nw);
- bitrv2(n, ip + 2, a);
- cftbsub(n, a, w);
- } else if (n == 4) {
- cftfsub(n, a, w);
- }
- }
- dstsub(n, a, nc, w + nw);
- if (isgn >= 0) {
- if (n > 4) {
- bitrv2(n, ip + 2, a);
- cftfsub(n, a, w);
- rftfsub(n, a, nc, w + nw);
- } else if (n == 4) {
- cftfsub(n, a, w);
- }
- xr = a[0] - a[1];
- a[0] += a[1];
- for (j = 2; j < n; j += 2) {
- a[j - 1] = -a[j] - a[j + 1];
- a[j] -= a[j + 1];
- }
- a[n - 1] = -xr;
- }
-}
-
-
-static void dfct(int n, float *a, float *t, int *ip, float *w)
-{
- int j, k, l, m, mh, nw, nc;
- float xr, xi, yr, yi;
-
- nw = ip[0];
- if (n > (nw << 3)) {
- nw = n >> 3;
- makewt(nw, ip, w);
- }
- nc = ip[1];
- if (n > (nc << 1)) {
- nc = n >> 1;
- makect(nc, ip, w + nw);
- }
- m = n >> 1;
- yi = a[m];
- xi = a[0] + a[n];
- a[0] -= a[n];
- t[0] = xi - yi;
- t[m] = xi + yi;
- if (n > 2) {
- mh = m >> 1;
- for (j = 1; j < mh; j++) {
- k = m - j;
- xr = a[j] - a[n - j];
- xi = a[j] + a[n - j];
- yr = a[k] - a[n - k];
- yi = a[k] + a[n - k];
- a[j] = xr;
- a[k] = yr;
- t[j] = xi - yi;
- t[k] = xi + yi;
- }
- t[mh] = a[mh] + a[n - mh];
- a[mh] -= a[n - mh];
- dctsub(m, a, nc, w + nw);
- if (m > 4) {
- bitrv2(m, ip + 2, a);
- cftfsub(m, a, w);
- rftfsub(m, a, nc, w + nw);
- } else if (m == 4) {
- cftfsub(m, a, w);
- }
- a[n - 1] = a[0] - a[1];
- a[1] = a[0] + a[1];
- for (j = m - 2; j >= 2; j -= 2) {
- a[2 * j + 1] = a[j] + a[j + 1];
- a[2 * j - 1] = a[j] - a[j + 1];
- }
- l = 2;
- m = mh;
- while (m >= 2) {
- dctsub(m, t, nc, w + nw);
- if (m > 4) {
- bitrv2(m, ip + 2, t);
- cftfsub(m, t, w);
- rftfsub(m, t, nc, w + nw);
- } else if (m == 4) {
- cftfsub(m, t, w);
- }
- a[n - l] = t[0] - t[1];
- a[l] = t[0] + t[1];
- k = 0;
- for (j = 2; j < m; j += 2) {
- k += l << 2;
- a[k - l] = t[j] - t[j + 1];
- a[k + l] = t[j] + t[j + 1];
- }
- l <<= 1;
- mh = m >> 1;
- for (j = 0; j < mh; j++) {
- k = m - j;
- t[j] = t[m + k] - t[m + j];
- t[k] = t[m + k] + t[m + j];
- }
- t[mh] = t[m + mh];
- m = mh;
- }
- a[l] = t[0];
- a[n] = t[2] - t[1];
- a[0] = t[2] + t[1];
- } else {
- a[1] = a[0];
- a[2] = t[0];
- a[0] = t[1];
- }
-}
-
-static void dfst(int n, float *a, float *t, int *ip, float *w)
-{
- int j, k, l, m, mh, nw, nc;
- float xr, xi, yr, yi;
-
- nw = ip[0];
- if (n > (nw << 3)) {
- nw = n >> 3;
- makewt(nw, ip, w);
- }
- nc = ip[1];
- if (n > (nc << 1)) {
- nc = n >> 1;
- makect(nc, ip, w + nw);
- }
- if (n > 2) {
- m = n >> 1;
- mh = m >> 1;
- for (j = 1; j < mh; j++) {
- k = m - j;
- xr = a[j] + a[n - j];
- xi = a[j] - a[n - j];
- yr = a[k] + a[n - k];
- yi = a[k] - a[n - k];
- a[j] = xr;
- a[k] = yr;
- t[j] = xi + yi;
- t[k] = xi - yi;
- }
- t[0] = a[mh] - a[n - mh];
- a[mh] += a[n - mh];
- a[0] = a[m];
- dstsub(m, a, nc, w + nw);
- if (m > 4) {
- bitrv2(m, ip + 2, a);
- cftfsub(m, a, w);
- rftfsub(m, a, nc, w + nw);
- } else if (m == 4) {
- cftfsub(m, a, w);
- }
- a[n - 1] = a[1] - a[0];
- a[1] = a[0] + a[1];
- for (j = m - 2; j >= 2; j -= 2) {
- a[2 * j + 1] = a[j] - a[j + 1];
- a[2 * j - 1] = -a[j] - a[j + 1];
- }
- l = 2;
- m = mh;
- while (m >= 2) {
- dstsub(m, t, nc, w + nw);
- if (m > 4) {
- bitrv2(m, ip + 2, t);
- cftfsub(m, t, w);
- rftfsub(m, t, nc, w + nw);
- } else if (m == 4) {
- cftfsub(m, t, w);
- }
- a[n - l] = t[1] - t[0];
- a[l] = t[0] + t[1];
- k = 0;
- for (j = 2; j < m; j += 2) {
- k += l << 2;
- a[k - l] = -t[j] - t[j + 1];
- a[k + l] = t[j] - t[j + 1];
- }
- l <<= 1;
- mh = m >> 1;
- for (j = 1; j < mh; j++) {
- k = m - j;
- t[j] = t[m + k] + t[m + j];
- t[k] = t[m + k] - t[m + j];
- }
- t[0] = t[m + mh];
- m = mh;
- }
- a[l] = t[0];
- }
- a[0] = 0;
-}
-#endif // Not used.
-
-
-/* -------- initializing routines -------- */
-
-
-#include <math.h>
-
-static void makewt(size_t nw, size_t *ip, float *w)
-{
- size_t j, nwh;
- float delta, x, y;
-
- ip[0] = nw;
- ip[1] = 1;
- if (nw > 2) {
- nwh = nw >> 1;
- delta = atanf(1.0f) / nwh;
- w[0] = 1;
- w[1] = 0;
- w[nwh] = (float)cos(delta * nwh);
- w[nwh + 1] = w[nwh];
- if (nwh > 2) {
- for (j = 2; j < nwh; j += 2) {
- x = (float)cos(delta * j);
- y = (float)sin(delta * j);
- w[j] = x;
- w[j + 1] = y;
- w[nw - j] = y;
- w[nw - j + 1] = x;
- }
- bitrv2(nw, ip + 2, w);
- }
- }
-}
-
-
-static void makect(size_t nc, size_t *ip, float *c)
-{
- size_t j, nch;
- float delta;
-
- ip[1] = nc;
- if (nc > 1) {
- nch = nc >> 1;
- delta = atanf(1.0f) / nch;
- c[0] = (float)cos(delta * nch);
- c[nch] = 0.5f * c[0];
- for (j = 1; j < nch; j++) {
- c[j] = 0.5f * (float)cos(delta * j);
- c[nc - j] = 0.5f * (float)sin(delta * j);
- }
- }
-}
-
-
-/* -------- child routines -------- */
-
-
-static void bitrv2(size_t n, size_t *ip, float *a)
-{
- size_t j, j1, k, k1, l, m, m2;
- float xr, xi, yr, yi;
-
- ip[0] = 0;
- l = n;
- m = 1;
- while ((m << 3) < l) {
- l >>= 1;
- for (j = 0; j < m; j++) {
- ip[m + j] = ip[j] + l;
- }
- m <<= 1;
- }
- m2 = 2 * m;
- if ((m << 3) == l) {
- for (k = 0; k < m; k++) {
- for (j = 0; j < k; j++) {
- j1 = 2 * j + ip[k];
- k1 = 2 * k + ip[j];
- xr = a[j1];
- xi = a[j1 + 1];
- yr = a[k1];
- yi = a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- j1 += m2;
- k1 += 2 * m2;
- xr = a[j1];
- xi = a[j1 + 1];
- yr = a[k1];
- yi = a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- j1 += m2;
- k1 -= m2;
- xr = a[j1];
- xi = a[j1 + 1];
- yr = a[k1];
- yi = a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- j1 += m2;
- k1 += 2 * m2;
- xr = a[j1];
- xi = a[j1 + 1];
- yr = a[k1];
- yi = a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- }
- j1 = 2 * k + m2 + ip[k];
- k1 = j1 + m2;
- xr = a[j1];
- xi = a[j1 + 1];
- yr = a[k1];
- yi = a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- }
- } else {
- for (k = 1; k < m; k++) {
- for (j = 0; j < k; j++) {
- j1 = 2 * j + ip[k];
- k1 = 2 * k + ip[j];
- xr = a[j1];
- xi = a[j1 + 1];
- yr = a[k1];
- yi = a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- j1 += m2;
- k1 += m2;
- xr = a[j1];
- xi = a[j1 + 1];
- yr = a[k1];
- yi = a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- }
- }
- }
-}
-
-#if 0 // Not used.
-static void bitrv2conj(int n, int *ip, float *a)
-{
- int j, j1, k, k1, l, m, m2;
- float xr, xi, yr, yi;
-
- ip[0] = 0;
- l = n;
- m = 1;
- while ((m << 3) < l) {
- l >>= 1;
- for (j = 0; j < m; j++) {
- ip[m + j] = ip[j] + l;
- }
- m <<= 1;
- }
- m2 = 2 * m;
- if ((m << 3) == l) {
- for (k = 0; k < m; k++) {
- for (j = 0; j < k; j++) {
- j1 = 2 * j + ip[k];
- k1 = 2 * k + ip[j];
- xr = a[j1];
- xi = -a[j1 + 1];
- yr = a[k1];
- yi = -a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- j1 += m2;
- k1 += 2 * m2;
- xr = a[j1];
- xi = -a[j1 + 1];
- yr = a[k1];
- yi = -a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- j1 += m2;
- k1 -= m2;
- xr = a[j1];
- xi = -a[j1 + 1];
- yr = a[k1];
- yi = -a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- j1 += m2;
- k1 += 2 * m2;
- xr = a[j1];
- xi = -a[j1 + 1];
- yr = a[k1];
- yi = -a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- }
- k1 = 2 * k + ip[k];
- a[k1 + 1] = -a[k1 + 1];
- j1 = k1 + m2;
- k1 = j1 + m2;
- xr = a[j1];
- xi = -a[j1 + 1];
- yr = a[k1];
- yi = -a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- k1 += m2;
- a[k1 + 1] = -a[k1 + 1];
- }
- } else {
- a[1] = -a[1];
- a[m2 + 1] = -a[m2 + 1];
- for (k = 1; k < m; k++) {
- for (j = 0; j < k; j++) {
- j1 = 2 * j + ip[k];
- k1 = 2 * k + ip[j];
- xr = a[j1];
- xi = -a[j1 + 1];
- yr = a[k1];
- yi = -a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- j1 += m2;
- k1 += m2;
- xr = a[j1];
- xi = -a[j1 + 1];
- yr = a[k1];
- yi = -a[k1 + 1];
- a[j1] = yr;
- a[j1 + 1] = yi;
- a[k1] = xr;
- a[k1 + 1] = xi;
- }
- k1 = 2 * k + ip[k];
- a[k1 + 1] = -a[k1 + 1];
- a[k1 + m2 + 1] = -a[k1 + m2 + 1];
- }
- }
-}
-#endif
-
-static void cftfsub(size_t n, float *a, float *w)
-{
- size_t j, j1, j2, j3, l;
- float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
-
- l = 2;
- if (n > 8) {
- cft1st(n, a, w);
- l = 8;
- while ((l << 2) < n) {
- cftmdl(n, l, a, w);
- l <<= 2;
- }
- }
- if ((l << 2) == n) {
- for (j = 0; j < l; j += 2) {
- j1 = j + l;
- j2 = j1 + l;
- j3 = j2 + l;
- x0r = a[j] + a[j1];
- x0i = a[j + 1] + a[j1 + 1];
- x1r = a[j] - a[j1];
- x1i = a[j + 1] - a[j1 + 1];
- x2r = a[j2] + a[j3];
- x2i = a[j2 + 1] + a[j3 + 1];
- x3r = a[j2] - a[j3];
- x3i = a[j2 + 1] - a[j3 + 1];
- a[j] = x0r + x2r;
- a[j + 1] = x0i + x2i;
- a[j2] = x0r - x2r;
- a[j2 + 1] = x0i - x2i;
- a[j1] = x1r - x3i;
- a[j1 + 1] = x1i + x3r;
- a[j3] = x1r + x3i;
- a[j3 + 1] = x1i - x3r;
- }
- } else {
- for (j = 0; j < l; j += 2) {
- j1 = j + l;
- x0r = a[j] - a[j1];
- x0i = a[j + 1] - a[j1 + 1];
- a[j] += a[j1];
- a[j + 1] += a[j1 + 1];
- a[j1] = x0r;
- a[j1 + 1] = x0i;
- }
- }
-}
-
-
-static void cftbsub(size_t n, float *a, float *w)
-{
- size_t j, j1, j2, j3, l;
- float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
-
- l = 2;
- if (n > 8) {
- cft1st(n, a, w);
- l = 8;
- while ((l << 2) < n) {
- cftmdl(n, l, a, w);
- l <<= 2;
- }
- }
- if ((l << 2) == n) {
- for (j = 0; j < l; j += 2) {
- j1 = j + l;
- j2 = j1 + l;
- j3 = j2 + l;
- x0r = a[j] + a[j1];
- x0i = -a[j + 1] - a[j1 + 1];
- x1r = a[j] - a[j1];
- x1i = -a[j + 1] + a[j1 + 1];
- x2r = a[j2] + a[j3];
- x2i = a[j2 + 1] + a[j3 + 1];
- x3r = a[j2] - a[j3];
- x3i = a[j2 + 1] - a[j3 + 1];
- a[j] = x0r + x2r;
- a[j + 1] = x0i - x2i;
- a[j2] = x0r - x2r;
- a[j2 + 1] = x0i + x2i;
- a[j1] = x1r - x3i;
- a[j1 + 1] = x1i - x3r;
- a[j3] = x1r + x3i;
- a[j3 + 1] = x1i + x3r;
- }
- } else {
- for (j = 0; j < l; j += 2) {
- j1 = j + l;
- x0r = a[j] - a[j1];
- x0i = -a[j + 1] + a[j1 + 1];
- a[j] += a[j1];
- a[j + 1] = -a[j + 1] - a[j1 + 1];
- a[j1] = x0r;
- a[j1 + 1] = x0i;
- }
- }
-}
-
-
-static void cft1st(size_t n, float *a, float *w)
-{
- size_t j, k1, k2;
- float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
- float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
-
- x0r = a[0] + a[2];
- x0i = a[1] + a[3];
- x1r = a[0] - a[2];
- x1i = a[1] - a[3];
- x2r = a[4] + a[6];
- x2i = a[5] + a[7];
- x3r = a[4] - a[6];
- x3i = a[5] - a[7];
- a[0] = x0r + x2r;
- a[1] = x0i + x2i;
- a[4] = x0r - x2r;
- a[5] = x0i - x2i;
- a[2] = x1r - x3i;
- a[3] = x1i + x3r;
- a[6] = x1r + x3i;
- a[7] = x1i - x3r;
- wk1r = w[2];
- x0r = a[8] + a[10];
- x0i = a[9] + a[11];
- x1r = a[8] - a[10];
- x1i = a[9] - a[11];
- x2r = a[12] + a[14];
- x2i = a[13] + a[15];
- x3r = a[12] - a[14];
- x3i = a[13] - a[15];
- a[8] = x0r + x2r;
- a[9] = x0i + x2i;
- a[12] = x2i - x0i;
- a[13] = x0r - x2r;
- x0r = x1r - x3i;
- x0i = x1i + x3r;
- a[10] = wk1r * (x0r - x0i);
- a[11] = wk1r * (x0r + x0i);
- x0r = x3i + x1r;
- x0i = x3r - x1i;
- a[14] = wk1r * (x0i - x0r);
- a[15] = wk1r * (x0i + x0r);
- k1 = 0;
- for (j = 16; j < n; j += 16) {
- k1 += 2;
- k2 = 2 * k1;
- wk2r = w[k1];
- wk2i = w[k1 + 1];
- wk1r = w[k2];
- wk1i = w[k2 + 1];
- wk3r = wk1r - 2 * wk2i * wk1i;
- wk3i = 2 * wk2i * wk1r - wk1i;
- x0r = a[j] + a[j + 2];
- x0i = a[j + 1] + a[j + 3];
- x1r = a[j] - a[j + 2];
- x1i = a[j + 1] - a[j + 3];
- x2r = a[j + 4] + a[j + 6];
- x2i = a[j + 5] + a[j + 7];
- x3r = a[j + 4] - a[j + 6];
- x3i = a[j + 5] - a[j + 7];
- a[j] = x0r + x2r;
- a[j + 1] = x0i + x2i;
- x0r -= x2r;
- x0i -= x2i;
- a[j + 4] = wk2r * x0r - wk2i * x0i;
- a[j + 5] = wk2r * x0i + wk2i * x0r;
- x0r = x1r - x3i;
- x0i = x1i + x3r;
- a[j + 2] = wk1r * x0r - wk1i * x0i;
- a[j + 3] = wk1r * x0i + wk1i * x0r;
- x0r = x1r + x3i;
- x0i = x1i - x3r;
- a[j + 6] = wk3r * x0r - wk3i * x0i;
- a[j + 7] = wk3r * x0i + wk3i * x0r;
- wk1r = w[k2 + 2];
- wk1i = w[k2 + 3];
- wk3r = wk1r - 2 * wk2r * wk1i;
- wk3i = 2 * wk2r * wk1r - wk1i;
- x0r = a[j + 8] + a[j + 10];
- x0i = a[j + 9] + a[j + 11];
- x1r = a[j + 8] - a[j + 10];
- x1i = a[j + 9] - a[j + 11];
- x2r = a[j + 12] + a[j + 14];
- x2i = a[j + 13] + a[j + 15];
- x3r = a[j + 12] - a[j + 14];
- x3i = a[j + 13] - a[j + 15];
- a[j + 8] = x0r + x2r;
- a[j + 9] = x0i + x2i;
- x0r -= x2r;
- x0i -= x2i;
- a[j + 12] = -wk2i * x0r - wk2r * x0i;
- a[j + 13] = -wk2i * x0i + wk2r * x0r;
- x0r = x1r - x3i;
- x0i = x1i + x3r;
- a[j + 10] = wk1r * x0r - wk1i * x0i;
- a[j + 11] = wk1r * x0i + wk1i * x0r;
- x0r = x1r + x3i;
- x0i = x1i - x3r;
- a[j + 14] = wk3r * x0r - wk3i * x0i;
- a[j + 15] = wk3r * x0i + wk3i * x0r;
- }
-}
-
-
-static void cftmdl(size_t n, size_t l, float *a, float *w)
-{
- size_t j, j1, j2, j3, k, k1, k2, m, m2;
- float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
- float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
-
- m = l << 2;
- for (j = 0; j < l; j += 2) {
- j1 = j + l;
- j2 = j1 + l;
- j3 = j2 + l;
- x0r = a[j] + a[j1];
- x0i = a[j + 1] + a[j1 + 1];
- x1r = a[j] - a[j1];
- x1i = a[j + 1] - a[j1 + 1];
- x2r = a[j2] + a[j3];
- x2i = a[j2 + 1] + a[j3 + 1];
- x3r = a[j2] - a[j3];
- x3i = a[j2 + 1] - a[j3 + 1];
- a[j] = x0r + x2r;
- a[j + 1] = x0i + x2i;
- a[j2] = x0r - x2r;
- a[j2 + 1] = x0i - x2i;
- a[j1] = x1r - x3i;
- a[j1 + 1] = x1i + x3r;
- a[j3] = x1r + x3i;
- a[j3 + 1] = x1i - x3r;
- }
- wk1r = w[2];
- for (j = m; j < l + m; j += 2) {
- j1 = j + l;
- j2 = j1 + l;
- j3 = j2 + l;
- x0r = a[j] + a[j1];
- x0i = a[j + 1] + a[j1 + 1];
- x1r = a[j] - a[j1];
- x1i = a[j + 1] - a[j1 + 1];
- x2r = a[j2] + a[j3];
- x2i = a[j2 + 1] + a[j3 + 1];
- x3r = a[j2] - a[j3];
- x3i = a[j2 + 1] - a[j3 + 1];
- a[j] = x0r + x2r;
- a[j + 1] = x0i + x2i;
- a[j2] = x2i - x0i;
- a[j2 + 1] = x0r - x2r;
- x0r = x1r - x3i;
- x0i = x1i + x3r;
- a[j1] = wk1r * (x0r - x0i);
- a[j1 + 1] = wk1r * (x0r + x0i);
- x0r = x3i + x1r;
- x0i = x3r - x1i;
- a[j3] = wk1r * (x0i - x0r);
- a[j3 + 1] = wk1r * (x0i + x0r);
- }
- k1 = 0;
- m2 = 2 * m;
- for (k = m2; k < n; k += m2) {
- k1 += 2;
- k2 = 2 * k1;
- wk2r = w[k1];
- wk2i = w[k1 + 1];
- wk1r = w[k2];
- wk1i = w[k2 + 1];
- wk3r = wk1r - 2 * wk2i * wk1i;
- wk3i = 2 * wk2i * wk1r - wk1i;
- for (j = k; j < l + k; j += 2) {
- j1 = j + l;
- j2 = j1 + l;
- j3 = j2 + l;
- x0r = a[j] + a[j1];
- x0i = a[j + 1] + a[j1 + 1];
- x1r = a[j] - a[j1];
- x1i = a[j + 1] - a[j1 + 1];
- x2r = a[j2] + a[j3];
- x2i = a[j2 + 1] + a[j3 + 1];
- x3r = a[j2] - a[j3];
- x3i = a[j2 + 1] - a[j3 + 1];
- a[j] = x0r + x2r;
- a[j + 1] = x0i + x2i;
- x0r -= x2r;
- x0i -= x2i;
- a[j2] = wk2r * x0r - wk2i * x0i;
- a[j2 + 1] = wk2r * x0i + wk2i * x0r;
- x0r = x1r - x3i;
- x0i = x1i + x3r;
- a[j1] = wk1r * x0r - wk1i * x0i;
- a[j1 + 1] = wk1r * x0i + wk1i * x0r;
- x0r = x1r + x3i;
- x0i = x1i - x3r;
- a[j3] = wk3r * x0r - wk3i * x0i;
- a[j3 + 1] = wk3r * x0i + wk3i * x0r;
- }
- wk1r = w[k2 + 2];
- wk1i = w[k2 + 3];
- wk3r = wk1r - 2 * wk2r * wk1i;
- wk3i = 2 * wk2r * wk1r - wk1i;
- for (j = k + m; j < l + (k + m); j += 2) {
- j1 = j + l;
- j2 = j1 + l;
- j3 = j2 + l;
- x0r = a[j] + a[j1];
- x0i = a[j + 1] + a[j1 + 1];
- x1r = a[j] - a[j1];
- x1i = a[j + 1] - a[j1 + 1];
- x2r = a[j2] + a[j3];
- x2i = a[j2 + 1] + a[j3 + 1];
- x3r = a[j2] - a[j3];
- x3i = a[j2 + 1] - a[j3 + 1];
- a[j] = x0r + x2r;
- a[j + 1] = x0i + x2i;
- x0r -= x2r;
- x0i -= x2i;
- a[j2] = -wk2i * x0r - wk2r * x0i;
- a[j2 + 1] = -wk2i * x0i + wk2r * x0r;
- x0r = x1r - x3i;
- x0i = x1i + x3r;
- a[j1] = wk1r * x0r - wk1i * x0i;
- a[j1 + 1] = wk1r * x0i + wk1i * x0r;
- x0r = x1r + x3i;
- x0i = x1i - x3r;
- a[j3] = wk3r * x0r - wk3i * x0i;
- a[j3 + 1] = wk3r * x0i + wk3i * x0r;
- }
- }
-}
-
-
-static void rftfsub(size_t n, float *a, size_t nc, float *c)
-{
- size_t j, k, kk, ks, m;
- float wkr, wki, xr, xi, yr, yi;
-
- m = n >> 1;
- ks = 2 * nc / m;
- kk = 0;
- for (j = 2; j < m; j += 2) {
- k = n - j;
- kk += ks;
- wkr = 0.5f - c[nc - kk];
- wki = c[kk];
- xr = a[j] - a[k];
- xi = a[j + 1] + a[k + 1];
- yr = wkr * xr - wki * xi;
- yi = wkr * xi + wki * xr;
- a[j] -= yr;
- a[j + 1] -= yi;
- a[k] += yr;
- a[k + 1] -= yi;
- }
-}
-
-
-static void rftbsub(size_t n, float *a, size_t nc, float *c)
-{
- size_t j, k, kk, ks, m;
- float wkr, wki, xr, xi, yr, yi;
-
- a[1] = -a[1];
- m = n >> 1;
- ks = 2 * nc / m;
- kk = 0;
- for (j = 2; j < m; j += 2) {
- k = n - j;
- kk += ks;
- wkr = 0.5f - c[nc - kk];
- wki = c[kk];
- xr = a[j] - a[k];
- xi = a[j + 1] + a[k + 1];
- yr = wkr * xr + wki * xi;
- yi = wkr * xi - wki * xr;
- a[j] -= yr;
- a[j + 1] = yi - a[j + 1];
- a[k] += yr;
- a[k + 1] = yi - a[k + 1];
- }
- a[m + 1] = -a[m + 1];
-}
-
-#if 0 // Not used.
-static void dctsub(int n, float *a, int nc, float *c)
-{
- int j, k, kk, ks, m;
- float wkr, wki, xr;
-
- m = n >> 1;
- ks = nc / n;
- kk = 0;
- for (j = 1; j < m; j++) {
- k = n - j;
- kk += ks;
- wkr = c[kk] - c[nc - kk];
- wki = c[kk] + c[nc - kk];
- xr = wki * a[j] - wkr * a[k];
- a[j] = wkr * a[j] + wki * a[k];
- a[k] = xr;
- }
- a[m] *= c[0];
-}
-
-
-static void dstsub(int n, float *a, int nc, float *c)
-{
- int j, k, kk, ks, m;
- float wkr, wki, xr;
-
- m = n >> 1;
- ks = nc / n;
- kk = 0;
- for (j = 1; j < m; j++) {
- k = n - j;
- kk += ks;
- wkr = c[kk] - c[nc - kk];
- wki = c[kk] + c[nc - kk];
- xr = wki * a[k] - wkr * a[j];
- a[k] = wkr * a[k] + wki * a[j];
- a[j] = xr;
- }
- a[m] *= c[0];
-}
-#endif // Not used.
diff --git a/webrtc/common_audio/fft4g.h b/webrtc/common_audio/fft4g.h
deleted file mode 100644
index 6dd792f..0000000
--- a/webrtc/common_audio/fft4g.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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 WEBRTC_COMMON_AUDIO_FFT4G_H_
-#define WEBRTC_COMMON_AUDIO_FFT4G_H_
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-// Refer to fft4g.c for documentation.
-void WebRtc_rdft(size_t n, int isgn, float *a, size_t *ip, float *w);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif // WEBRTC_COMMON_AUDIO_FFT4G_H_
diff --git a/webrtc/common_audio/fir_filter.cc b/webrtc/common_audio/fir_filter.cc
deleted file mode 100644
index dc1b776..0000000
--- a/webrtc/common_audio/fir_filter.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/common_audio/fir_filter.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/fir_filter_neon.h"
-#include "webrtc/common_audio/fir_filter_sse.h"
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
-
-namespace webrtc {
-
-class FIRFilterC : public FIRFilter {
- public:
- FIRFilterC(const float* coefficients,
- size_t coefficients_length);
-
- void Filter(const float* in, size_t length, float* out) override;
-
- private:
- size_t coefficients_length_;
- size_t state_length_;
- rtc::scoped_ptr<float[]> coefficients_;
- rtc::scoped_ptr<float[]> state_;
-};
-
-FIRFilter* FIRFilter::Create(const float* coefficients,
- size_t coefficients_length,
- size_t max_input_length) {
- if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) {
- assert(false);
- return NULL;
- }
-
- FIRFilter* filter = NULL;
-// If we know the minimum architecture at compile time, avoid CPU detection.
-#if defined(WEBRTC_ARCH_X86_FAMILY)
-#if defined(__SSE2__)
- filter =
- new FIRFilterSSE2(coefficients, coefficients_length, max_input_length);
-#else
- // x86 CPU detection required.
- if (WebRtc_GetCPUInfo(kSSE2)) {
- filter =
- new FIRFilterSSE2(coefficients, coefficients_length, max_input_length);
- } else {
- filter = new FIRFilterC(coefficients, coefficients_length);
- }
-#endif
-#elif defined(WEBRTC_HAS_NEON)
- filter =
- new FIRFilterNEON(coefficients, coefficients_length, max_input_length);
-#elif defined(WEBRTC_DETECT_NEON)
- if (WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) {
- filter =
- new FIRFilterNEON(coefficients, coefficients_length, max_input_length);
- } else {
- filter = new FIRFilterC(coefficients, coefficients_length);
- }
-#else
- filter = new FIRFilterC(coefficients, coefficients_length);
-#endif
-
- return filter;
-}
-
-FIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length)
- : coefficients_length_(coefficients_length),
- state_length_(coefficients_length - 1),
- coefficients_(new float[coefficients_length_]),
- state_(new float[state_length_]) {
- for (size_t i = 0; i < coefficients_length_; ++i) {
- coefficients_[i] = coefficients[coefficients_length_ - i - 1];
- }
- memset(state_.get(), 0, state_length_ * sizeof(state_[0]));
-}
-
-void FIRFilterC::Filter(const float* in, size_t length, float* out) {
- assert(length > 0);
-
- // Convolves the input signal |in| with the filter kernel |coefficients_|
- // taking into account the previous state.
- for (size_t i = 0; i < length; ++i) {
- out[i] = 0.f;
- size_t j;
- for (j = 0; state_length_ > i && j < state_length_ - i; ++j) {
- out[i] += state_[i + j] * coefficients_[j];
- }
- for (; j < coefficients_length_; ++j) {
- out[i] += in[j + i - state_length_] * coefficients_[j];
- }
- }
-
- // Update current state.
- if (length >= state_length_) {
- memcpy(
- state_.get(), &in[length - state_length_], state_length_ * sizeof(*in));
- } else {
- memmove(state_.get(),
- &state_[length],
- (state_length_ - length) * sizeof(state_[0]));
- memcpy(&state_[state_length_ - length], in, length * sizeof(*in));
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/common_audio/fir_filter.h b/webrtc/common_audio/fir_filter.h
index a5dc6ec..a76e936 100644
--- a/webrtc/common_audio/fir_filter.h
+++ b/webrtc/common_audio/fir_filter.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_FIR_FILTER_H_
-#define WEBRTC_COMMON_AUDIO_FIR_FILTER_H_
+#ifndef COMMON_AUDIO_FIR_FILTER_H_
+#define COMMON_AUDIO_FIR_FILTER_H_
#include <string.h>
@@ -18,16 +18,6 @@ namespace webrtc {
// Finite Impulse Response filter using floating-point arithmetic.
class FIRFilter {
public:
- // Creates a filter with the given coefficients. All initial state values will
- // be zeros.
- // The length of the chunks fed to the filter should never be greater than
- // |max_input_length|. This is needed because, when vectorizing it is
- // necessary to concatenate the input after the state, and resizing this array
- // dynamically is expensive.
- static FIRFilter* Create(const float* coefficients,
- size_t coefficients_length,
- size_t max_input_length);
-
virtual ~FIRFilter() {}
// Filters the |in| data supplied.
@@ -37,4 +27,4 @@ class FIRFilter {
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_FIR_FILTER_H_
+#endif // COMMON_AUDIO_FIR_FILTER_H_
diff --git a/webrtc/common_audio/fir_filter_avx2.cc b/webrtc/common_audio/fir_filter_avx2.cc
new file mode 100644
index 0000000..26468e2
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_avx2.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "common_audio/fir_filter_avx2.h"
+
+#include <immintrin.h>
+#include <stdint.h>
+#include <string.h>
+#include <xmmintrin.h>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/memory/aligned_malloc.h"
+
+namespace webrtc {
+
+FIRFilterAVX2::FIRFilterAVX2(const float* unaligned_coefficients,
+ size_t unaligned_coefficients_length,
+ size_t max_input_length)
+ : // Closest higher multiple of eight.
+ coefficients_length_((unaligned_coefficients_length + 7) & ~0x07),
+ state_length_(coefficients_length_ - 1),
+ coefficients_(static_cast<float*>(
+ AlignedMalloc(sizeof(float) * coefficients_length_, 32))),
+ state_(static_cast<float*>(
+ AlignedMalloc(sizeof(float) * (max_input_length + state_length_),
+ 32))) {
+ // Add zeros at the end of the coefficients.
+ RTC_DCHECK_GE(coefficients_length_, unaligned_coefficients_length);
+ size_t padding = coefficients_length_ - unaligned_coefficients_length;
+ memset(coefficients_.get(), 0, padding * sizeof(coefficients_[0]));
+ // The coefficients are reversed to compensate for the order in which the
+ // input samples are acquired (most recent last).
+ for (size_t i = 0; i < unaligned_coefficients_length; ++i) {
+ coefficients_[i + padding] =
+ unaligned_coefficients[unaligned_coefficients_length - i - 1];
+ }
+ memset(state_.get(), 0,
+ (max_input_length + state_length_) * sizeof(state_[0]));
+}
+
+FIRFilterAVX2::~FIRFilterAVX2() = default;
+
+void FIRFilterAVX2::Filter(const float* in, size_t length, float* out) {
+ RTC_DCHECK_GT(length, 0);
+
+ memcpy(&state_[state_length_], in, length * sizeof(*in));
+
+ // Convolves the input signal |in| with the filter kernel |coefficients_|
+ // taking into account the previous state.
+ for (size_t i = 0; i < length; ++i) {
+ float* in_ptr = &state_[i];
+ float* coef_ptr = coefficients_.get();
+
+ __m256 m_sum = _mm256_setzero_ps();
+ __m256 m_in;
+
+ // Depending on if the pointer is aligned with 32 bytes or not it is loaded
+ // differently.
+ if (reinterpret_cast<uintptr_t>(in_ptr) & 0x1F) {
+ for (size_t j = 0; j < coefficients_length_; j += 8) {
+ m_in = _mm256_loadu_ps(in_ptr + j);
+ m_sum = _mm256_fmadd_ps(m_in, _mm256_load_ps(coef_ptr + j), m_sum);
+ }
+ } else {
+ for (size_t j = 0; j < coefficients_length_; j += 8) {
+ m_in = _mm256_load_ps(in_ptr + j);
+ m_sum = _mm256_fmadd_ps(m_in, _mm256_load_ps(coef_ptr + j), m_sum);
+ }
+ }
+ __m128 m128_sum = _mm_add_ps(_mm256_extractf128_ps(m_sum, 0),
+ _mm256_extractf128_ps(m_sum, 1));
+ m128_sum = _mm_add_ps(_mm_movehl_ps(m128_sum, m128_sum), m128_sum);
+ _mm_store_ss(out + i,
+ _mm_add_ss(m128_sum, _mm_shuffle_ps(m128_sum, m128_sum, 1)));
+ }
+
+ // Update current state.
+ memmove(state_.get(), &state_[length], state_length_ * sizeof(state_[0]));
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/fir_filter_avx2.h b/webrtc/common_audio/fir_filter_avx2.h
new file mode 100644
index 0000000..893b60b
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_avx2.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef COMMON_AUDIO_FIR_FILTER_AVX2_H_
+#define COMMON_AUDIO_FIR_FILTER_AVX2_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "common_audio/fir_filter.h"
+#include "rtc_base/memory/aligned_malloc.h"
+
+namespace webrtc {
+
+class FIRFilterAVX2 : public FIRFilter {
+ public:
+ FIRFilterAVX2(const float* coefficients,
+ size_t coefficients_length,
+ size_t max_input_length);
+ ~FIRFilterAVX2() override;
+
+ void Filter(const float* in, size_t length, float* out) override;
+
+ private:
+ const size_t coefficients_length_;
+ const size_t state_length_;
+ std::unique_ptr<float[], AlignedFreeDeleter> coefficients_;
+ std::unique_ptr<float[], AlignedFreeDeleter> state_;
+};
+
+} // namespace webrtc
+
+#endif // COMMON_AUDIO_FIR_FILTER_AVX2_H_
diff --git a/webrtc/common_audio/fir_filter_c.cc b/webrtc/common_audio/fir_filter_c.cc
new file mode 100644
index 0000000..3f1fa09
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_c.cc
@@ -0,0 +1,61 @@
+/*
+ * 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 "common_audio/fir_filter_c.h"
+
+#include <string.h>
+
+#include <memory>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+FIRFilterC::~FIRFilterC() {}
+
+FIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length)
+ : coefficients_length_(coefficients_length),
+ state_length_(coefficients_length - 1),
+ coefficients_(new float[coefficients_length_]),
+ state_(new float[state_length_]) {
+ for (size_t i = 0; i < coefficients_length_; ++i) {
+ coefficients_[i] = coefficients[coefficients_length_ - i - 1];
+ }
+ memset(state_.get(), 0, state_length_ * sizeof(state_[0]));
+}
+
+void FIRFilterC::Filter(const float* in, size_t length, float* out) {
+ RTC_DCHECK_GT(length, 0);
+
+ // Convolves the input signal |in| with the filter kernel |coefficients_|
+ // taking into account the previous state.
+ for (size_t i = 0; i < length; ++i) {
+ out[i] = 0.f;
+ size_t j;
+ for (j = 0; state_length_ > i && j < state_length_ - i; ++j) {
+ out[i] += state_[i + j] * coefficients_[j];
+ }
+ for (; j < coefficients_length_; ++j) {
+ out[i] += in[j + i - state_length_] * coefficients_[j];
+ }
+ }
+
+ // Update current state.
+ if (length >= state_length_) {
+ memcpy(state_.get(), &in[length - state_length_],
+ state_length_ * sizeof(*in));
+ } else {
+ memmove(state_.get(), &state_[length],
+ (state_length_ - length) * sizeof(state_[0]));
+ memcpy(&state_[state_length_ - length], in, length * sizeof(*in));
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/fir_filter_c.h b/webrtc/common_audio/fir_filter_c.h
new file mode 100644
index 0000000..b2ae4c3
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_c.h
@@ -0,0 +1,38 @@
+/*
+ * 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 COMMON_AUDIO_FIR_FILTER_C_H_
+#define COMMON_AUDIO_FIR_FILTER_C_H_
+
+#include <string.h>
+
+#include <memory>
+
+#include "common_audio/fir_filter.h"
+
+namespace webrtc {
+
+class FIRFilterC : public FIRFilter {
+ public:
+ FIRFilterC(const float* coefficients, size_t coefficients_length);
+ ~FIRFilterC() override;
+
+ void Filter(const float* in, size_t length, float* out) override;
+
+ private:
+ size_t coefficients_length_;
+ size_t state_length_;
+ std::unique_ptr<float[]> coefficients_;
+ std::unique_ptr<float[]> state_;
+};
+
+} // namespace webrtc
+
+#endif // COMMON_AUDIO_FIR_FILTER_C_H_
diff --git a/webrtc/common_audio/fir_filter_factory.cc b/webrtc/common_audio/fir_filter_factory.cc
new file mode 100644
index 0000000..4bcf052
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_factory.cc
@@ -0,0 +1,58 @@
+/*
+ * 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 "common_audio/fir_filter_factory.h"
+
+#include "common_audio/fir_filter_c.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/system/arch.h"
+
+#if defined(WEBRTC_HAS_NEON)
+#include "common_audio/fir_filter_neon.h"
+#elif defined(WEBRTC_ARCH_X86_FAMILY)
+#include "common_audio/fir_filter_avx2.h"
+#include "common_audio/fir_filter_sse.h"
+#include "system_wrappers/include/cpu_features_wrapper.h" // kSSE2, WebRtc_G...
+#endif
+
+namespace webrtc {
+
+FIRFilter* CreateFirFilter(const float* coefficients,
+ size_t coefficients_length,
+ size_t max_input_length) {
+ if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) {
+ RTC_NOTREACHED();
+ return nullptr;
+ }
+
+ FIRFilter* filter = nullptr;
+// If we know the minimum architecture at compile time, avoid CPU detection.
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ // x86 CPU detection required.
+ if (GetCPUInfo(kAVX2)) {
+ filter =
+ new FIRFilterAVX2(coefficients, coefficients_length, max_input_length);
+ } else if (GetCPUInfo(kSSE2)) {
+ filter =
+ new FIRFilterSSE2(coefficients, coefficients_length, max_input_length);
+ } else {
+ filter = new FIRFilterC(coefficients, coefficients_length);
+ }
+#elif defined(WEBRTC_HAS_NEON)
+ filter =
+ new FIRFilterNEON(coefficients, coefficients_length, max_input_length);
+#else
+ filter = new FIRFilterC(coefficients, coefficients_length);
+#endif
+
+ return filter;
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/fir_filter_factory.h b/webrtc/common_audio/fir_filter_factory.h
new file mode 100644
index 0000000..a952541
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_factory.h
@@ -0,0 +1,32 @@
+/*
+ * 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 COMMON_AUDIO_FIR_FILTER_FACTORY_H_
+#define COMMON_AUDIO_FIR_FILTER_FACTORY_H_
+
+#include <string.h>
+
+namespace webrtc {
+
+class FIRFilter;
+
+// Creates a filter with the given coefficients. All initial state values will
+// be zeros.
+// The length of the chunks fed to the filter should never be greater than
+// |max_input_length|. This is needed because, when vectorizing it is
+// necessary to concatenate the input after the state, and resizing this array
+// dynamically is expensive.
+FIRFilter* CreateFirFilter(const float* coefficients,
+ size_t coefficients_length,
+ size_t max_input_length);
+
+} // namespace webrtc
+
+#endif // COMMON_AUDIO_FIR_FILTER_FACTORY_H_
diff --git a/webrtc/common_audio/fir_filter_neon.cc b/webrtc/common_audio/fir_filter_neon.cc
index a815626..f668841 100644
--- a/webrtc/common_audio/fir_filter_neon.cc
+++ b/webrtc/common_audio/fir_filter_neon.cc
@@ -8,16 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/fir_filter_neon.h"
+#include "common_audio/fir_filter_neon.h"
#include <arm_neon.h>
-#include <assert.h>
#include <string.h>
-#include "webrtc/system_wrappers/include/aligned_malloc.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/memory/aligned_malloc.h"
namespace webrtc {
+FIRFilterNEON::~FIRFilterNEON() {}
+
FIRFilterNEON::FIRFilterNEON(const float* coefficients,
size_t coefficients_length,
size_t max_input_length)
@@ -37,13 +39,12 @@ FIRFilterNEON::FIRFilterNEON(const float* coefficients,
for (size_t i = 0; i < coefficients_length; ++i) {
coefficients_[i + padding] = coefficients[coefficients_length - i - 1];
}
- memset(state_.get(),
- 0.f,
+ memset(state_.get(), 0.f,
(max_input_length + state_length_) * sizeof(state_[0]));
}
void FIRFilterNEON::Filter(const float* in, size_t length, float* out) {
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
memcpy(&state_[state_length_], in, length * sizeof(*in));
@@ -57,8 +58,8 @@ void FIRFilterNEON::Filter(const float* in, size_t length, float* out) {
float32x4_t m_in;
for (size_t j = 0; j < coefficients_length_; j += 4) {
- m_in = vld1q_f32(in_ptr + j);
- m_sum = vmlaq_f32(m_sum, m_in, vld1q_f32(coef_ptr + j));
+ m_in = vld1q_f32(in_ptr + j);
+ m_sum = vmlaq_f32(m_sum, m_in, vld1q_f32(coef_ptr + j));
}
float32x2_t m_half = vadd_f32(vget_high_f32(m_sum), vget_low_f32(m_sum));
diff --git a/webrtc/common_audio/fir_filter_neon.h b/webrtc/common_audio/fir_filter_neon.h
index 3aa6168..1ffefd8 100644
--- a/webrtc/common_audio/fir_filter_neon.h
+++ b/webrtc/common_audio/fir_filter_neon.h
@@ -8,12 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_FIR_FILTER_NEON_H_
-#define WEBRTC_COMMON_AUDIO_FIR_FILTER_NEON_H_
+#ifndef COMMON_AUDIO_FIR_FILTER_NEON_H_
+#define COMMON_AUDIO_FIR_FILTER_NEON_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/fir_filter.h"
-#include "webrtc/system_wrappers/include/aligned_malloc.h"
+#include <memory>
+
+#include "common_audio/fir_filter.h"
+#include "rtc_base/memory/aligned_malloc.h"
namespace webrtc {
@@ -22,16 +23,17 @@ class FIRFilterNEON : public FIRFilter {
FIRFilterNEON(const float* coefficients,
size_t coefficients_length,
size_t max_input_length);
+ ~FIRFilterNEON() override;
void Filter(const float* in, size_t length, float* out) override;
private:
size_t coefficients_length_;
size_t state_length_;
- rtc::scoped_ptr<float[], AlignedFreeDeleter> coefficients_;
- rtc::scoped_ptr<float[], AlignedFreeDeleter> state_;
+ std::unique_ptr<float[], AlignedFreeDeleter> coefficients_;
+ std::unique_ptr<float[], AlignedFreeDeleter> state_;
};
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_FIR_FILTER_NEON_H_
+#endif // COMMON_AUDIO_FIR_FILTER_NEON_H_
diff --git a/webrtc/common_audio/fir_filter_sse.cc b/webrtc/common_audio/fir_filter_sse.cc
index adbb2b7..ee75fb3 100644
--- a/webrtc/common_audio/fir_filter_sse.cc
+++ b/webrtc/common_audio/fir_filter_sse.cc
@@ -8,16 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/fir_filter_sse.h"
+#include "common_audio/fir_filter_sse.h"
-#include <assert.h>
+#include <stdint.h>
#include <string.h>
#include <xmmintrin.h>
-#include "webrtc/system_wrappers/include/aligned_malloc.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/memory/aligned_malloc.h"
namespace webrtc {
+FIRFilterSSE2::~FIRFilterSSE2() {}
+
FIRFilterSSE2::FIRFilterSSE2(const float* coefficients,
size_t coefficients_length,
size_t max_input_length)
@@ -37,13 +40,12 @@ FIRFilterSSE2::FIRFilterSSE2(const float* coefficients,
for (size_t i = 0; i < coefficients_length; ++i) {
coefficients_[i + padding] = coefficients[coefficients_length - i - 1];
}
- memset(state_.get(),
- 0,
+ memset(state_.get(), 0,
(max_input_length + state_length_) * sizeof(state_[0]));
}
void FIRFilterSSE2::Filter(const float* in, size_t length, float* out) {
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
memcpy(&state_[state_length_], in, length * sizeof(*in));
diff --git a/webrtc/common_audio/fir_filter_sse.h b/webrtc/common_audio/fir_filter_sse.h
index a3325cd..32f4945 100644
--- a/webrtc/common_audio/fir_filter_sse.h
+++ b/webrtc/common_audio/fir_filter_sse.h
@@ -8,12 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_FIR_FILTER_SSE_H_
-#define WEBRTC_COMMON_AUDIO_FIR_FILTER_SSE_H_
+#ifndef COMMON_AUDIO_FIR_FILTER_SSE_H_
+#define COMMON_AUDIO_FIR_FILTER_SSE_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/fir_filter.h"
-#include "webrtc/system_wrappers/include/aligned_malloc.h"
+#include <stddef.h>
+
+#include <memory>
+
+#include "common_audio/fir_filter.h"
+#include "rtc_base/memory/aligned_malloc.h"
namespace webrtc {
@@ -22,16 +25,17 @@ class FIRFilterSSE2 : public FIRFilter {
FIRFilterSSE2(const float* coefficients,
size_t coefficients_length,
size_t max_input_length);
+ ~FIRFilterSSE2() override;
void Filter(const float* in, size_t length, float* out) override;
private:
size_t coefficients_length_;
size_t state_length_;
- rtc::scoped_ptr<float[], AlignedFreeDeleter> coefficients_;
- rtc::scoped_ptr<float[], AlignedFreeDeleter> state_;
+ std::unique_ptr<float[], AlignedFreeDeleter> coefficients_;
+ std::unique_ptr<float[], AlignedFreeDeleter> state_;
};
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_FIR_FILTER_SSE_H_
+#endif // COMMON_AUDIO_FIR_FILTER_SSE_H_
diff --git a/webrtc/common_audio/include/audio_util.h b/webrtc/common_audio/include/audio_util.h
index 2c0028c..f6b6bfd 100644
--- a/webrtc/common_audio/include/audio_util.h
+++ b/webrtc/common_audio/include/audio_util.h
@@ -8,15 +8,17 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
-#define WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
+#ifndef COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
+#define COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
-#include <limits>
+#include <stdint.h>
+
+#include <algorithm>
+#include <cmath>
#include <cstring>
+#include <limits>
-#include "webrtc/base/checks.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/typedefs.h"
+#include "rtc_base/checks.h"
namespace webrtc {
@@ -25,46 +27,70 @@ typedef std::numeric_limits<int16_t> limits_int16;
// The conversion functions use the following naming convention:
// S16: int16_t [-32768, 32767]
// Float: float [-1.0, 1.0]
-// FloatS16: float [-32768.0, 32767.0]
-static inline int16_t FloatToS16(float v) {
- if (v > 0)
- return v >= 1 ? limits_int16::max()
- : static_cast<int16_t>(v * limits_int16::max() + 0.5f);
- return v <= -1 ? limits_int16::min()
- : static_cast<int16_t>(-v * limits_int16::min() - 0.5f);
-}
-
+// FloatS16: float [-32768.0, 32768.0]
+// Dbfs: float [-20.0*log(10, 32768), 0] = [-90.3, 0]
+// The ratio conversion functions use this naming convention:
+// Ratio: float (0, +inf)
+// Db: float (-inf, +inf)
static inline float S16ToFloat(int16_t v) {
- static const float kMaxInt16Inverse = 1.f / limits_int16::max();
- static const float kMinInt16Inverse = 1.f / limits_int16::min();
- return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
+ constexpr float kScaling = 1.f / 32768.f;
+ return v * kScaling;
}
static inline int16_t FloatS16ToS16(float v) {
- static const float kMaxRound = limits_int16::max() - 0.5f;
- static const float kMinRound = limits_int16::min() + 0.5f;
- if (v > 0)
- return v >= kMaxRound ? limits_int16::max()
- : static_cast<int16_t>(v + 0.5f);
- return v <= kMinRound ? limits_int16::min() : static_cast<int16_t>(v - 0.5f);
+ v = std::min(v, 32767.f);
+ v = std::max(v, -32768.f);
+ return static_cast<int16_t>(v + std::copysign(0.5f, v));
+}
+
+static inline int16_t FloatToS16(float v) {
+ v *= 32768.f;
+ v = std::min(v, 32767.f);
+ v = std::max(v, -32768.f);
+ return static_cast<int16_t>(v + std::copysign(0.5f, v));
}
static inline float FloatToFloatS16(float v) {
- return v * (v > 0 ? limits_int16::max() : -limits_int16::min());
+ v = std::min(v, 1.f);
+ v = std::max(v, -1.f);
+ return v * 32768.f;
}
static inline float FloatS16ToFloat(float v) {
- static const float kMaxInt16Inverse = 1.f / limits_int16::max();
- static const float kMinInt16Inverse = 1.f / limits_int16::min();
- return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
+ v = std::min(v, 32768.f);
+ v = std::max(v, -32768.f);
+ constexpr float kScaling = 1.f / 32768.f;
+ return v * kScaling;
}
void FloatToS16(const float* src, size_t size, int16_t* dest);
void S16ToFloat(const int16_t* src, size_t size, float* dest);
+void S16ToFloatS16(const int16_t* src, size_t size, float* dest);
void FloatS16ToS16(const float* src, size_t size, int16_t* dest);
void FloatToFloatS16(const float* src, size_t size, float* dest);
void FloatS16ToFloat(const float* src, size_t size, float* dest);
+inline float DbToRatio(float v) {
+ return std::pow(10.0f, v / 20.0f);
+}
+
+inline float DbfsToFloatS16(float v) {
+ static constexpr float kMaximumAbsFloatS16 = -limits_int16::min();
+ return DbToRatio(v) * kMaximumAbsFloatS16;
+}
+
+inline float FloatS16ToDbfs(float v) {
+ RTC_DCHECK_GE(v, 0);
+
+ // kMinDbfs is equal to -20.0 * log10(-limits_int16::min())
+ static constexpr float kMinDbfs = -90.30899869919436f;
+ if (v <= 1.0f) {
+ return kMinDbfs;
+ }
+ // Equal to 20 * log10(v / (-limits_int16::min()))
+ return 20.0f * std::log10(v) + kMinDbfs;
+}
+
// Copy audio from |src| channels to |dest| channels unless |src| and |dest|
// point to the same address. |src| and |dest| must have the same number of
// channels, and there must be sufficient space allocated in |dest|.
@@ -87,11 +113,11 @@ void CopyAudioIfNeeded(const T* const* src,
template <typename T>
void Deinterleave(const T* interleaved,
size_t samples_per_channel,
- int num_channels,
+ size_t num_channels,
T* const* deinterleaved) {
- for (int i = 0; i < num_channels; ++i) {
+ for (size_t i = 0; i < num_channels; ++i) {
T* channel = deinterleaved[i];
- int interleaved_idx = i;
+ size_t interleaved_idx = i;
for (size_t j = 0; j < samples_per_channel; ++j) {
channel[j] = interleaved[interleaved_idx];
interleaved_idx += num_channels;
@@ -105,11 +131,11 @@ void Deinterleave(const T* interleaved,
template <typename T>
void Interleave(const T* const* deinterleaved,
size_t samples_per_channel,
- int num_channels,
+ size_t num_channels,
T* interleaved) {
- for (int i = 0; i < num_channels; ++i) {
+ for (size_t i = 0; i < num_channels; ++i) {
const T* channel = deinterleaved[i];
- int interleaved_idx = i;
+ size_t interleaved_idx = i;
for (size_t j = 0; j < samples_per_channel; ++j) {
interleaved[interleaved_idx] = channel[j];
interleaved_idx += num_channels;
@@ -155,7 +181,7 @@ void DownmixInterleavedToMonoImpl(const T* interleaved,
int num_channels,
T* deinterleaved) {
RTC_DCHECK_GT(num_channels, 0);
- RTC_DCHECK_GT(num_frames, 0u);
+ RTC_DCHECK_GT(num_frames, 0);
const T* const end = interleaved + num_frames * num_channels;
@@ -185,4 +211,4 @@ void DownmixInterleavedToMono<int16_t>(const int16_t* interleaved,
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
+#endif // COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
diff --git a/webrtc/common_audio/lapped_transform.cc b/webrtc/common_audio/lapped_transform.cc
deleted file mode 100644
index c01f1d9..0000000
--- a/webrtc/common_audio/lapped_transform.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/common_audio/lapped_transform.h"
-
-#include <algorithm>
-#include <cstdlib>
-#include <cstring>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/real_fourier.h"
-
-namespace webrtc {
-
-void LappedTransform::BlockThunk::ProcessBlock(const float* const* input,
- size_t num_frames,
- int num_input_channels,
- int num_output_channels,
- float* const* output) {
- RTC_CHECK_EQ(num_input_channels, parent_->num_in_channels_);
- RTC_CHECK_EQ(num_output_channels, parent_->num_out_channels_);
- RTC_CHECK_EQ(parent_->block_length_, num_frames);
-
- for (int i = 0; i < num_input_channels; ++i) {
- memcpy(parent_->real_buf_.Row(i), input[i],
- num_frames * sizeof(*input[0]));
- parent_->fft_->Forward(parent_->real_buf_.Row(i),
- parent_->cplx_pre_.Row(i));
- }
-
- size_t block_length = RealFourier::ComplexLength(
- RealFourier::FftOrder(num_frames));
- RTC_CHECK_EQ(parent_->cplx_length_, block_length);
- parent_->block_processor_->ProcessAudioBlock(parent_->cplx_pre_.Array(),
- num_input_channels,
- parent_->cplx_length_,
- num_output_channels,
- parent_->cplx_post_.Array());
-
- for (int i = 0; i < num_output_channels; ++i) {
- parent_->fft_->Inverse(parent_->cplx_post_.Row(i),
- parent_->real_buf_.Row(i));
- memcpy(output[i], parent_->real_buf_.Row(i),
- num_frames * sizeof(*input[0]));
- }
-}
-
-LappedTransform::LappedTransform(int num_in_channels,
- int num_out_channels,
- size_t chunk_length,
- const float* window,
- size_t block_length,
- size_t shift_amount,
- Callback* callback)
- : blocker_callback_(this),
- num_in_channels_(num_in_channels),
- num_out_channels_(num_out_channels),
- block_length_(block_length),
- chunk_length_(chunk_length),
- block_processor_(callback),
- blocker_(chunk_length_,
- block_length_,
- num_in_channels_,
- num_out_channels_,
- window,
- shift_amount,
- &blocker_callback_),
- fft_(RealFourier::Create(RealFourier::FftOrder(block_length_))),
- cplx_length_(RealFourier::ComplexLength(fft_->order())),
- real_buf_(num_in_channels,
- block_length_,
- RealFourier::kFftBufferAlignment),
- cplx_pre_(num_in_channels,
- cplx_length_,
- RealFourier::kFftBufferAlignment),
- cplx_post_(num_out_channels,
- cplx_length_,
- RealFourier::kFftBufferAlignment) {
- RTC_CHECK(num_in_channels_ > 0 && num_out_channels_ > 0);
- RTC_CHECK_GT(block_length_, 0u);
- RTC_CHECK_GT(chunk_length_, 0u);
- RTC_CHECK(block_processor_);
-
- // block_length_ power of 2?
- RTC_CHECK_EQ(0u, block_length_ & (block_length_ - 1));
-}
-
-void LappedTransform::ProcessChunk(const float* const* in_chunk,
- float* const* out_chunk) {
- blocker_.ProcessChunk(in_chunk, chunk_length_, num_in_channels_,
- num_out_channels_, out_chunk);
-}
-
-} // namespace webrtc
diff --git a/webrtc/common_audio/lapped_transform.h b/webrtc/common_audio/lapped_transform.h
deleted file mode 100644
index 21e10e3..0000000
--- a/webrtc/common_audio/lapped_transform.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_COMMON_AUDIO_LAPPED_TRANSFORM_H_
-#define WEBRTC_COMMON_AUDIO_LAPPED_TRANSFORM_H_
-
-#include <complex>
-
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/blocker.h"
-#include "webrtc/common_audio/real_fourier.h"
-#include "webrtc/system_wrappers/include/aligned_array.h"
-
-namespace webrtc {
-
-// Helper class for audio processing modules which operate on frequency domain
-// input derived from the windowed time domain audio stream.
-//
-// The input audio chunk is sliced into possibly overlapping blocks, multiplied
-// by a window and transformed with an FFT implementation. The transformed data
-// is supplied to the given callback for processing. The processed output is
-// then inverse transformed into the time domain and spliced back into a chunk
-// which constitutes the final output of this processing module.
-class LappedTransform {
- public:
- class Callback {
- public:
- virtual ~Callback() {}
-
- virtual void ProcessAudioBlock(const std::complex<float>* const* in_block,
- int num_in_channels, size_t frames,
- int num_out_channels,
- std::complex<float>* const* out_block) = 0;
- };
-
- // Construct a transform instance. |chunk_length| is the number of samples in
- // each channel. |window| defines the window, owned by the caller (a copy is
- // made internally); |window| should have length equal to |block_length|.
- // |block_length| defines the length of a block, in samples.
- // |shift_amount| is in samples. |callback| is the caller-owned audio
- // processing function called for each block of the input chunk.
- LappedTransform(int num_in_channels,
- int num_out_channels,
- size_t chunk_length,
- const float* window,
- size_t block_length,
- size_t shift_amount,
- Callback* callback);
- ~LappedTransform() {}
-
- // Main audio processing helper method. Internally slices |in_chunk| into
- // blocks, transforms them to frequency domain, calls the callback for each
- // block and returns a de-blocked time domain chunk of audio through
- // |out_chunk|. Both buffers are caller-owned.
- void ProcessChunk(const float* const* in_chunk, float* const* out_chunk);
-
- // Get the chunk length.
- //
- // The chunk length is the number of samples per channel that must be passed
- // to ProcessChunk via the parameter in_chunk.
- //
- // Returns the same chunk_length passed to the LappedTransform constructor.
- size_t chunk_length() const { return chunk_length_; }
-
- // Get the number of input channels.
- //
- // This is the number of arrays that must be passed to ProcessChunk via
- // in_chunk.
- //
- // Returns the same num_in_channels passed to the LappedTransform constructor.
- int num_in_channels() const { return num_in_channels_; }
-
- // Get the number of output channels.
- //
- // This is the number of arrays that must be passed to ProcessChunk via
- // out_chunk.
- //
- // Returns the same num_out_channels passed to the LappedTransform
- // constructor.
- int num_out_channels() const { return num_out_channels_; }
-
- private:
- // Internal middleware callback, given to the blocker. Transforms each block
- // and hands it over to the processing method given at construction time.
- class BlockThunk : public BlockerCallback {
- public:
- explicit BlockThunk(LappedTransform* parent) : parent_(parent) {}
-
- virtual void ProcessBlock(const float* const* input, size_t num_frames,
- int num_input_channels, int num_output_channels,
- float* const* output);
-
- private:
- LappedTransform* const parent_;
- } blocker_callback_;
-
- const int num_in_channels_;
- const int num_out_channels_;
-
- const size_t block_length_;
- const size_t chunk_length_;
-
- Callback* const block_processor_;
- Blocker blocker_;
-
- rtc::scoped_ptr<RealFourier> fft_;
- const size_t cplx_length_;
- AlignedArray<float> real_buf_;
- AlignedArray<std::complex<float> > cplx_pre_;
- AlignedArray<std::complex<float> > cplx_post_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_COMMON_AUDIO_LAPPED_TRANSFORM_H_
-
diff --git a/webrtc/common_audio/meson.build b/webrtc/common_audio/meson.build
index e9cbbf8..e0c9129 100644
--- a/webrtc/common_audio/meson.build
+++ b/webrtc/common_audio/meson.build
@@ -1,19 +1,29 @@
common_audio_sources = [
+ 'audio_converter.cc',
+ 'audio_util.cc',
+ 'channel_buffer.cc',
+ 'fir_filter_c.cc',
+ 'fir_filter_factory.cc',
+ 'real_fourier.cc',
+ 'real_fourier_ooura.cc',
'resampler/push_resampler.cc',
'resampler/push_sinc_resampler.cc',
'resampler/resampler.cc',
'resampler/sinc_resampler.cc',
'resampler/sinusoidal_linear_chirp_source.cc',
- 'signal_processing/auto_corr_to_refl_coef.c',
+ 'ring_buffer.c',
'signal_processing/auto_correlation.c',
+ 'signal_processing/auto_corr_to_refl_coef.c',
+ 'signal_processing/complex_bit_reverse.c',
'signal_processing/complex_fft.c',
'signal_processing/copy_set_operations.c',
'signal_processing/cross_correlation.c',
'signal_processing/division_operations.c',
- 'signal_processing/dot_product_with_scale.c',
+ 'signal_processing/dot_product_with_scale.cc',
'signal_processing/downsample_fast.c',
- 'signal_processing/energy.c',
'signal_processing/filter_ar.c',
+ 'signal_processing/filter_ar_fast_q12.c',
+ 'signal_processing/energy.c',
'signal_processing/filter_ma_fast_q12.c',
'signal_processing/get_hanning_window.c',
'signal_processing/get_scaling_square.c',
@@ -24,34 +34,27 @@ common_audio_sources = [
'signal_processing/randomization_functions.c',
'signal_processing/real_fft.c',
'signal_processing/refl_coef_to_lpc.c',
- 'signal_processing/resample.c',
'signal_processing/resample_48khz.c',
'signal_processing/resample_by_2.c',
'signal_processing/resample_by_2_internal.c',
+ 'signal_processing/resample.c',
'signal_processing/resample_fractional.c',
'signal_processing/spl_init.c',
- 'signal_processing/spl_sqrt.c',
+ 'signal_processing/spl_inl.c',
'signal_processing/splitting_filter.c',
+ 'signal_processing/spl_sqrt.c',
'signal_processing/sqrt_of_one_minus_x_squared.c',
'signal_processing/vector_scaling_operations.c',
+ 'smoothing_filter.cc',
+ 'third_party/ooura/fft_size_128/ooura_fft.cc',
+ 'third_party/ooura/fft_size_256/fft4g.cc',
+ 'third_party/spl_sqrt_floor/spl_sqrt_floor.c',
'vad/vad.cc',
'vad/vad_core.c',
'vad/vad_filterbank.c',
'vad/vad_gmm.c',
'vad/vad_sp.c',
'vad/webrtc_vad.c',
- 'audio_converter.cc',
- 'audio_ring_buffer.cc',
- 'audio_util.cc',
- 'blocker.cc',
- 'channel_buffer.cc',
- 'fft4g.c',
- 'fir_filter.cc',
- 'lapped_transform.cc',
- 'real_fourier.cc',
- 'real_fourier_ooura.cc',
- 'ring_buffer.c',
- 'sparse_fir_filter.cc',
'wav_file.cc',
'wav_header.cc',
'window_generator.cc',
@@ -59,18 +62,52 @@ common_audio_sources = [
arch_libs = []
if have_x86
- arch_libs += [static_library('common_audio_sse2',
- ['resampler/sinc_resampler_sse.cc', 'fir_filter_sse.cc'],
- dependencies: common_deps,
- include_directories: webrtc_inc,
- c_args: common_cflags + ['-msse2'],
- cpp_args: common_cxxflags + ['-msse2'])]
+ arch_libs += [
+ static_library('common_audio_sse2',
+ [
+ 'fir_filter_sse.cc',
+ 'resampler/sinc_resampler_sse.cc',
+ 'third_party/ooura/fft_size_128/ooura_fft_sse2.cc',
+ ],
+ dependencies: common_deps,
+ include_directories: webrtc_inc,
+ c_args: common_cflags + ['-msse2'],
+ cpp_args: common_cxxflags + ['-msse2']
+ )
+ ]
+ arch_libs += [
+ static_library('common_audio_avx',
+ [
+ 'fir_filter_avx2.cc',
+ 'resampler/sinc_resampler_avx2.cc',
+ ],
+ dependencies: common_deps,
+ include_directories: webrtc_inc,
+ c_args: common_cflags + ['-mavx2', '-mfma'],
+ cpp_args: common_cxxflags + ['-mavx2', '-mfma']
+ )
+ ]
+endif
+
+if have_mips
+ common_audio_sources += [
+ 'signal_processing/complex_bit_reverse_mips.c',
+ 'signal_processing/complex_fft_mips.c',
+ 'signal_processing/cross_correlation_mips.c',
+ 'signal_processing/downsample_fast_mips.c',
+ 'signal_processing/filter_ar_fast_q12_mips.c',
+ 'signal_processing/min_max_operations_mips.c',
+ 'signal_processing/resample_by_2_mips.c',
+ 'signal_processing/vector_scaling_operations_mips.c',
+ 'third_party/ooura/fft_size_128/ooura_fft_mips.c',
+ 'third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c',
+ ]
endif
if have_arm
common_audio_sources += [
'signal_processing/complex_bit_reverse_arm.S',
- 'signal_processing/spl_sqrt_floor_arm.S',
+ 'third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S',
]
endif
@@ -82,11 +119,12 @@ endif
if have_neon
common_audio_sources += [
+ 'fir_filter_neon.cc',
'resampler/sinc_resampler_neon.cc',
'signal_processing/cross_correlation_neon.c',
'signal_processing/downsample_fast_neon.c',
'signal_processing/min_max_operations_neon.c',
- 'fir_filter_neon.cc',
+ 'third_party/ooura/fft_size_128/ooura_fft_neon.c',
]
endif
@@ -94,7 +132,6 @@ if not have_arm
common_audio_sources += [
'signal_processing/complex_bit_reverse.c',
'signal_processing/filter_ar_fast_q12.c',
- 'signal_processing/spl_sqrt_floor.c',
]
endif
diff --git a/webrtc/common_audio/real_fourier.cc b/webrtc/common_audio/real_fourier.cc
index fef3c60..7365844 100644
--- a/webrtc/common_audio/real_fourier.cc
+++ b/webrtc/common_audio/real_fourier.cc
@@ -8,25 +8,20 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/real_fourier.h"
+#include "common_audio/real_fourier.h"
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/real_fourier_ooura.h"
-#include "webrtc/common_audio/real_fourier_openmax.h"
-#include "webrtc/common_audio/signal_processing/include/spl_inl.h"
+#include "common_audio/real_fourier_ooura.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/checks.h"
namespace webrtc {
using std::complex;
-const int RealFourier::kFftBufferAlignment = 32;
+const size_t RealFourier::kFftBufferAlignment = 32;
-rtc::scoped_ptr<RealFourier> RealFourier::Create(int fft_order) {
-#if defined(RTC_USE_OPENMAX_DL)
- return rtc::scoped_ptr<RealFourier>(new RealFourierOpenmax(fft_order));
-#else
- return rtc::scoped_ptr<RealFourier>(new RealFourierOoura(fft_order));
-#endif
+std::unique_ptr<RealFourier> RealFourier::Create(int fft_order) {
+ return std::unique_ptr<RealFourier>(new RealFourierOoura(fft_order));
}
int RealFourier::FftOrder(size_t length) {
@@ -36,7 +31,7 @@ int RealFourier::FftOrder(size_t length) {
size_t RealFourier::FftLength(int order) {
RTC_CHECK_GE(order, 0);
- return static_cast<size_t>(1 << order);
+ return size_t{1} << order;
}
size_t RealFourier::ComplexLength(int order) {
@@ -54,4 +49,3 @@ RealFourier::fft_cplx_scoper RealFourier::AllocCplxBuffer(int count) {
}
} // namespace webrtc
-
diff --git a/webrtc/common_audio/real_fourier.h b/webrtc/common_audio/real_fourier.h
index ce3bbff..4881fb7 100644
--- a/webrtc/common_audio/real_fourier.h
+++ b/webrtc/common_audio/real_fourier.h
@@ -8,13 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_REAL_FOURIER_H_
-#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_H_
+#ifndef COMMON_AUDIO_REAL_FOURIER_H_
+#define COMMON_AUDIO_REAL_FOURIER_H_
+
+#include <stddef.h>
#include <complex>
+#include <memory>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/system_wrappers/include/aligned_malloc.h"
+#include "rtc_base/memory/aligned_malloc.h"
// Uniform interface class for the real DFT and its inverse, for power-of-2
// input lengths. Also contains helper functions for buffer allocation, taking
@@ -25,17 +27,17 @@ namespace webrtc {
class RealFourier {
public:
// Shorthand typenames for the scopers used by the buffer allocation helpers.
- typedef rtc::scoped_ptr<float[], AlignedFreeDeleter> fft_real_scoper;
- typedef rtc::scoped_ptr<std::complex<float>[], AlignedFreeDeleter>
+ typedef std::unique_ptr<float[], AlignedFreeDeleter> fft_real_scoper;
+ typedef std::unique_ptr<std::complex<float>[], AlignedFreeDeleter>
fft_cplx_scoper;
// The alignment required for all input and output buffers, in bytes.
- static const int kFftBufferAlignment;
+ static const size_t kFftBufferAlignment;
// Construct a wrapper instance for the given input order, which must be
// between 1 and kMaxFftOrder, inclusively.
- static rtc::scoped_ptr<RealFourier> Create(int fft_order);
- virtual ~RealFourier() {};
+ static std::unique_ptr<RealFourier> Create(int fft_order);
+ virtual ~RealFourier() {}
// Helper to compute the smallest FFT order (a power of 2) which will contain
// the given input length.
@@ -71,5 +73,4 @@ class RealFourier {
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_H_
-
+#endif // COMMON_AUDIO_REAL_FOURIER_H_
diff --git a/webrtc/common_audio/real_fourier_ooura.cc b/webrtc/common_audio/real_fourier_ooura.cc
index 8cd4c86..9acda54 100644
--- a/webrtc/common_audio/real_fourier_ooura.cc
+++ b/webrtc/common_audio/real_fourier_ooura.cc
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/real_fourier_ooura.h"
+#include "common_audio/real_fourier_ooura.h"
-#include <cmath>
#include <algorithm>
+#include <cmath>
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/fft4g.h"
+#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
+#include "rtc_base/checks.h"
namespace webrtc {
@@ -28,8 +28,8 @@ void Conjugate(complex<float>* array, size_t complex_length) {
}
size_t ComputeWorkIpSize(size_t fft_length) {
- return static_cast<size_t>(2 + std::ceil(std::sqrt(
- static_cast<float>(fft_length))));
+ return static_cast<size_t>(
+ 2 + std::ceil(std::sqrt(static_cast<float>(fft_length))));
}
} // namespace
@@ -45,11 +45,13 @@ RealFourierOoura::RealFourierOoura(int fft_order)
RTC_CHECK_GE(fft_order, 1);
}
+RealFourierOoura::~RealFourierOoura() = default;
+
void RealFourierOoura::Forward(const float* src, complex<float>* dest) const {
{
// This cast is well-defined since C++11. See "Non-static data members" at:
// http://en.cppreference.com/w/cpp/numeric/complex
- auto dest_float = reinterpret_cast<float*>(dest);
+ auto* dest_float = reinterpret_cast<float*>(dest);
std::copy(src, src + length_, dest_float);
WebRtc_rdft(length_, 1, dest_float, work_ip_.get(), work_w_.get());
}
@@ -63,7 +65,7 @@ void RealFourierOoura::Forward(const float* src, complex<float>* dest) const {
void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const {
{
- auto dest_complex = reinterpret_cast<complex<float>*>(dest);
+ auto* dest_complex = reinterpret_cast<complex<float>*>(dest);
// The real output array is shorter than the input complex array by one
// complex element.
const size_t dest_complex_length = complex_length_ - 1;
@@ -71,8 +73,8 @@ void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const {
// Restore Ooura's conjugate definition.
Conjugate(dest_complex, dest_complex_length);
// Restore real[n/2] to imag[0].
- dest_complex[0] = complex<float>(dest_complex[0].real(),
- src[complex_length_ - 1].real());
+ dest_complex[0] =
+ complex<float>(dest_complex[0].real(), src[complex_length_ - 1].real());
}
WebRtc_rdft(length_, -1, dest, work_ip_.get(), work_w_.get());
@@ -82,4 +84,8 @@ void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const {
std::for_each(dest, dest + length_, [scale](float& v) { v *= scale; });
}
+int RealFourierOoura::order() const {
+ return order_;
+}
+
} // namespace webrtc
diff --git a/webrtc/common_audio/real_fourier_ooura.h b/webrtc/common_audio/real_fourier_ooura.h
index 8d094bf..ae85dfd 100644
--- a/webrtc/common_audio/real_fourier_ooura.h
+++ b/webrtc/common_audio/real_fourier_ooura.h
@@ -8,38 +8,38 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
-#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+#ifndef COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+#define COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+
+#include <stddef.h>
#include <complex>
+#include <memory>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/real_fourier.h"
+#include "common_audio/real_fourier.h"
namespace webrtc {
class RealFourierOoura : public RealFourier {
public:
explicit RealFourierOoura(int fft_order);
+ ~RealFourierOoura() override;
void Forward(const float* src, std::complex<float>* dest) const override;
void Inverse(const std::complex<float>* src, float* dest) const override;
- int order() const override {
- return order_;
- }
+ int order() const override;
private:
const int order_;
const size_t length_;
const size_t complex_length_;
// These are work arrays for Ooura. The names are based on the comments in
- // fft4g.c.
- const rtc::scoped_ptr<size_t[]> work_ip_;
- const rtc::scoped_ptr<float[]> work_w_;
+ // common_audio/third_party/ooura/fft_size_256/fft4g.cc.
+ const std::unique_ptr<size_t[]> work_ip_;
+ const std::unique_ptr<float[]> work_w_;
};
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
-
+#endif // COMMON_AUDIO_REAL_FOURIER_OOURA_H_
diff --git a/webrtc/common_audio/resampler/include/push_resampler.h b/webrtc/common_audio/resampler/include/push_resampler.h
index b5c0003..3da6712 100644
--- a/webrtc/common_audio/resampler/include/push_resampler.h
+++ b/webrtc/common_audio/resampler/include/push_resampler.h
@@ -8,11 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
-#define WEBRTC_COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
+#ifndef COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
+#define COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/typedefs.h"
+#include <memory>
+#include <vector>
namespace webrtc {
@@ -28,25 +28,32 @@ class PushResampler {
// Must be called whenever the parameters change. Free to be called at any
// time as it is a no-op if parameters have not changed since the last call.
- int InitializeIfNeeded(int src_sample_rate_hz, int dst_sample_rate_hz,
- int num_channels);
+ int InitializeIfNeeded(int src_sample_rate_hz,
+ int dst_sample_rate_hz,
+ size_t num_channels);
// Returns the total number of samples provided in destination (e.g. 32 kHz,
// 2 channel audio gives 640 samples).
int Resample(const T* src, size_t src_length, T* dst, size_t dst_capacity);
private:
- rtc::scoped_ptr<PushSincResampler> sinc_resampler_;
- rtc::scoped_ptr<PushSincResampler> sinc_resampler_right_;
int src_sample_rate_hz_;
int dst_sample_rate_hz_;
- int num_channels_;
- rtc::scoped_ptr<T[]> src_left_;
- rtc::scoped_ptr<T[]> src_right_;
- rtc::scoped_ptr<T[]> dst_left_;
- rtc::scoped_ptr<T[]> dst_right_;
+ size_t num_channels_;
+ // Vector that is needed to provide the proper inputs and outputs to the
+ // interleave/de-interleave methods used in Resample. This needs to be
+ // heap-allocated on the state to support an arbitrary number of channels
+ // without doing run-time heap-allocations in the Resample method.
+ std::vector<T*> channel_data_array_;
+
+ struct ChannelResampler {
+ std::unique_ptr<PushSincResampler> resampler;
+ std::vector<T> source;
+ std::vector<T> destination;
+ };
+
+ std::vector<ChannelResampler> channel_resamplers_;
};
-
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
+#endif // COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
diff --git a/webrtc/common_audio/resampler/include/resampler.h b/webrtc/common_audio/resampler/include/resampler.h
index 0d4c1af..41940f9 100644
--- a/webrtc/common_audio/resampler/include/resampler.h
+++ b/webrtc/common_audio/resampler/include/resampler.h
@@ -8,88 +8,92 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
/*
* A wrapper for resampling a numerous amount of sampling combinations.
*/
-#ifndef WEBRTC_RESAMPLER_RESAMPLER_H_
-#define WEBRTC_RESAMPLER_RESAMPLER_H_
+#ifndef COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_
+#define COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_
#include <stddef.h>
-
-#include "webrtc/typedefs.h"
+#include <stdint.h>
namespace webrtc {
// All methods return 0 on success and -1 on failure.
-class Resampler
-{
-
-public:
- Resampler();
- Resampler(int inFreq, int outFreq, int num_channels);
- ~Resampler();
-
- // Reset all states
- int Reset(int inFreq, int outFreq, int num_channels);
-
- // Reset all states if any parameter has changed
- int ResetIfNeeded(int inFreq, int outFreq, int num_channels);
-
- // Resample samplesIn to samplesOut.
- int Push(const int16_t* samplesIn, size_t lengthIn, int16_t* samplesOut,
- size_t maxLen, size_t &outLen);
-
-private:
- enum ResamplerMode
- {
- kResamplerMode1To1,
- kResamplerMode1To2,
- kResamplerMode1To3,
- kResamplerMode1To4,
- kResamplerMode1To6,
- kResamplerMode1To12,
- kResamplerMode2To3,
- kResamplerMode2To11,
- kResamplerMode4To11,
- kResamplerMode8To11,
- kResamplerMode11To16,
- kResamplerMode11To32,
- kResamplerMode2To1,
- kResamplerMode3To1,
- kResamplerMode4To1,
- kResamplerMode6To1,
- kResamplerMode12To1,
- kResamplerMode3To2,
- kResamplerMode11To2,
- kResamplerMode11To4,
- kResamplerMode11To8
- };
-
- // Generic pointers since we don't know what states we'll need
- void* state1_;
- void* state2_;
- void* state3_;
-
- // Storage if needed
- int16_t* in_buffer_;
- int16_t* out_buffer_;
- size_t in_buffer_size_;
- size_t out_buffer_size_;
- size_t in_buffer_size_max_;
- size_t out_buffer_size_max_;
-
- int my_in_frequency_khz_;
- int my_out_frequency_khz_;
- ResamplerMode my_mode_;
- int num_channels_;
-
- // Extra instance for stereo
- Resampler* slave_left_;
- Resampler* slave_right_;
+class Resampler {
+ public:
+ Resampler();
+ Resampler(int inFreq, int outFreq, size_t num_channels);
+ ~Resampler();
+
+ // Reset all states
+ int Reset(int inFreq, int outFreq, size_t num_channels);
+
+ // Reset all states if any parameter has changed
+ int ResetIfNeeded(int inFreq, int outFreq, size_t num_channels);
+
+ // Resample samplesIn to samplesOut.
+ int Push(const int16_t* samplesIn,
+ size_t lengthIn,
+ int16_t* samplesOut,
+ size_t maxLen,
+ size_t& outLen); // NOLINT: to avoid changing APIs
+
+ private:
+ enum ResamplerMode {
+ kResamplerMode1To1,
+ kResamplerMode1To2,
+ kResamplerMode1To3,
+ kResamplerMode1To4,
+ kResamplerMode1To6,
+ kResamplerMode1To12,
+ kResamplerMode2To3,
+ kResamplerMode2To11,
+ kResamplerMode4To11,
+ kResamplerMode8To11,
+ kResamplerMode11To16,
+ kResamplerMode11To32,
+ kResamplerMode2To1,
+ kResamplerMode3To1,
+ kResamplerMode4To1,
+ kResamplerMode6To1,
+ kResamplerMode12To1,
+ kResamplerMode3To2,
+ kResamplerMode11To2,
+ kResamplerMode11To4,
+ kResamplerMode11To8
+ };
+
+ // Computes the resampler mode for a given sampling frequency pair.
+ // Returns -1 for unsupported frequency pairs.
+ static int ComputeResamplerMode(int in_freq_hz,
+ int out_freq_hz,
+ ResamplerMode* mode);
+
+ // Generic pointers since we don't know what states we'll need
+ void* state1_;
+ void* state2_;
+ void* state3_;
+
+ // Storage if needed
+ int16_t* in_buffer_;
+ int16_t* out_buffer_;
+ size_t in_buffer_size_;
+ size_t out_buffer_size_;
+ size_t in_buffer_size_max_;
+ size_t out_buffer_size_max_;
+
+ int my_in_frequency_khz_;
+ int my_out_frequency_khz_;
+ ResamplerMode my_mode_;
+ size_t num_channels_;
+
+ // Extra instance for stereo
+ Resampler* helper_left_;
+ Resampler* helper_right_;
};
} // namespace webrtc
-#endif // WEBRTC_RESAMPLER_RESAMPLER_H_
+#endif // COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_
diff --git a/webrtc/common_audio/resampler/push_resampler.cc b/webrtc/common_audio/resampler/push_resampler.cc
index 566acde..d7aa8d7 100644
--- a/webrtc/common_audio/resampler/push_resampler.cc
+++ b/webrtc/common_audio/resampler/push_resampler.cc
@@ -8,40 +8,78 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/resampler/include/push_resampler.h"
+#include "common_audio/resampler/include/push_resampler.h"
+#include <stdint.h>
#include <string.h>
-#include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/resampler/include/resampler.h"
-#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
+#include <memory>
+
+#include "common_audio/include/audio_util.h"
+#include "common_audio/resampler/push_sinc_resampler.h"
+#include "rtc_base/checks.h"
namespace webrtc {
+namespace {
+// These checks were factored out into a non-templatized function
+// due to problems with clang on Windows in debug builds.
+// For some reason having the DCHECKs inline in the template code
+// caused the compiler to generate code that threw off the linker.
+// TODO(tommi): Re-enable when we've figured out what the problem is.
+// http://crbug.com/615050
+void CheckValidInitParams(int src_sample_rate_hz,
+ int dst_sample_rate_hz,
+ size_t num_channels) {
+// The below checks are temporarily disabled on WEBRTC_WIN due to problems
+// with clang debug builds.
+#if !defined(WEBRTC_WIN) && defined(__clang__)
+ RTC_DCHECK_GT(src_sample_rate_hz, 0);
+ RTC_DCHECK_GT(dst_sample_rate_hz, 0);
+ RTC_DCHECK_GT(num_channels, 0);
+#endif
+}
+
+void CheckExpectedBufferSizes(size_t src_length,
+ size_t dst_capacity,
+ size_t num_channels,
+ int src_sample_rate,
+ int dst_sample_rate) {
+// The below checks are temporarily disabled on WEBRTC_WIN due to problems
+// with clang debug builds.
+// TODO(tommi): Re-enable when we've figured out what the problem is.
+// http://crbug.com/615050
+#if !defined(WEBRTC_WIN) && defined(__clang__)
+ const size_t src_size_10ms = src_sample_rate * num_channels / 100;
+ const size_t dst_size_10ms = dst_sample_rate * num_channels / 100;
+ RTC_DCHECK_EQ(src_length, src_size_10ms);
+ RTC_DCHECK_GE(dst_capacity, dst_size_10ms);
+#endif
+}
+} // namespace
template <typename T>
PushResampler<T>::PushResampler()
- : src_sample_rate_hz_(0),
- dst_sample_rate_hz_(0),
- num_channels_(0) {
-}
+ : src_sample_rate_hz_(0), dst_sample_rate_hz_(0), num_channels_(0) {}
template <typename T>
-PushResampler<T>::~PushResampler() {
-}
+PushResampler<T>::~PushResampler() {}
template <typename T>
int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz,
int dst_sample_rate_hz,
- int num_channels) {
+ size_t num_channels) {
+ CheckValidInitParams(src_sample_rate_hz, dst_sample_rate_hz, num_channels);
+
if (src_sample_rate_hz == src_sample_rate_hz_ &&
dst_sample_rate_hz == dst_sample_rate_hz_ &&
- num_channels == num_channels_)
+ num_channels == num_channels_) {
// No-op if settings haven't changed.
return 0;
+ }
- if (src_sample_rate_hz <= 0 || dst_sample_rate_hz <= 0 ||
- num_channels <= 0 || num_channels > 2)
+ if (src_sample_rate_hz <= 0 || dst_sample_rate_hz <= 0 || num_channels <= 0) {
return -1;
+ }
src_sample_rate_hz_ = src_sample_rate_hz;
dst_sample_rate_hz_ = dst_sample_rate_hz;
@@ -51,29 +89,28 @@ int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz,
static_cast<size_t>(src_sample_rate_hz / 100);
const size_t dst_size_10ms_mono =
static_cast<size_t>(dst_sample_rate_hz / 100);
- sinc_resampler_.reset(new PushSincResampler(src_size_10ms_mono,
- dst_size_10ms_mono));
- if (num_channels_ == 2) {
- src_left_.reset(new T[src_size_10ms_mono]);
- src_right_.reset(new T[src_size_10ms_mono]);
- dst_left_.reset(new T[dst_size_10ms_mono]);
- dst_right_.reset(new T[dst_size_10ms_mono]);
- sinc_resampler_right_.reset(new PushSincResampler(src_size_10ms_mono,
- dst_size_10ms_mono));
+ channel_resamplers_.clear();
+ for (size_t i = 0; i < num_channels; ++i) {
+ channel_resamplers_.push_back(ChannelResampler());
+ auto channel_resampler = channel_resamplers_.rbegin();
+ channel_resampler->resampler = std::make_unique<PushSincResampler>(
+ src_size_10ms_mono, dst_size_10ms_mono);
+ channel_resampler->source.resize(src_size_10ms_mono);
+ channel_resampler->destination.resize(dst_size_10ms_mono);
}
+ channel_data_array_.resize(num_channels_);
+
return 0;
}
template <typename T>
-int PushResampler<T>::Resample(const T* src, size_t src_length, T* dst,
+int PushResampler<T>::Resample(const T* src,
+ size_t src_length,
+ T* dst,
size_t dst_capacity) {
- const size_t src_size_10ms =
- static_cast<size_t>(src_sample_rate_hz_ * num_channels_ / 100);
- const size_t dst_size_10ms =
- static_cast<size_t>(dst_sample_rate_hz_ * num_channels_ / 100);
- if (src_length != src_size_10ms || dst_capacity < dst_size_10ms)
- return -1;
+ CheckExpectedBufferSizes(src_length, dst_capacity, num_channels_,
+ src_sample_rate_hz_, dst_sample_rate_hz_);
if (src_sample_rate_hz_ == dst_sample_rate_hz_) {
// The old resampler provides this memcpy facility in the case of matching
@@ -81,26 +118,30 @@ int PushResampler<T>::Resample(const T* src, size_t src_length, T* dst,
memcpy(dst, src, src_length * sizeof(T));
return static_cast<int>(src_length);
}
- if (num_channels_ == 2) {
- const size_t src_length_mono = src_length / num_channels_;
- const size_t dst_capacity_mono = dst_capacity / num_channels_;
- T* deinterleaved[] = {src_left_.get(), src_right_.get()};
- Deinterleave(src, src_length_mono, num_channels_, deinterleaved);
-
- size_t dst_length_mono =
- sinc_resampler_->Resample(src_left_.get(), src_length_mono,
- dst_left_.get(), dst_capacity_mono);
- sinc_resampler_right_->Resample(src_right_.get(), src_length_mono,
- dst_right_.get(), dst_capacity_mono);
-
- deinterleaved[0] = dst_left_.get();
- deinterleaved[1] = dst_right_.get();
- Interleave(deinterleaved, dst_length_mono, num_channels_, dst);
- return static_cast<int>(dst_length_mono * num_channels_);
- } else {
- return static_cast<int>(
- sinc_resampler_->Resample(src, src_length, dst, dst_capacity));
+
+ const size_t src_length_mono = src_length / num_channels_;
+ const size_t dst_capacity_mono = dst_capacity / num_channels_;
+
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ channel_data_array_[ch] = channel_resamplers_[ch].source.data();
+ }
+
+ Deinterleave(src, src_length_mono, num_channels_, channel_data_array_.data());
+
+ size_t dst_length_mono = 0;
+
+ for (auto& resampler : channel_resamplers_) {
+ dst_length_mono = resampler.resampler->Resample(
+ resampler.source.data(), src_length_mono, resampler.destination.data(),
+ dst_capacity_mono);
+ }
+
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ channel_data_array_[ch] = channel_resamplers_[ch].destination.data();
}
+
+ Interleave(channel_data_array_.data(), dst_length_mono, num_channels_, dst);
+ return static_cast<int>(dst_length_mono * num_channels_);
}
// Explictly generate required instantiations.
diff --git a/webrtc/common_audio/resampler/push_sinc_resampler.cc b/webrtc/common_audio/resampler/push_sinc_resampler.cc
index a740423..3bfead2 100644
--- a/webrtc/common_audio/resampler/push_sinc_resampler.cc
+++ b/webrtc/common_audio/resampler/push_sinc_resampler.cc
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
+#include "common_audio/resampler/push_sinc_resampler.h"
#include <cstring>
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/include/audio_util.h"
+#include "common_audio/include/audio_util.h"
+#include "rtc_base/checks.h"
namespace webrtc {
@@ -28,8 +28,7 @@ PushSincResampler::PushSincResampler(size_t source_frames,
first_pass_(true),
source_available_(0) {}
-PushSincResampler::~PushSincResampler() {
-}
+PushSincResampler::~PushSincResampler() {}
size_t PushSincResampler::Resample(const int16_t* source,
size_t source_length,
diff --git a/webrtc/common_audio/resampler/push_sinc_resampler.h b/webrtc/common_audio/resampler/push_sinc_resampler.h
index cefc62a..bd609c4 100644
--- a/webrtc/common_audio/resampler/push_sinc_resampler.h
+++ b/webrtc/common_audio/resampler/push_sinc_resampler.h
@@ -8,13 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
-#define WEBRTC_COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
+#ifndef COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
+#define COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/resampler/sinc_resampler.h"
-#include "webrtc/typedefs.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "common_audio/resampler/sinc_resampler.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -35,8 +38,10 @@ class PushSincResampler : public SincResamplerCallback {
// at least as large as |destination_frames|. Returns the number of samples
// provided in destination (for convenience, since this will always be equal
// to |destination_frames|).
- size_t Resample(const int16_t* source, size_t source_frames,
- int16_t* destination, size_t destination_capacity);
+ size_t Resample(const int16_t* source,
+ size_t source_frames,
+ int16_t* destination,
+ size_t destination_capacity);
size_t Resample(const float* source,
size_t source_frames,
float* destination,
@@ -56,8 +61,8 @@ class PushSincResampler : public SincResamplerCallback {
friend class PushSincResamplerTest;
SincResampler* get_resampler_for_testing() { return resampler_.get(); }
- rtc::scoped_ptr<SincResampler> resampler_;
- rtc::scoped_ptr<float[]> float_buffer_;
+ std::unique_ptr<SincResampler> resampler_;
+ std::unique_ptr<float[]> float_buffer_;
const float* source_ptr_;
const int16_t* source_ptr_int_;
const size_t destination_frames_;
@@ -73,4 +78,4 @@ class PushSincResampler : public SincResamplerCallback {
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
+#endif // COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
diff --git a/webrtc/common_audio/resampler/resampler.cc b/webrtc/common_audio/resampler/resampler.cc
index c9e7a1f..ccfed5a 100644
--- a/webrtc/common_audio/resampler/resampler.cc
+++ b/webrtc/common_audio/resampler/resampler.cc
@@ -8,16 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
/*
* A wrapper for resampling a numerous amount of sampling combinations.
*/
+#include "common_audio/resampler/include/resampler.h"
+
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include "webrtc/common_audio/resampler/include/resampler.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/logging.h"
namespace webrtc {
@@ -35,925 +37,888 @@ Resampler::Resampler()
my_out_frequency_khz_(0),
my_mode_(kResamplerMode1To1),
num_channels_(0),
- slave_left_(nullptr),
- slave_right_(nullptr) {
-}
+ helper_left_(nullptr),
+ helper_right_(nullptr) {}
-Resampler::Resampler(int inFreq, int outFreq, int num_channels)
+Resampler::Resampler(int inFreq, int outFreq, size_t num_channels)
: Resampler() {
Reset(inFreq, outFreq, num_channels);
}
-Resampler::~Resampler()
-{
- if (state1_)
- {
- free(state1_);
- }
- if (state2_)
- {
- free(state2_);
- }
- if (state3_)
- {
- free(state3_);
- }
- if (in_buffer_)
- {
- free(in_buffer_);
- }
- if (out_buffer_)
- {
- free(out_buffer_);
- }
- if (slave_left_)
- {
- delete slave_left_;
- }
- if (slave_right_)
- {
- delete slave_right_;
- }
+Resampler::~Resampler() {
+ if (state1_) {
+ free(state1_);
+ }
+ if (state2_) {
+ free(state2_);
+ }
+ if (state3_) {
+ free(state3_);
+ }
+ if (in_buffer_) {
+ free(in_buffer_);
+ }
+ if (out_buffer_) {
+ free(out_buffer_);
+ }
+ if (helper_left_) {
+ delete helper_left_;
+ }
+ if (helper_right_) {
+ delete helper_right_;
+ }
}
-int Resampler::ResetIfNeeded(int inFreq, int outFreq, int num_channels)
-{
- int tmpInFreq_kHz = inFreq / 1000;
- int tmpOutFreq_kHz = outFreq / 1000;
-
- if ((tmpInFreq_kHz != my_in_frequency_khz_) || (tmpOutFreq_kHz != my_out_frequency_khz_)
- || (num_channels != num_channels_))
- {
- return Reset(inFreq, outFreq, num_channels);
- } else
- {
- return 0;
- }
+int Resampler::ResetIfNeeded(int inFreq, int outFreq, size_t num_channels) {
+ int tmpInFreq_kHz = inFreq / 1000;
+ int tmpOutFreq_kHz = outFreq / 1000;
+
+ if ((tmpInFreq_kHz != my_in_frequency_khz_) ||
+ (tmpOutFreq_kHz != my_out_frequency_khz_) ||
+ (num_channels != num_channels_)) {
+ return Reset(inFreq, outFreq, num_channels);
+ } else {
+ return 0;
+ }
}
-int Resampler::Reset(int inFreq, int outFreq, int num_channels)
-{
- if (num_channels != 1 && num_channels != 2) {
- return -1;
- }
- num_channels_ = num_channels;
+int Resampler::Reset(int inFreq, int outFreq, size_t num_channels) {
+ if (num_channels != 1 && num_channels != 2) {
+ RTC_LOG(LS_WARNING)
+ << "Reset() called with unsupported channel count, num_channels = "
+ << num_channels;
+ return -1;
+ }
+ ResamplerMode mode;
+ if (ComputeResamplerMode(inFreq, outFreq, &mode) != 0) {
+ RTC_LOG(LS_WARNING)
+ << "Reset() called with unsupported sample rates, inFreq = " << inFreq
+ << ", outFreq = " << outFreq;
+ return -1;
+ }
+ // Reinitialize internal state for the frequencies and sample rates.
+ num_channels_ = num_channels;
+ my_mode_ = mode;
+
+ if (state1_) {
+ free(state1_);
+ state1_ = nullptr;
+ }
+ if (state2_) {
+ free(state2_);
+ state2_ = nullptr;
+ }
+ if (state3_) {
+ free(state3_);
+ state3_ = nullptr;
+ }
+ if (in_buffer_) {
+ free(in_buffer_);
+ in_buffer_ = nullptr;
+ }
+ if (out_buffer_) {
+ free(out_buffer_);
+ out_buffer_ = nullptr;
+ }
+ if (helper_left_) {
+ delete helper_left_;
+ helper_left_ = nullptr;
+ }
+ if (helper_right_) {
+ delete helper_right_;
+ helper_right_ = nullptr;
+ }
+
+ in_buffer_size_ = 0;
+ out_buffer_size_ = 0;
+ in_buffer_size_max_ = 0;
+ out_buffer_size_max_ = 0;
+
+ // We need to track what domain we're in.
+ my_in_frequency_khz_ = inFreq / 1000;
+ my_out_frequency_khz_ = outFreq / 1000;
+
+ if (num_channels_ == 2) {
+ // Create two mono resamplers.
+ helper_left_ = new Resampler(inFreq, outFreq, 1);
+ helper_right_ = new Resampler(inFreq, outFreq, 1);
+ }
+
+ // Now create the states we need.
+ switch (my_mode_) {
+ case kResamplerMode1To1:
+ // No state needed;
+ break;
+ case kResamplerMode1To2:
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+ break;
+ case kResamplerMode1To3:
+ state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
+ WebRtcSpl_ResetResample16khzTo48khz(
+ static_cast<WebRtcSpl_State16khzTo48khz*>(state1_));
+ break;
+ case kResamplerMode1To4:
+ // 1:2
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+ // 2:4
+ state2_ = malloc(8 * sizeof(int32_t));
+ memset(state2_, 0, 8 * sizeof(int32_t));
+ break;
+ case kResamplerMode1To6:
+ // 1:2
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+ // 2:6
+ state2_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
+ WebRtcSpl_ResetResample16khzTo48khz(
+ static_cast<WebRtcSpl_State16khzTo48khz*>(state2_));
+ break;
+ case kResamplerMode1To12:
+ // 1:2
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+ // 2:4
+ state2_ = malloc(8 * sizeof(int32_t));
+ memset(state2_, 0, 8 * sizeof(int32_t));
+ // 4:12
+ state3_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
+ WebRtcSpl_ResetResample16khzTo48khz(
+ static_cast<WebRtcSpl_State16khzTo48khz*>(state3_));
+ break;
+ case kResamplerMode2To3:
+ // 2:6
+ state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
+ WebRtcSpl_ResetResample16khzTo48khz(
+ static_cast<WebRtcSpl_State16khzTo48khz*>(state1_));
+ // 6:3
+ state2_ = malloc(8 * sizeof(int32_t));
+ memset(state2_, 0, 8 * sizeof(int32_t));
+ break;
+ case kResamplerMode2To11:
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+
+ state2_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz));
+ WebRtcSpl_ResetResample8khzTo22khz(
+ static_cast<WebRtcSpl_State8khzTo22khz*>(state2_));
+ break;
+ case kResamplerMode4To11:
+ state1_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz));
+ WebRtcSpl_ResetResample8khzTo22khz(
+ static_cast<WebRtcSpl_State8khzTo22khz*>(state1_));
+ break;
+ case kResamplerMode8To11:
+ state1_ = malloc(sizeof(WebRtcSpl_State16khzTo22khz));
+ WebRtcSpl_ResetResample16khzTo22khz(
+ static_cast<WebRtcSpl_State16khzTo22khz*>(state1_));
+ break;
+ case kResamplerMode11To16:
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+
+ state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz));
+ WebRtcSpl_ResetResample22khzTo16khz(
+ static_cast<WebRtcSpl_State22khzTo16khz*>(state2_));
+ break;
+ case kResamplerMode11To32:
+ // 11 -> 22
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+
+ // 22 -> 16
+ state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz));
+ WebRtcSpl_ResetResample22khzTo16khz(
+ static_cast<WebRtcSpl_State22khzTo16khz*>(state2_));
+
+ // 16 -> 32
+ state3_ = malloc(8 * sizeof(int32_t));
+ memset(state3_, 0, 8 * sizeof(int32_t));
+
+ break;
+ case kResamplerMode2To1:
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+ break;
+ case kResamplerMode3To1:
+ state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz));
+ WebRtcSpl_ResetResample48khzTo16khz(
+ static_cast<WebRtcSpl_State48khzTo16khz*>(state1_));
+ break;
+ case kResamplerMode4To1:
+ // 4:2
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+ // 2:1
+ state2_ = malloc(8 * sizeof(int32_t));
+ memset(state2_, 0, 8 * sizeof(int32_t));
+ break;
+ case kResamplerMode6To1:
+ // 6:2
+ state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz));
+ WebRtcSpl_ResetResample48khzTo16khz(
+ static_cast<WebRtcSpl_State48khzTo16khz*>(state1_));
+ // 2:1
+ state2_ = malloc(8 * sizeof(int32_t));
+ memset(state2_, 0, 8 * sizeof(int32_t));
+ break;
+ case kResamplerMode12To1:
+ // 12:4
+ state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz));
+ WebRtcSpl_ResetResample48khzTo16khz(
+ static_cast<WebRtcSpl_State48khzTo16khz*>(state1_));
+ // 4:2
+ state2_ = malloc(8 * sizeof(int32_t));
+ memset(state2_, 0, 8 * sizeof(int32_t));
+ // 2:1
+ state3_ = malloc(8 * sizeof(int32_t));
+ memset(state3_, 0, 8 * sizeof(int32_t));
+ break;
+ case kResamplerMode3To2:
+ // 3:6
+ state1_ = malloc(8 * sizeof(int32_t));
+ memset(state1_, 0, 8 * sizeof(int32_t));
+ // 6:2
+ state2_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz));
+ WebRtcSpl_ResetResample48khzTo16khz(
+ static_cast<WebRtcSpl_State48khzTo16khz*>(state2_));
+ break;
+ case kResamplerMode11To2:
+ state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz));
+ WebRtcSpl_ResetResample22khzTo8khz(
+ static_cast<WebRtcSpl_State22khzTo8khz*>(state1_));
+
+ state2_ = malloc(8 * sizeof(int32_t));
+ memset(state2_, 0, 8 * sizeof(int32_t));
+
+ break;
+ case kResamplerMode11To4:
+ state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz));
+ WebRtcSpl_ResetResample22khzTo8khz(
+ static_cast<WebRtcSpl_State22khzTo8khz*>(state1_));
+ break;
+ case kResamplerMode11To8:
+ state1_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz));
+ WebRtcSpl_ResetResample22khzTo16khz(
+ static_cast<WebRtcSpl_State22khzTo16khz*>(state1_));
+ break;
+ }
+
+ return 0;
+}
- if (state1_)
- {
- free(state1_);
- state1_ = NULL;
- }
- if (state2_)
- {
- free(state2_);
- state2_ = NULL;
- }
- if (state3_)
- {
- free(state3_);
- state3_ = NULL;
- }
- if (in_buffer_)
- {
- free(in_buffer_);
- in_buffer_ = NULL;
+int Resampler::ComputeResamplerMode(int in_freq_hz,
+ int out_freq_hz,
+ ResamplerMode* mode) {
+ // Start with a math exercise, Euclid's algorithm to find the gcd:
+ int a = in_freq_hz;
+ int b = out_freq_hz;
+ int c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+ // b is now the gcd;
+
+ // Scale with GCD
+ const int reduced_in_freq = in_freq_hz / b;
+ const int reduced_out_freq = out_freq_hz / b;
+
+ if (reduced_in_freq == reduced_out_freq) {
+ *mode = kResamplerMode1To1;
+ } else if (reduced_in_freq == 1) {
+ switch (reduced_out_freq) {
+ case 2:
+ *mode = kResamplerMode1To2;
+ break;
+ case 3:
+ *mode = kResamplerMode1To3;
+ break;
+ case 4:
+ *mode = kResamplerMode1To4;
+ break;
+ case 6:
+ *mode = kResamplerMode1To6;
+ break;
+ case 12:
+ *mode = kResamplerMode1To12;
+ break;
+ default:
+ return -1;
}
- if (out_buffer_)
- {
- free(out_buffer_);
- out_buffer_ = NULL;
+ } else if (reduced_out_freq == 1) {
+ switch (reduced_in_freq) {
+ case 2:
+ *mode = kResamplerMode2To1;
+ break;
+ case 3:
+ *mode = kResamplerMode3To1;
+ break;
+ case 4:
+ *mode = kResamplerMode4To1;
+ break;
+ case 6:
+ *mode = kResamplerMode6To1;
+ break;
+ case 12:
+ *mode = kResamplerMode12To1;
+ break;
+ default:
+ return -1;
}
- if (slave_left_)
- {
- delete slave_left_;
- slave_left_ = NULL;
+ } else if ((reduced_in_freq == 2) && (reduced_out_freq == 3)) {
+ *mode = kResamplerMode2To3;
+ } else if ((reduced_in_freq == 2) && (reduced_out_freq == 11)) {
+ *mode = kResamplerMode2To11;
+ } else if ((reduced_in_freq == 4) && (reduced_out_freq == 11)) {
+ *mode = kResamplerMode4To11;
+ } else if ((reduced_in_freq == 8) && (reduced_out_freq == 11)) {
+ *mode = kResamplerMode8To11;
+ } else if ((reduced_in_freq == 3) && (reduced_out_freq == 2)) {
+ *mode = kResamplerMode3To2;
+ } else if ((reduced_in_freq == 11) && (reduced_out_freq == 2)) {
+ *mode = kResamplerMode11To2;
+ } else if ((reduced_in_freq == 11) && (reduced_out_freq == 4)) {
+ *mode = kResamplerMode11To4;
+ } else if ((reduced_in_freq == 11) && (reduced_out_freq == 16)) {
+ *mode = kResamplerMode11To16;
+ } else if ((reduced_in_freq == 11) && (reduced_out_freq == 32)) {
+ *mode = kResamplerMode11To32;
+ } else if ((reduced_in_freq == 11) && (reduced_out_freq == 8)) {
+ *mode = kResamplerMode11To8;
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+// Synchronous resampling, all output samples are written to samplesOut
+int Resampler::Push(const int16_t* samplesIn,
+ size_t lengthIn,
+ int16_t* samplesOut,
+ size_t maxLen,
+ size_t& outLen) {
+ if (num_channels_ == 2) {
+ // Split up the signal and call the helper object for each channel
+ int16_t* left =
+ static_cast<int16_t*>(malloc(lengthIn * sizeof(int16_t) / 2));
+ int16_t* right =
+ static_cast<int16_t*>(malloc(lengthIn * sizeof(int16_t) / 2));
+ int16_t* out_left =
+ static_cast<int16_t*>(malloc(maxLen / 2 * sizeof(int16_t)));
+ int16_t* out_right =
+ static_cast<int16_t*>(malloc(maxLen / 2 * sizeof(int16_t)));
+ int res = 0;
+ for (size_t i = 0; i < lengthIn; i += 2) {
+ left[i >> 1] = samplesIn[i];
+ right[i >> 1] = samplesIn[i + 1];
}
- if (slave_right_)
- {
- delete slave_right_;
- slave_right_ = NULL;
+
+ // It's OK to overwrite the local parameter, since it's just a copy
+ lengthIn = lengthIn / 2;
+
+ size_t actualOutLen_left = 0;
+ size_t actualOutLen_right = 0;
+ // Do resampling for right channel
+ res |= helper_left_->Push(left, lengthIn, out_left, maxLen / 2,
+ actualOutLen_left);
+ res |= helper_right_->Push(right, lengthIn, out_right, maxLen / 2,
+ actualOutLen_right);
+ if (res || (actualOutLen_left != actualOutLen_right)) {
+ free(left);
+ free(right);
+ free(out_left);
+ free(out_right);
+ return -1;
}
- in_buffer_size_ = 0;
- out_buffer_size_ = 0;
- in_buffer_size_max_ = 0;
- out_buffer_size_max_ = 0;
-
- // Start with a math exercise, Euclid's algorithm to find the gcd:
- int a = inFreq;
- int b = outFreq;
- int c = a % b;
- while (c != 0)
- {
- a = b;
- b = c;
- c = a % b;
+ // Reassemble the signal
+ for (size_t i = 0; i < actualOutLen_left; i++) {
+ samplesOut[i * 2] = out_left[i];
+ samplesOut[i * 2 + 1] = out_right[i];
}
- // b is now the gcd;
+ outLen = 2 * actualOutLen_left;
- // We need to track what domain we're in.
- my_in_frequency_khz_ = inFreq / 1000;
- my_out_frequency_khz_ = outFreq / 1000;
+ free(left);
+ free(right);
+ free(out_left);
+ free(out_right);
- // Scale with GCD
- inFreq = inFreq / b;
- outFreq = outFreq / b;
+ return 0;
+ }
+
+ // Containers for temp samples
+ int16_t* tmp;
+ int16_t* tmp_2;
+ // tmp data for resampling routines
+ int32_t* tmp_mem;
+
+ switch (my_mode_) {
+ case kResamplerMode1To1:
+ memcpy(samplesOut, samplesIn, lengthIn * sizeof(int16_t));
+ outLen = lengthIn;
+ break;
+ case kResamplerMode1To2:
+ if (maxLen < (lengthIn * 2)) {
+ return -1;
+ }
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut,
+ static_cast<int32_t*>(state1_));
+ outLen = lengthIn * 2;
+ return 0;
+ case kResamplerMode1To3:
+
+ // We can only handle blocks of 160 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 160) != 0) {
+ return -1;
+ }
+ if (maxLen < (lengthIn * 3)) {
+ return -1;
+ }
+ tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t)));
+
+ for (size_t i = 0; i < lengthIn; i += 160) {
+ WebRtcSpl_Resample16khzTo48khz(
+ samplesIn + i, samplesOut + i * 3,
+ static_cast<WebRtcSpl_State16khzTo48khz*>(state1_), tmp_mem);
+ }
+ outLen = lengthIn * 3;
+ free(tmp_mem);
+ return 0;
+ case kResamplerMode1To4:
+ if (maxLen < (lengthIn * 4)) {
+ return -1;
+ }
+
+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * 2 * lengthIn));
+ // 1:2
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp,
+ static_cast<int32_t*>(state1_));
+ // 2:4
+ WebRtcSpl_UpsampleBy2(tmp, lengthIn * 2, samplesOut,
+ static_cast<int32_t*>(state2_));
+ outLen = lengthIn * 4;
+ free(tmp);
+ return 0;
+ case kResamplerMode1To6:
+ // We can only handle blocks of 80 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 80) != 0) {
+ return -1;
+ }
+ if (maxLen < (lengthIn * 6)) {
+ return -1;
+ }
+
+ // 1:2
+
+ tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t)));
+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * 2 * lengthIn));
+
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp,
+ static_cast<int32_t*>(state1_));
+ outLen = lengthIn * 2;
+
+ for (size_t i = 0; i < outLen; i += 160) {
+ WebRtcSpl_Resample16khzTo48khz(
+ tmp + i, samplesOut + i * 3,
+ static_cast<WebRtcSpl_State16khzTo48khz*>(state2_), tmp_mem);
+ }
+ outLen = outLen * 3;
+ free(tmp_mem);
+ free(tmp);
+
+ return 0;
+ case kResamplerMode1To12:
+ // We can only handle blocks of 40 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 40) != 0) {
+ return -1;
+ }
+ if (maxLen < (lengthIn * 12)) {
+ return -1;
+ }
+
+ tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t)));
+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * 4 * lengthIn));
+ // 1:2
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut,
+ static_cast<int32_t*>(state1_));
+ outLen = lengthIn * 2;
+ // 2:4
+ WebRtcSpl_UpsampleBy2(samplesOut, outLen, tmp,
+ static_cast<int32_t*>(state2_));
+ outLen = outLen * 2;
+ // 4:12
+ for (size_t i = 0; i < outLen; i += 160) {
+ // WebRtcSpl_Resample16khzTo48khz() takes a block of 160 samples
+ // as input and outputs a resampled block of 480 samples. The
+ // data is now actually in 32 kHz sampling rate, despite the
+ // function name, and with a resampling factor of three becomes
+ // 96 kHz.
+ WebRtcSpl_Resample16khzTo48khz(
+ tmp + i, samplesOut + i * 3,
+ static_cast<WebRtcSpl_State16khzTo48khz*>(state3_), tmp_mem);
+ }
+ outLen = outLen * 3;
+ free(tmp_mem);
+ free(tmp);
+
+ return 0;
+ case kResamplerMode2To3:
+ if (maxLen < (lengthIn * 3 / 2)) {
+ return -1;
+ }
+ // 2:6
+ // We can only handle blocks of 160 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 160) != 0) {
+ return -1;
+ }
+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn * 3));
+ tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t)));
+ for (size_t i = 0; i < lengthIn; i += 160) {
+ WebRtcSpl_Resample16khzTo48khz(
+ samplesIn + i, tmp + i * 3,
+ static_cast<WebRtcSpl_State16khzTo48khz*>(state1_), tmp_mem);
+ }
+ lengthIn = lengthIn * 3;
+ // 6:3
+ WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut,
+ static_cast<int32_t*>(state2_));
+ outLen = lengthIn / 2;
+ free(tmp);
+ free(tmp_mem);
+ return 0;
+ case kResamplerMode2To11:
+
+ // We can only handle blocks of 80 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 80) != 0) {
+ return -1;
+ }
+ if (maxLen < ((lengthIn * 11) / 2)) {
+ return -1;
+ }
+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * 2 * lengthIn));
+ // 1:2
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp,
+ static_cast<int32_t*>(state1_));
+ lengthIn *= 2;
+
+ tmp_mem = static_cast<int32_t*>(malloc(98 * sizeof(int32_t)));
+
+ for (size_t i = 0; i < lengthIn; i += 80) {
+ WebRtcSpl_Resample8khzTo22khz(
+ tmp + i, samplesOut + (i * 11) / 4,
+ static_cast<WebRtcSpl_State8khzTo22khz*>(state2_), tmp_mem);
+ }
+ outLen = (lengthIn * 11) / 4;
+ free(tmp_mem);
+ free(tmp);
+ return 0;
+ case kResamplerMode4To11:
+
+ // We can only handle blocks of 80 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 80) != 0) {
+ return -1;
+ }
+ if (maxLen < ((lengthIn * 11) / 4)) {
+ return -1;
+ }
+ tmp_mem = static_cast<int32_t*>(malloc(98 * sizeof(int32_t)));
+
+ for (size_t i = 0; i < lengthIn; i += 80) {
+ WebRtcSpl_Resample8khzTo22khz(
+ samplesIn + i, samplesOut + (i * 11) / 4,
+ static_cast<WebRtcSpl_State8khzTo22khz*>(state1_), tmp_mem);
+ }
+ outLen = (lengthIn * 11) / 4;
+ free(tmp_mem);
+ return 0;
+ case kResamplerMode8To11:
+ // We can only handle blocks of 160 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 160) != 0) {
+ return -1;
+ }
+ if (maxLen < ((lengthIn * 11) / 8)) {
+ return -1;
+ }
+ tmp_mem = static_cast<int32_t*>(malloc(88 * sizeof(int32_t)));
+
+ for (size_t i = 0; i < lengthIn; i += 160) {
+ WebRtcSpl_Resample16khzTo22khz(
+ samplesIn + i, samplesOut + (i * 11) / 8,
+ static_cast<WebRtcSpl_State16khzTo22khz*>(state1_), tmp_mem);
+ }
+ outLen = (lengthIn * 11) / 8;
+ free(tmp_mem);
+ return 0;
+
+ case kResamplerMode11To16:
+ // We can only handle blocks of 110 samples
+ if ((lengthIn % 110) != 0) {
+ return -1;
+ }
+ if (maxLen < ((lengthIn * 16) / 11)) {
+ return -1;
+ }
- if (num_channels_ == 2)
- {
- // Create two mono resamplers.
- slave_left_ = new Resampler(inFreq, outFreq, 1);
- slave_right_ = new Resampler(inFreq, outFreq, 1);
- }
+ tmp_mem = static_cast<int32_t*>(malloc(104 * sizeof(int32_t)));
+ tmp = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn * 2)));
+
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp,
+ static_cast<int32_t*>(state1_));
+
+ for (size_t i = 0; i < (lengthIn * 2); i += 220) {
+ WebRtcSpl_Resample22khzTo16khz(
+ tmp + i, samplesOut + (i / 220) * 160,
+ static_cast<WebRtcSpl_State22khzTo16khz*>(state2_), tmp_mem);
+ }
+
+ outLen = (lengthIn * 16) / 11;
- if (inFreq == outFreq)
- {
- my_mode_ = kResamplerMode1To1;
- } else if (inFreq == 1)
- {
- switch (outFreq)
- {
- case 2:
- my_mode_ = kResamplerMode1To2;
- break;
- case 3:
- my_mode_ = kResamplerMode1To3;
- break;
- case 4:
- my_mode_ = kResamplerMode1To4;
- break;
- case 6:
- my_mode_ = kResamplerMode1To6;
- break;
- case 12:
- my_mode_ = kResamplerMode1To12;
- break;
- default:
- return -1;
- }
- } else if (outFreq == 1)
- {
- switch (inFreq)
- {
- case 2:
- my_mode_ = kResamplerMode2To1;
- break;
- case 3:
- my_mode_ = kResamplerMode3To1;
- break;
- case 4:
- my_mode_ = kResamplerMode4To1;
- break;
- case 6:
- my_mode_ = kResamplerMode6To1;
- break;
- case 12:
- my_mode_ = kResamplerMode12To1;
- break;
- default:
- return -1;
- }
- } else if ((inFreq == 2) && (outFreq == 3))
- {
- my_mode_ = kResamplerMode2To3;
- } else if ((inFreq == 2) && (outFreq == 11))
- {
- my_mode_ = kResamplerMode2To11;
- } else if ((inFreq == 4) && (outFreq == 11))
- {
- my_mode_ = kResamplerMode4To11;
- } else if ((inFreq == 8) && (outFreq == 11))
- {
- my_mode_ = kResamplerMode8To11;
- } else if ((inFreq == 3) && (outFreq == 2))
- {
- my_mode_ = kResamplerMode3To2;
- } else if ((inFreq == 11) && (outFreq == 2))
- {
- my_mode_ = kResamplerMode11To2;
- } else if ((inFreq == 11) && (outFreq == 4))
- {
- my_mode_ = kResamplerMode11To4;
- } else if ((inFreq == 11) && (outFreq == 16))
- {
- my_mode_ = kResamplerMode11To16;
- } else if ((inFreq == 11) && (outFreq == 32))
- {
- my_mode_ = kResamplerMode11To32;
- } else if ((inFreq == 11) && (outFreq == 8))
- {
- my_mode_ = kResamplerMode11To8;
- } else
- {
+ free(tmp_mem);
+ free(tmp);
+ return 0;
+
+ case kResamplerMode11To32:
+
+ // We can only handle blocks of 110 samples
+ if ((lengthIn % 110) != 0) {
return -1;
- }
+ }
+ if (maxLen < ((lengthIn * 32) / 11)) {
+ return -1;
+ }
- // Now create the states we need
- switch (my_mode_)
- {
- case kResamplerMode1To1:
- // No state needed;
- break;
- case kResamplerMode1To2:
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
- break;
- case kResamplerMode1To3:
- state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
- WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state1_);
- break;
- case kResamplerMode1To4:
- // 1:2
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
- // 2:4
- state2_ = malloc(8 * sizeof(int32_t));
- memset(state2_, 0, 8 * sizeof(int32_t));
- break;
- case kResamplerMode1To6:
- // 1:2
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
- // 2:6
- state2_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
- WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state2_);
- break;
- case kResamplerMode1To12:
- // 1:2
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
- // 2:4
- state2_ = malloc(8 * sizeof(int32_t));
- memset(state2_, 0, 8 * sizeof(int32_t));
- // 4:12
- state3_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
- WebRtcSpl_ResetResample16khzTo48khz(
- (WebRtcSpl_State16khzTo48khz*) state3_);
- break;
- case kResamplerMode2To3:
- // 2:6
- state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
- WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state1_);
- // 6:3
- state2_ = malloc(8 * sizeof(int32_t));
- memset(state2_, 0, 8 * sizeof(int32_t));
- break;
- case kResamplerMode2To11:
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
-
- state2_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz));
- WebRtcSpl_ResetResample8khzTo22khz((WebRtcSpl_State8khzTo22khz *)state2_);
- break;
- case kResamplerMode4To11:
- state1_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz));
- WebRtcSpl_ResetResample8khzTo22khz((WebRtcSpl_State8khzTo22khz *)state1_);
- break;
- case kResamplerMode8To11:
- state1_ = malloc(sizeof(WebRtcSpl_State16khzTo22khz));
- WebRtcSpl_ResetResample16khzTo22khz((WebRtcSpl_State16khzTo22khz *)state1_);
- break;
- case kResamplerMode11To16:
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
-
- state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz));
- WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state2_);
- break;
- case kResamplerMode11To32:
- // 11 -> 22
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
-
- // 22 -> 16
- state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz));
- WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state2_);
-
- // 16 -> 32
- state3_ = malloc(8 * sizeof(int32_t));
- memset(state3_, 0, 8 * sizeof(int32_t));
-
- break;
- case kResamplerMode2To1:
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
- break;
- case kResamplerMode3To1:
- state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz));
- WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state1_);
- break;
- case kResamplerMode4To1:
- // 4:2
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
- // 2:1
- state2_ = malloc(8 * sizeof(int32_t));
- memset(state2_, 0, 8 * sizeof(int32_t));
- break;
- case kResamplerMode6To1:
- // 6:2
- state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz));
- WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state1_);
- // 2:1
- state2_ = malloc(8 * sizeof(int32_t));
- memset(state2_, 0, 8 * sizeof(int32_t));
- break;
- case kResamplerMode12To1:
- // 12:4
- state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz));
- WebRtcSpl_ResetResample48khzTo16khz(
- (WebRtcSpl_State48khzTo16khz*) state1_);
- // 4:2
- state2_ = malloc(8 * sizeof(int32_t));
- memset(state2_, 0, 8 * sizeof(int32_t));
- // 2:1
- state3_ = malloc(8 * sizeof(int32_t));
- memset(state3_, 0, 8 * sizeof(int32_t));
- break;
- case kResamplerMode3To2:
- // 3:6
- state1_ = malloc(8 * sizeof(int32_t));
- memset(state1_, 0, 8 * sizeof(int32_t));
- // 6:2
- state2_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz));
- WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state2_);
- break;
- case kResamplerMode11To2:
- state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz));
- WebRtcSpl_ResetResample22khzTo8khz((WebRtcSpl_State22khzTo8khz *)state1_);
-
- state2_ = malloc(8 * sizeof(int32_t));
- memset(state2_, 0, 8 * sizeof(int32_t));
-
- break;
- case kResamplerMode11To4:
- state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz));
- WebRtcSpl_ResetResample22khzTo8khz((WebRtcSpl_State22khzTo8khz *)state1_);
- break;
- case kResamplerMode11To8:
- state1_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz));
- WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state1_);
- break;
+ tmp_mem = static_cast<int32_t*>(malloc(104 * sizeof(int32_t)));
+ tmp = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn * 2)));
- }
+ // 11 -> 22 kHz in samplesOut
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut,
+ static_cast<int32_t*>(state1_));
- return 0;
-}
+ // 22 -> 16 in tmp
+ for (size_t i = 0; i < (lengthIn * 2); i += 220) {
+ WebRtcSpl_Resample22khzTo16khz(
+ samplesOut + i, tmp + (i / 220) * 160,
+ static_cast<WebRtcSpl_State22khzTo16khz*>(state2_), tmp_mem);
+ }
-// Synchronous resampling, all output samples are written to samplesOut
-int Resampler::Push(const int16_t * samplesIn, size_t lengthIn,
- int16_t* samplesOut, size_t maxLen, size_t &outLen)
-{
- if (num_channels_ == 2)
- {
- // Split up the signal and call the slave object for each channel
- int16_t* left = (int16_t*)malloc(lengthIn * sizeof(int16_t) / 2);
- int16_t* right = (int16_t*)malloc(lengthIn * sizeof(int16_t) / 2);
- int16_t* out_left = (int16_t*)malloc(maxLen / 2 * sizeof(int16_t));
- int16_t* out_right =
- (int16_t*)malloc(maxLen / 2 * sizeof(int16_t));
- int res = 0;
- for (size_t i = 0; i < lengthIn; i += 2)
- {
- left[i >> 1] = samplesIn[i];
- right[i >> 1] = samplesIn[i + 1];
- }
-
- // It's OK to overwrite the local parameter, since it's just a copy
- lengthIn = lengthIn / 2;
-
- size_t actualOutLen_left = 0;
- size_t actualOutLen_right = 0;
- // Do resampling for right channel
- res |= slave_left_->Push(left, lengthIn, out_left, maxLen / 2, actualOutLen_left);
- res |= slave_right_->Push(right, lengthIn, out_right, maxLen / 2, actualOutLen_right);
- if (res || (actualOutLen_left != actualOutLen_right))
- {
- free(left);
- free(right);
- free(out_left);
- free(out_right);
- return -1;
- }
-
- // Reassemble the signal
- for (size_t i = 0; i < actualOutLen_left; i++)
- {
- samplesOut[i * 2] = out_left[i];
- samplesOut[i * 2 + 1] = out_right[i];
- }
- outLen = 2 * actualOutLen_left;
-
- free(left);
- free(right);
- free(out_left);
- free(out_right);
-
- return 0;
- }
+ // 16 -> 32 in samplesOut
+ WebRtcSpl_UpsampleBy2(tmp, (lengthIn * 16) / 11, samplesOut,
+ static_cast<int32_t*>(state3_));
- // Containers for temp samples
- int16_t* tmp;
- int16_t* tmp_2;
- // tmp data for resampling routines
- int32_t* tmp_mem;
-
- switch (my_mode_)
- {
- case kResamplerMode1To1:
- memcpy(samplesOut, samplesIn, lengthIn * sizeof(int16_t));
- outLen = lengthIn;
- break;
- case kResamplerMode1To2:
- if (maxLen < (lengthIn * 2))
- {
- return -1;
- }
- WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, (int32_t*)state1_);
- outLen = lengthIn * 2;
- return 0;
- case kResamplerMode1To3:
-
- // We can only handle blocks of 160 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 160) != 0)
- {
- return -1;
- }
- if (maxLen < (lengthIn * 3))
- {
- return -1;
- }
- tmp_mem = (int32_t*)malloc(336 * sizeof(int32_t));
-
- for (size_t i = 0; i < lengthIn; i += 160)
- {
- WebRtcSpl_Resample16khzTo48khz(samplesIn + i, samplesOut + i * 3,
- (WebRtcSpl_State16khzTo48khz *)state1_,
- tmp_mem);
- }
- outLen = lengthIn * 3;
- free(tmp_mem);
- return 0;
- case kResamplerMode1To4:
- if (maxLen < (lengthIn * 4))
- {
- return -1;
- }
-
- tmp = (int16_t*)malloc(sizeof(int16_t) * 2 * lengthIn);
- // 1:2
- WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
- // 2:4
- WebRtcSpl_UpsampleBy2(tmp, lengthIn * 2, samplesOut, (int32_t*)state2_);
- outLen = lengthIn * 4;
- free(tmp);
- return 0;
- case kResamplerMode1To6:
- // We can only handle blocks of 80 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 80) != 0)
- {
- return -1;
- }
- if (maxLen < (lengthIn * 6))
- {
- return -1;
- }
-
- //1:2
-
- tmp_mem = (int32_t*)malloc(336 * sizeof(int32_t));
- tmp = (int16_t*)malloc(sizeof(int16_t) * 2 * lengthIn);
-
- WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
- outLen = lengthIn * 2;
-
- for (size_t i = 0; i < outLen; i += 160)
- {
- WebRtcSpl_Resample16khzTo48khz(tmp + i, samplesOut + i * 3,
- (WebRtcSpl_State16khzTo48khz *)state2_,
- tmp_mem);
- }
- outLen = outLen * 3;
- free(tmp_mem);
- free(tmp);
-
- return 0;
- case kResamplerMode1To12:
- // We can only handle blocks of 40 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 40) != 0) {
- return -1;
- }
- if (maxLen < (lengthIn * 12)) {
- return -1;
- }
-
- tmp_mem = (int32_t*) malloc(336 * sizeof(int32_t));
- tmp = (int16_t*) malloc(sizeof(int16_t) * 4 * lengthIn);
- //1:2
- WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut,
- (int32_t*) state1_);
- outLen = lengthIn * 2;
- //2:4
- WebRtcSpl_UpsampleBy2(samplesOut, outLen, tmp, (int32_t*) state2_);
- outLen = outLen * 2;
- // 4:12
- for (size_t i = 0; i < outLen; i += 160) {
- // WebRtcSpl_Resample16khzTo48khz() takes a block of 160 samples
- // as input and outputs a resampled block of 480 samples. The
- // data is now actually in 32 kHz sampling rate, despite the
- // function name, and with a resampling factor of three becomes
- // 96 kHz.
- WebRtcSpl_Resample16khzTo48khz(tmp + i, samplesOut + i * 3,
- (WebRtcSpl_State16khzTo48khz*) state3_,
- tmp_mem);
- }
- outLen = outLen * 3;
- free(tmp_mem);
- free(tmp);
-
- return 0;
- case kResamplerMode2To3:
- if (maxLen < (lengthIn * 3 / 2))
- {
- return -1;
- }
- // 2:6
- // We can only handle blocks of 160 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 160) != 0)
- {
- return -1;
- }
- tmp = static_cast<int16_t*> (malloc(sizeof(int16_t) * lengthIn * 3));
- tmp_mem = (int32_t*)malloc(336 * sizeof(int32_t));
- for (size_t i = 0; i < lengthIn; i += 160)
- {
- WebRtcSpl_Resample16khzTo48khz(samplesIn + i, tmp + i * 3,
- (WebRtcSpl_State16khzTo48khz *)state1_,
- tmp_mem);
- }
- lengthIn = lengthIn * 3;
- // 6:3
- WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, (int32_t*)state2_);
- outLen = lengthIn / 2;
- free(tmp);
- free(tmp_mem);
- return 0;
- case kResamplerMode2To11:
-
- // We can only handle blocks of 80 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 80) != 0)
- {
- return -1;
- }
- if (maxLen < ((lengthIn * 11) / 2))
- {
- return -1;
- }
- tmp = (int16_t*)malloc(sizeof(int16_t) * 2 * lengthIn);
- // 1:2
- WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
- lengthIn *= 2;
-
- tmp_mem = (int32_t*)malloc(98 * sizeof(int32_t));
-
- for (size_t i = 0; i < lengthIn; i += 80)
- {
- WebRtcSpl_Resample8khzTo22khz(tmp + i, samplesOut + (i * 11) / 4,
- (WebRtcSpl_State8khzTo22khz *)state2_,
- tmp_mem);
- }
- outLen = (lengthIn * 11) / 4;
- free(tmp_mem);
- free(tmp);
- return 0;
- case kResamplerMode4To11:
-
- // We can only handle blocks of 80 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 80) != 0)
- {
- return -1;
- }
- if (maxLen < ((lengthIn * 11) / 4))
- {
- return -1;
- }
- tmp_mem = (int32_t*)malloc(98 * sizeof(int32_t));
-
- for (size_t i = 0; i < lengthIn; i += 80)
- {
- WebRtcSpl_Resample8khzTo22khz(samplesIn + i, samplesOut + (i * 11) / 4,
- (WebRtcSpl_State8khzTo22khz *)state1_,
- tmp_mem);
- }
- outLen = (lengthIn * 11) / 4;
- free(tmp_mem);
- return 0;
- case kResamplerMode8To11:
- // We can only handle blocks of 160 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 160) != 0)
- {
- return -1;
- }
- if (maxLen < ((lengthIn * 11) / 8))
- {
- return -1;
- }
- tmp_mem = (int32_t*)malloc(88 * sizeof(int32_t));
-
- for (size_t i = 0; i < lengthIn; i += 160)
- {
- WebRtcSpl_Resample16khzTo22khz(samplesIn + i, samplesOut + (i * 11) / 8,
- (WebRtcSpl_State16khzTo22khz *)state1_,
- tmp_mem);
- }
- outLen = (lengthIn * 11) / 8;
- free(tmp_mem);
- return 0;
-
- case kResamplerMode11To16:
- // We can only handle blocks of 110 samples
- if ((lengthIn % 110) != 0)
- {
- return -1;
- }
- if (maxLen < ((lengthIn * 16) / 11))
- {
- return -1;
- }
-
- tmp_mem = (int32_t*)malloc(104 * sizeof(int32_t));
- tmp = (int16_t*)malloc((sizeof(int16_t) * lengthIn * 2));
-
- WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
-
- for (size_t i = 0; i < (lengthIn * 2); i += 220)
- {
- WebRtcSpl_Resample22khzTo16khz(tmp + i, samplesOut + (i / 220) * 160,
- (WebRtcSpl_State22khzTo16khz *)state2_,
- tmp_mem);
- }
-
- outLen = (lengthIn * 16) / 11;
-
- free(tmp_mem);
- free(tmp);
- return 0;
-
- case kResamplerMode11To32:
-
- // We can only handle blocks of 110 samples
- if ((lengthIn % 110) != 0)
- {
- return -1;
- }
- if (maxLen < ((lengthIn * 32) / 11))
- {
- return -1;
- }
-
- tmp_mem = (int32_t*)malloc(104 * sizeof(int32_t));
- tmp = (int16_t*)malloc((sizeof(int16_t) * lengthIn * 2));
-
- // 11 -> 22 kHz in samplesOut
- WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, (int32_t*)state1_);
-
- // 22 -> 16 in tmp
- for (size_t i = 0; i < (lengthIn * 2); i += 220)
- {
- WebRtcSpl_Resample22khzTo16khz(samplesOut + i, tmp + (i / 220) * 160,
- (WebRtcSpl_State22khzTo16khz *)state2_,
- tmp_mem);
- }
-
- // 16 -> 32 in samplesOut
- WebRtcSpl_UpsampleBy2(tmp, (lengthIn * 16) / 11, samplesOut,
- (int32_t*)state3_);
-
- outLen = (lengthIn * 32) / 11;
-
- free(tmp_mem);
- free(tmp);
- return 0;
-
- case kResamplerMode2To1:
- if (maxLen < (lengthIn / 2))
- {
- return -1;
- }
- WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, samplesOut, (int32_t*)state1_);
- outLen = lengthIn / 2;
- return 0;
- case kResamplerMode3To1:
- // We can only handle blocks of 480 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 480) != 0)
- {
- return -1;
- }
- if (maxLen < (lengthIn / 3))
- {
- return -1;
- }
- tmp_mem = (int32_t*)malloc(496 * sizeof(int32_t));
-
- for (size_t i = 0; i < lengthIn; i += 480)
- {
- WebRtcSpl_Resample48khzTo16khz(samplesIn + i, samplesOut + i / 3,
- (WebRtcSpl_State48khzTo16khz *)state1_,
- tmp_mem);
- }
- outLen = lengthIn / 3;
- free(tmp_mem);
- return 0;
- case kResamplerMode4To1:
- if (maxLen < (lengthIn / 4))
- {
- return -1;
- }
- tmp = (int16_t*)malloc(sizeof(int16_t) * lengthIn / 2);
- // 4:2
- WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
- // 2:1
- WebRtcSpl_DownsampleBy2(tmp, lengthIn / 2, samplesOut, (int32_t*)state2_);
- outLen = lengthIn / 4;
- free(tmp);
- return 0;
-
- case kResamplerMode6To1:
- // We can only handle blocks of 480 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 480) != 0)
- {
- return -1;
- }
- if (maxLen < (lengthIn / 6))
- {
- return -1;
- }
-
- tmp_mem = (int32_t*)malloc(496 * sizeof(int32_t));
- tmp = (int16_t*)malloc((sizeof(int16_t) * lengthIn) / 3);
-
- for (size_t i = 0; i < lengthIn; i += 480)
- {
- WebRtcSpl_Resample48khzTo16khz(samplesIn + i, tmp + i / 3,
- (WebRtcSpl_State48khzTo16khz *)state1_,
- tmp_mem);
- }
- outLen = lengthIn / 3;
- free(tmp_mem);
- WebRtcSpl_DownsampleBy2(tmp, outLen, samplesOut, (int32_t*)state2_);
- free(tmp);
- outLen = outLen / 2;
- return 0;
- case kResamplerMode12To1:
- // We can only handle blocks of 480 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 480) != 0) {
- return -1;
- }
- if (maxLen < (lengthIn / 12)) {
- return -1;
- }
-
- tmp_mem = (int32_t*) malloc(496 * sizeof(int32_t));
- tmp = (int16_t*) malloc((sizeof(int16_t) * lengthIn) / 3);
- tmp_2 = (int16_t*) malloc((sizeof(int16_t) * lengthIn) / 6);
- // 12:4
- for (size_t i = 0; i < lengthIn; i += 480) {
- // WebRtcSpl_Resample48khzTo16khz() takes a block of 480 samples
- // as input and outputs a resampled block of 160 samples. The
- // data is now actually in 96 kHz sampling rate, despite the
- // function name, and with a resampling factor of 1/3 becomes
- // 32 kHz.
- WebRtcSpl_Resample48khzTo16khz(samplesIn + i, tmp + i / 3,
- (WebRtcSpl_State48khzTo16khz*) state1_,
- tmp_mem);
- }
- outLen = lengthIn / 3;
- free(tmp_mem);
- // 4:2
- WebRtcSpl_DownsampleBy2(tmp, outLen, tmp_2, (int32_t*) state2_);
- outLen = outLen / 2;
- free(tmp);
- // 2:1
- WebRtcSpl_DownsampleBy2(tmp_2, outLen, samplesOut,
- (int32_t*) state3_);
- free(tmp_2);
- outLen = outLen / 2;
- return 0;
- case kResamplerMode3To2:
- if (maxLen < (lengthIn * 2 / 3))
- {
- return -1;
- }
- // 3:6
- tmp = static_cast<int16_t*> (malloc(sizeof(int16_t) * lengthIn * 2));
- WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
- lengthIn *= 2;
- // 6:2
- // We can only handle blocks of 480 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 480) != 0)
- {
- free(tmp);
- return -1;
- }
- tmp_mem = (int32_t*)malloc(496 * sizeof(int32_t));
- for (size_t i = 0; i < lengthIn; i += 480)
- {
- WebRtcSpl_Resample48khzTo16khz(tmp + i, samplesOut + i / 3,
- (WebRtcSpl_State48khzTo16khz *)state2_,
- tmp_mem);
- }
- outLen = lengthIn / 3;
- free(tmp);
- free(tmp_mem);
- return 0;
- case kResamplerMode11To2:
- // We can only handle blocks of 220 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 220) != 0)
- {
- return -1;
- }
- if (maxLen < ((lengthIn * 2) / 11))
- {
- return -1;
- }
- tmp_mem = (int32_t*)malloc(126 * sizeof(int32_t));
- tmp = (int16_t*)malloc((lengthIn * 4) / 11 * sizeof(int16_t));
-
- for (size_t i = 0; i < lengthIn; i += 220)
- {
- WebRtcSpl_Resample22khzTo8khz(samplesIn + i, tmp + (i * 4) / 11,
- (WebRtcSpl_State22khzTo8khz *)state1_,
- tmp_mem);
- }
- lengthIn = (lengthIn * 4) / 11;
-
- WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut,
- (int32_t*)state2_);
- outLen = lengthIn / 2;
-
- free(tmp_mem);
- free(tmp);
- return 0;
- case kResamplerMode11To4:
- // We can only handle blocks of 220 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 220) != 0)
- {
- return -1;
- }
- if (maxLen < ((lengthIn * 4) / 11))
- {
- return -1;
- }
- tmp_mem = (int32_t*)malloc(126 * sizeof(int32_t));
-
- for (size_t i = 0; i < lengthIn; i += 220)
- {
- WebRtcSpl_Resample22khzTo8khz(samplesIn + i, samplesOut + (i * 4) / 11,
- (WebRtcSpl_State22khzTo8khz *)state1_,
- tmp_mem);
- }
- outLen = (lengthIn * 4) / 11;
- free(tmp_mem);
- return 0;
- case kResamplerMode11To8:
- // We can only handle blocks of 160 samples
- // Can be fixed, but I don't think it's needed
- if ((lengthIn % 220) != 0)
- {
- return -1;
- }
- if (maxLen < ((lengthIn * 8) / 11))
- {
- return -1;
- }
- tmp_mem = (int32_t*)malloc(104 * sizeof(int32_t));
-
- for (size_t i = 0; i < lengthIn; i += 220)
- {
- WebRtcSpl_Resample22khzTo16khz(samplesIn + i, samplesOut + (i * 8) / 11,
- (WebRtcSpl_State22khzTo16khz *)state1_,
- tmp_mem);
- }
- outLen = (lengthIn * 8) / 11;
- free(tmp_mem);
- return 0;
- break;
+ outLen = (lengthIn * 32) / 11;
- }
- return 0;
+ free(tmp_mem);
+ free(tmp);
+ return 0;
+
+ case kResamplerMode2To1:
+ if (maxLen < (lengthIn / 2)) {
+ return -1;
+ }
+ WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, samplesOut,
+ static_cast<int32_t*>(state1_));
+ outLen = lengthIn / 2;
+ return 0;
+ case kResamplerMode3To1:
+ // We can only handle blocks of 480 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 480) != 0) {
+ return -1;
+ }
+ if (maxLen < (lengthIn / 3)) {
+ return -1;
+ }
+ tmp_mem = static_cast<int32_t*>(malloc(496 * sizeof(int32_t)));
+
+ for (size_t i = 0; i < lengthIn; i += 480) {
+ WebRtcSpl_Resample48khzTo16khz(
+ samplesIn + i, samplesOut + i / 3,
+ static_cast<WebRtcSpl_State48khzTo16khz*>(state1_), tmp_mem);
+ }
+ outLen = lengthIn / 3;
+ free(tmp_mem);
+ return 0;
+ case kResamplerMode4To1:
+ if (maxLen < (lengthIn / 4)) {
+ return -1;
+ }
+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn / 2));
+ // 4:2
+ WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, tmp,
+ static_cast<int32_t*>(state1_));
+ // 2:1
+ WebRtcSpl_DownsampleBy2(tmp, lengthIn / 2, samplesOut,
+ static_cast<int32_t*>(state2_));
+ outLen = lengthIn / 4;
+ free(tmp);
+ return 0;
+
+ case kResamplerMode6To1:
+ // We can only handle blocks of 480 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 480) != 0) {
+ return -1;
+ }
+ if (maxLen < (lengthIn / 6)) {
+ return -1;
+ }
+
+ tmp_mem = static_cast<int32_t*>(malloc(496 * sizeof(int32_t)));
+ tmp = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn) / 3));
+
+ for (size_t i = 0; i < lengthIn; i += 480) {
+ WebRtcSpl_Resample48khzTo16khz(
+ samplesIn + i, tmp + i / 3,
+ static_cast<WebRtcSpl_State48khzTo16khz*>(state1_), tmp_mem);
+ }
+ outLen = lengthIn / 3;
+ free(tmp_mem);
+ WebRtcSpl_DownsampleBy2(tmp, outLen, samplesOut,
+ static_cast<int32_t*>(state2_));
+ free(tmp);
+ outLen = outLen / 2;
+ return 0;
+ case kResamplerMode12To1:
+ // We can only handle blocks of 480 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 480) != 0) {
+ return -1;
+ }
+ if (maxLen < (lengthIn / 12)) {
+ return -1;
+ }
+
+ tmp_mem = static_cast<int32_t*>(malloc(496 * sizeof(int32_t)));
+ tmp = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn) / 3));
+ tmp_2 = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn) / 6));
+ // 12:4
+ for (size_t i = 0; i < lengthIn; i += 480) {
+ // WebRtcSpl_Resample48khzTo16khz() takes a block of 480 samples
+ // as input and outputs a resampled block of 160 samples. The
+ // data is now actually in 96 kHz sampling rate, despite the
+ // function name, and with a resampling factor of 1/3 becomes
+ // 32 kHz.
+ WebRtcSpl_Resample48khzTo16khz(
+ samplesIn + i, tmp + i / 3,
+ static_cast<WebRtcSpl_State48khzTo16khz*>(state1_), tmp_mem);
+ }
+ outLen = lengthIn / 3;
+ free(tmp_mem);
+ // 4:2
+ WebRtcSpl_DownsampleBy2(tmp, outLen, tmp_2,
+ static_cast<int32_t*>(state2_));
+ outLen = outLen / 2;
+ free(tmp);
+ // 2:1
+ WebRtcSpl_DownsampleBy2(tmp_2, outLen, samplesOut,
+ static_cast<int32_t*>(state3_));
+ free(tmp_2);
+ outLen = outLen / 2;
+ return 0;
+ case kResamplerMode3To2:
+ if (maxLen < (lengthIn * 2 / 3)) {
+ return -1;
+ }
+ // 3:6
+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn * 2));
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp,
+ static_cast<int32_t*>(state1_));
+ lengthIn *= 2;
+ // 6:2
+ // We can only handle blocks of 480 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 480) != 0) {
+ free(tmp);
+ return -1;
+ }
+ tmp_mem = static_cast<int32_t*>(malloc(496 * sizeof(int32_t)));
+ for (size_t i = 0; i < lengthIn; i += 480) {
+ WebRtcSpl_Resample48khzTo16khz(
+ tmp + i, samplesOut + i / 3,
+ static_cast<WebRtcSpl_State48khzTo16khz*>(state2_), tmp_mem);
+ }
+ outLen = lengthIn / 3;
+ free(tmp);
+ free(tmp_mem);
+ return 0;
+ case kResamplerMode11To2:
+ // We can only handle blocks of 220 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 220) != 0) {
+ return -1;
+ }
+ if (maxLen < ((lengthIn * 2) / 11)) {
+ return -1;
+ }
+ tmp_mem = static_cast<int32_t*>(malloc(126 * sizeof(int32_t)));
+ tmp =
+ static_cast<int16_t*>(malloc((lengthIn * 4) / 11 * sizeof(int16_t)));
+
+ for (size_t i = 0; i < lengthIn; i += 220) {
+ WebRtcSpl_Resample22khzTo8khz(
+ samplesIn + i, tmp + (i * 4) / 11,
+ static_cast<WebRtcSpl_State22khzTo8khz*>(state1_), tmp_mem);
+ }
+ lengthIn = (lengthIn * 4) / 11;
+
+ WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut,
+ static_cast<int32_t*>(state2_));
+ outLen = lengthIn / 2;
+
+ free(tmp_mem);
+ free(tmp);
+ return 0;
+ case kResamplerMode11To4:
+ // We can only handle blocks of 220 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 220) != 0) {
+ return -1;
+ }
+ if (maxLen < ((lengthIn * 4) / 11)) {
+ return -1;
+ }
+ tmp_mem = static_cast<int32_t*>(malloc(126 * sizeof(int32_t)));
+
+ for (size_t i = 0; i < lengthIn; i += 220) {
+ WebRtcSpl_Resample22khzTo8khz(
+ samplesIn + i, samplesOut + (i * 4) / 11,
+ static_cast<WebRtcSpl_State22khzTo8khz*>(state1_), tmp_mem);
+ }
+ outLen = (lengthIn * 4) / 11;
+ free(tmp_mem);
+ return 0;
+ case kResamplerMode11To8:
+ // We can only handle blocks of 160 samples
+ // Can be fixed, but I don't think it's needed
+ if ((lengthIn % 220) != 0) {
+ return -1;
+ }
+ if (maxLen < ((lengthIn * 8) / 11)) {
+ return -1;
+ }
+ tmp_mem = static_cast<int32_t*>(malloc(104 * sizeof(int32_t)));
+
+ for (size_t i = 0; i < lengthIn; i += 220) {
+ WebRtcSpl_Resample22khzTo16khz(
+ samplesIn + i, samplesOut + (i * 8) / 11,
+ static_cast<WebRtcSpl_State22khzTo16khz*>(state1_), tmp_mem);
+ }
+ outLen = (lengthIn * 8) / 11;
+ free(tmp_mem);
+ return 0;
+ break;
+ }
+ return 0;
}
} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/sinc_resampler.cc b/webrtc/common_audio/resampler/sinc_resampler.cc
index 69ac220..4fa78c5 100644
--- a/webrtc/common_audio/resampler/sinc_resampler.cc
+++ b/webrtc/common_audio/resampler/sinc_resampler.cc
@@ -85,16 +85,17 @@
// MSVC++ requires this to be set before any other includes to get M_PI.
#define _USE_MATH_DEFINES
-#include "webrtc/common_audio/resampler/sinc_resampler.h"
+#include "common_audio/resampler/sinc_resampler.h"
-#include <assert.h>
#include <math.h>
+#include <stdint.h>
#include <string.h>
#include <limits>
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
-#include "webrtc/typedefs.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/system/arch.h"
+#include "system_wrappers/include/cpu_features_wrapper.h" // kSSE2, WebRtc_G...
namespace webrtc {
@@ -118,35 +119,25 @@ double SincScaleFactor(double io_ratio) {
} // namespace
-// If we know the minimum architecture at compile time, avoid CPU detection.
-#if defined(WEBRTC_ARCH_X86_FAMILY)
-#if defined(__SSE2__)
-#define CONVOLVE_FUNC Convolve_SSE
-void SincResampler::InitializeCPUSpecificFeatures() {}
-#else
-// x86 CPU detection required. Function will be set by
-// InitializeCPUSpecificFeatures().
-// TODO(dalecurtis): Once Chrome moves to an SSE baseline this can be removed.
-#define CONVOLVE_FUNC convolve_proc_
+const size_t SincResampler::kKernelSize;
+// If we know the minimum architecture at compile time, avoid CPU detection.
void SincResampler::InitializeCPUSpecificFeatures() {
- convolve_proc_ = WebRtc_GetCPUInfo(kSSE2) ? Convolve_SSE : Convolve_C;
-}
-#endif
-#elif defined(WEBRTC_HAS_NEON)
-#define CONVOLVE_FUNC Convolve_NEON
-void SincResampler::InitializeCPUSpecificFeatures() {}
-#elif defined(WEBRTC_DETECT_NEON)
-#define CONVOLVE_FUNC convolve_proc_
-void SincResampler::InitializeCPUSpecificFeatures() {
- convolve_proc_ = WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON ?
- Convolve_NEON : Convolve_C;
-}
+#if defined(WEBRTC_HAS_NEON)
+ convolve_proc_ = Convolve_NEON;
+#elif defined(WEBRTC_ARCH_X86_FAMILY)
+ // Using AVX2 instead of SSE2 when AVX2 supported.
+ if (GetCPUInfo(kAVX2))
+ convolve_proc_ = Convolve_AVX2;
+ else if (GetCPUInfo(kSSE2))
+ convolve_proc_ = Convolve_SSE;
+ else
+ convolve_proc_ = Convolve_C;
#else
-// Unknown architecture.
-#define CONVOLVE_FUNC Convolve_C
-void SincResampler::InitializeCPUSpecificFeatures() {}
+ // Unknown architecture.
+ convolve_proc_ = Convolve_C;
#endif
+}
SincResampler::SincResampler(double io_sample_rate_ratio,
size_t request_frames,
@@ -155,27 +146,23 @@ SincResampler::SincResampler(double io_sample_rate_ratio,
read_cb_(read_cb),
request_frames_(request_frames),
input_buffer_size_(request_frames_ + kKernelSize),
- // Create input buffers with a 16-byte alignment for SSE optimizations.
+ // Create input buffers with a 32-byte alignment for SIMD optimizations.
kernel_storage_(static_cast<float*>(
- AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
+ AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))),
kernel_pre_sinc_storage_(static_cast<float*>(
- AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
+ AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))),
kernel_window_storage_(static_cast<float*>(
- AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
+ AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))),
input_buffer_(static_cast<float*>(
- AlignedMalloc(sizeof(float) * input_buffer_size_, 16))),
-#if defined(WEBRTC_CPU_DETECTION)
- convolve_proc_(NULL),
-#endif
+ AlignedMalloc(sizeof(float) * input_buffer_size_, 32))),
+ convolve_proc_(nullptr),
r1_(input_buffer_.get()),
r2_(input_buffer_.get() + kKernelSize / 2) {
-#if defined(WEBRTC_CPU_DETECTION)
InitializeCPUSpecificFeatures();
- assert(convolve_proc_);
-#endif
- assert(request_frames_ > 0);
+ RTC_DCHECK(convolve_proc_);
+ RTC_DCHECK_GT(request_frames_, 0);
Flush();
- assert(block_size_ > kKernelSize);
+ RTC_DCHECK_GT(block_size_, kKernelSize);
memset(kernel_storage_.get(), 0,
sizeof(*kernel_storage_.get()) * kKernelStorageSize);
@@ -198,11 +185,11 @@ void SincResampler::UpdateRegions(bool second_load) {
block_size_ = r4_ - r2_;
// r1_ at the beginning of the buffer.
- assert(r1_ == input_buffer_.get());
+ RTC_DCHECK_EQ(r1_, input_buffer_.get());
// r1_ left of r2_, r4_ left of r3_ and size correct.
- assert(r2_ - r1_ == r4_ - r3_);
+ RTC_DCHECK_EQ(r2_ - r1_, r4_ - r3_);
// r2_ left of r3.
- assert(r2_ < r3_);
+ RTC_DCHECK_LT(r2_, r3_);
}
void SincResampler::InitializeKernel() {
@@ -221,23 +208,23 @@ void SincResampler::InitializeKernel() {
for (size_t i = 0; i < kKernelSize; ++i) {
const size_t idx = i + offset_idx * kKernelSize;
- const float pre_sinc = static_cast<float>(M_PI *
- (static_cast<int>(i) - static_cast<int>(kKernelSize / 2) -
- subsample_offset));
+ const float pre_sinc = static_cast<float>(
+ M_PI * (static_cast<int>(i) - static_cast<int>(kKernelSize / 2) -
+ subsample_offset));
kernel_pre_sinc_storage_[idx] = pre_sinc;
// Compute Blackman window, matching the offset of the sinc().
const float x = (i - subsample_offset) / kKernelSize;
const float window = static_cast<float>(kA0 - kA1 * cos(2.0 * M_PI * x) +
- kA2 * cos(4.0 * M_PI * x));
+ kA2 * cos(4.0 * M_PI * x));
kernel_window_storage_[idx] = window;
// Compute the sinc with offset, then window the sinc() function and store
// at the correct offset.
- kernel_storage_[idx] = static_cast<float>(window *
- ((pre_sinc == 0) ?
- sinc_scale_factor :
- (sin(sinc_scale_factor * pre_sinc) / pre_sinc)));
+ kernel_storage_[idx] = static_cast<float>(
+ window * ((pre_sinc == 0)
+ ? sinc_scale_factor
+ : (sin(sinc_scale_factor * pre_sinc) / pre_sinc)));
}
}
}
@@ -259,10 +246,10 @@ void SincResampler::SetRatio(double io_sample_rate_ratio) {
const float window = kernel_window_storage_[idx];
const float pre_sinc = kernel_pre_sinc_storage_[idx];
- kernel_storage_[idx] = static_cast<float>(window *
- ((pre_sinc == 0) ?
- sinc_scale_factor :
- (sin(sinc_scale_factor * pre_sinc) / pre_sinc)));
+ kernel_storage_[idx] = static_cast<float>(
+ window * ((pre_sinc == 0)
+ ? sinc_scale_factor
+ : (sin(sinc_scale_factor * pre_sinc) / pre_sinc)));
}
}
}
@@ -289,7 +276,7 @@ void SincResampler::Resample(size_t frames, float* destination) {
for (int i = static_cast<int>(
ceil((block_size_ - virtual_source_idx_) / current_io_ratio));
i > 0; --i) {
- assert(virtual_source_idx_ < block_size_);
+ RTC_DCHECK_LT(virtual_source_idx_, block_size_);
// |virtual_source_idx_| lies in between two kernel offsets so figure out
// what they are.
@@ -305,10 +292,10 @@ void SincResampler::Resample(size_t frames, float* destination) {
const float* const k1 = kernel_ptr + offset_idx * kKernelSize;
const float* const k2 = k1 + kKernelSize;
- // Ensure |k1|, |k2| are 16-byte aligned for SIMD usage. Should always be
- // true so long as kKernelSize is a multiple of 16.
- assert(0u == (reinterpret_cast<uintptr_t>(k1) & 0x0F));
- assert(0u == (reinterpret_cast<uintptr_t>(k2) & 0x0F));
+ // Ensure |k1|, |k2| are 32-byte aligned for SIMD usage. Should always be
+ // true so long as kKernelSize is a multiple of 32.
+ RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k1) % 32);
+ RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k2) % 32);
// Initialize input pointer based on quantized |virtual_source_idx_|.
const float* const input_ptr = r1_ + source_idx;
@@ -316,8 +303,8 @@ void SincResampler::Resample(size_t frames, float* destination) {
// Figure out how much to weight each kernel's "convolution".
const double kernel_interpolation_factor =
virtual_offset_idx - offset_idx;
- *destination++ = CONVOLVE_FUNC(
- input_ptr, k1, k2, kernel_interpolation_factor);
+ *destination++ =
+ convolve_proc_(input_ptr, k1, k2, kernel_interpolation_factor);
// Advance the virtual index.
virtual_source_idx_ += current_io_ratio;
@@ -356,7 +343,8 @@ void SincResampler::Flush() {
UpdateRegions(false);
}
-float SincResampler::Convolve_C(const float* input_ptr, const float* k1,
+float SincResampler::Convolve_C(const float* input_ptr,
+ const float* k1,
const float* k2,
double kernel_interpolation_factor) {
float sum1 = 0;
@@ -372,7 +360,7 @@ float SincResampler::Convolve_C(const float* input_ptr, const float* k1,
// Linearly interpolate the two "convolutions".
return static_cast<float>((1.0 - kernel_interpolation_factor) * sum1 +
- kernel_interpolation_factor * sum2);
+ kernel_interpolation_factor * sum2);
}
} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/sinc_resampler.h b/webrtc/common_audio/resampler/sinc_resampler.h
index 4ce8d37..a72a0c6 100644
--- a/webrtc/common_audio/resampler/sinc_resampler.h
+++ b/webrtc/common_audio/resampler/sinc_resampler.h
@@ -11,16 +11,17 @@
// Modified from the Chromium original here:
// src/media/base/sinc_resampler.h
-#ifndef WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
-#define WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
-
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/system_wrappers/include/aligned_malloc.h"
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
-#include "webrtc/test/testsupport/gtest_prod_util.h"
-#endif
-#include "webrtc/typedefs.h"
+#ifndef COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
+#define COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/gtest_prod_util.h"
+#include "rtc_base/memory/aligned_malloc.h"
+#include "rtc_base/system/arch.h"
namespace webrtc {
@@ -87,10 +88,8 @@ class SincResampler {
float* get_kernel_for_testing() { return kernel_storage_.get(); }
private:
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, Convolve);
FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, ConvolveBenchmark);
-#endif
void InitializeKernel();
void UpdateRegions(bool second_load);
@@ -104,14 +103,22 @@ class SincResampler {
// Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are
// linearly interpolated using |kernel_interpolation_factor|. On x86 and ARM
// the underlying implementation is chosen at run time.
- static float Convolve_C(const float* input_ptr, const float* k1,
- const float* k2, double kernel_interpolation_factor);
+ static float Convolve_C(const float* input_ptr,
+ const float* k1,
+ const float* k2,
+ double kernel_interpolation_factor);
#if defined(WEBRTC_ARCH_X86_FAMILY)
- static float Convolve_SSE(const float* input_ptr, const float* k1,
+ static float Convolve_SSE(const float* input_ptr,
+ const float* k1,
const float* k2,
double kernel_interpolation_factor);
-#elif defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
- static float Convolve_NEON(const float* input_ptr, const float* k1,
+ static float Convolve_AVX2(const float* input_ptr,
+ const float* k1,
+ const float* k2,
+ double kernel_interpolation_factor);
+#elif defined(WEBRTC_HAS_NEON)
+ static float Convolve_NEON(const float* input_ptr,
+ const float* k1,
const float* k2,
double kernel_interpolation_factor);
#endif
@@ -141,22 +148,22 @@ class SincResampler {
// Contains kKernelOffsetCount kernels back-to-back, each of size kKernelSize.
// The kernel offsets are sub-sample shifts of a windowed sinc shifted from
// 0.0 to 1.0 sample.
- rtc::scoped_ptr<float[], AlignedFreeDeleter> kernel_storage_;
- rtc::scoped_ptr<float[], AlignedFreeDeleter> kernel_pre_sinc_storage_;
- rtc::scoped_ptr<float[], AlignedFreeDeleter> kernel_window_storage_;
+ std::unique_ptr<float[], AlignedFreeDeleter> kernel_storage_;
+ std::unique_ptr<float[], AlignedFreeDeleter> kernel_pre_sinc_storage_;
+ std::unique_ptr<float[], AlignedFreeDeleter> kernel_window_storage_;
// Data from the source is copied into this buffer for each processing pass.
- rtc::scoped_ptr<float[], AlignedFreeDeleter> input_buffer_;
-
- // Stores the runtime selection of which Convolve function to use.
- // TODO(ajm): Move to using a global static which must only be initialized
- // once by the user. We're not doing this initially, because we don't have
- // e.g. a LazyInstance helper in webrtc.
-#if defined(WEBRTC_CPU_DETECTION)
- typedef float (*ConvolveProc)(const float*, const float*, const float*,
+ std::unique_ptr<float[], AlignedFreeDeleter> input_buffer_;
+
+// Stores the runtime selection of which Convolve function to use.
+// TODO(ajm): Move to using a global static which must only be initialized
+// once by the user. We're not doing this initially, because we don't have
+// e.g. a LazyInstance helper in webrtc.
+ typedef float (*ConvolveProc)(const float*,
+ const float*,
+ const float*,
double);
ConvolveProc convolve_proc_;
-#endif
// Pointers to the various regions inside |input_buffer_|. See the diagram at
// the top of the .cc file for more information.
@@ -171,4 +178,4 @@ class SincResampler {
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
+#endif // COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
diff --git a/webrtc/common_audio/resampler/sinc_resampler_avx2.cc b/webrtc/common_audio/resampler/sinc_resampler_avx2.cc
new file mode 100644
index 0000000..3eb5d4a
--- /dev/null
+++ b/webrtc/common_audio/resampler/sinc_resampler_avx2.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <immintrin.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <xmmintrin.h>
+
+#include "common_audio/resampler/sinc_resampler.h"
+
+namespace webrtc {
+
+float SincResampler::Convolve_AVX2(const float* input_ptr,
+ const float* k1,
+ const float* k2,
+ double kernel_interpolation_factor) {
+ __m256 m_input;
+ __m256 m_sums1 = _mm256_setzero_ps();
+ __m256 m_sums2 = _mm256_setzero_ps();
+
+ // Based on |input_ptr| alignment, we need to use loadu or load. Unrolling
+ // these loops has not been tested or benchmarked.
+ bool aligned_input = (reinterpret_cast<uintptr_t>(input_ptr) & 0x1F) == 0;
+ if (!aligned_input) {
+ for (size_t i = 0; i < kKernelSize; i += 8) {
+ m_input = _mm256_loadu_ps(input_ptr + i);
+ m_sums1 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k1 + i), m_sums1);
+ m_sums2 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k2 + i), m_sums2);
+ }
+ } else {
+ for (size_t i = 0; i < kKernelSize; i += 8) {
+ m_input = _mm256_load_ps(input_ptr + i);
+ m_sums1 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k1 + i), m_sums1);
+ m_sums2 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k2 + i), m_sums2);
+ }
+ }
+
+ // Linearly interpolate the two "convolutions".
+ __m128 m128_sums1 = _mm_add_ps(_mm256_extractf128_ps(m_sums1, 0),
+ _mm256_extractf128_ps(m_sums1, 1));
+ __m128 m128_sums2 = _mm_add_ps(_mm256_extractf128_ps(m_sums2, 0),
+ _mm256_extractf128_ps(m_sums2, 1));
+ m128_sums1 = _mm_mul_ps(
+ m128_sums1,
+ _mm_set_ps1(static_cast<float>(1.0 - kernel_interpolation_factor)));
+ m128_sums2 = _mm_mul_ps(
+ m128_sums2, _mm_set_ps1(static_cast<float>(kernel_interpolation_factor)));
+ m128_sums1 = _mm_add_ps(m128_sums1, m128_sums2);
+
+ // Sum components together.
+ float result;
+ m128_sums2 = _mm_add_ps(_mm_movehl_ps(m128_sums1, m128_sums1), m128_sums1);
+ _mm_store_ss(&result, _mm_add_ss(m128_sums2,
+ _mm_shuffle_ps(m128_sums2, m128_sums2, 1)));
+
+ return result;
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/sinc_resampler_neon.cc b/webrtc/common_audio/resampler/sinc_resampler_neon.cc
index e909a6c..9ee918b 100644
--- a/webrtc/common_audio/resampler/sinc_resampler_neon.cc
+++ b/webrtc/common_audio/resampler/sinc_resampler_neon.cc
@@ -11,13 +11,14 @@
// Modified from the Chromium original:
// src/media/base/sinc_resampler.cc
-#include "webrtc/common_audio/resampler/sinc_resampler.h"
-
#include <arm_neon.h>
+#include "common_audio/resampler/sinc_resampler.h"
+
namespace webrtc {
-float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1,
+float SincResampler::Convolve_NEON(const float* input_ptr,
+ const float* k1,
const float* k2,
double kernel_interpolation_factor) {
float32x4_t m_input;
@@ -25,7 +26,7 @@ float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1,
float32x4_t m_sums2 = vmovq_n_f32(0);
const float* upper = input_ptr + kKernelSize;
- for (; input_ptr < upper; ) {
+ for (; input_ptr < upper;) {
m_input = vld1q_f32(input_ptr);
input_ptr += 4;
m_sums1 = vmlaq_f32(m_sums1, m_input, vld1q_f32(k1));
diff --git a/webrtc/common_audio/resampler/sinc_resampler_sse.cc b/webrtc/common_audio/resampler/sinc_resampler_sse.cc
index 9e3953f..f6a24d0 100644
--- a/webrtc/common_audio/resampler/sinc_resampler_sse.cc
+++ b/webrtc/common_audio/resampler/sinc_resampler_sse.cc
@@ -11,13 +11,16 @@
// Modified from the Chromium original:
// src/media/base/simd/sinc_resampler_sse.cc
-#include "webrtc/common_audio/resampler/sinc_resampler.h"
-
+#include <stddef.h>
+#include <stdint.h>
#include <xmmintrin.h>
+#include "common_audio/resampler/sinc_resampler.h"
+
namespace webrtc {
-float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1,
+float SincResampler::Convolve_SSE(const float* input_ptr,
+ const float* k1,
const float* k2,
double kernel_interpolation_factor) {
__m128 m_input;
@@ -41,17 +44,18 @@ float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1,
}
// Linearly interpolate the two "convolutions".
- m_sums1 = _mm_mul_ps(m_sums1, _mm_set_ps1(
- static_cast<float>(1.0 - kernel_interpolation_factor)));
- m_sums2 = _mm_mul_ps(m_sums2, _mm_set_ps1(
- static_cast<float>(kernel_interpolation_factor)));
+ m_sums1 = _mm_mul_ps(
+ m_sums1,
+ _mm_set_ps1(static_cast<float>(1.0 - kernel_interpolation_factor)));
+ m_sums2 = _mm_mul_ps(
+ m_sums2, _mm_set_ps1(static_cast<float>(kernel_interpolation_factor)));
m_sums1 = _mm_add_ps(m_sums1, m_sums2);
// Sum components together.
float result;
m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1);
- _mm_store_ss(&result, _mm_add_ss(m_sums2, _mm_shuffle_ps(
- m_sums2, m_sums2, 1)));
+ _mm_store_ss(&result,
+ _mm_add_ss(m_sums2, _mm_shuffle_ps(m_sums2, m_sums2, 1)));
return result;
}
diff --git a/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc b/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc
index 5d21568..2afdd1b 100644
--- a/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc
+++ b/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc
@@ -11,7 +11,7 @@
// MSVC++ requires this to be set before any other includes to get M_PI.
#define _USE_MATH_DEFINES
-#include "webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h"
+#include "common_audio/resampler/sinusoidal_linear_chirp_source.h"
#include <math.h>
@@ -43,8 +43,7 @@ void SinusoidalLinearChirpSource::Run(size_t frames, float* destination) {
} else {
// Sinusoidal linear chirp.
double t = (current_index_ - delay_samples_) / sample_rate_;
- destination[i] =
- sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t));
+ destination[i] = sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t));
}
}
}
@@ -52,7 +51,7 @@ void SinusoidalLinearChirpSource::Run(size_t frames, float* destination) {
double SinusoidalLinearChirpSource::Frequency(size_t position) {
return kMinFrequency + (position - delay_samples_) *
- (max_frequency_ - kMinFrequency) / total_samples_;
+ (max_frequency_ - kMinFrequency) / total_samples_;
}
} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h b/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h
index 1807f86..81f6a24 100644
--- a/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h
+++ b/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h
@@ -11,11 +11,11 @@
// Modified from the Chromium original here:
// src/media/base/sinc_resampler_unittest.cc
-#ifndef WEBRTC_COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
-#define WEBRTC_COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
+#ifndef COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
+#define COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/common_audio/resampler/sinc_resampler.h"
+#include "common_audio/resampler/sinc_resampler.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
@@ -26,19 +26,19 @@ class SinusoidalLinearChirpSource : public SincResamplerCallback {
public:
// |delay_samples| can be used to insert a fractional sample delay into the
// source. It will produce zeros until non-negative time is reached.
- SinusoidalLinearChirpSource(int sample_rate, size_t samples,
- double max_frequency, double delay_samples);
+ SinusoidalLinearChirpSource(int sample_rate,
+ size_t samples,
+ double max_frequency,
+ double delay_samples);
- virtual ~SinusoidalLinearChirpSource() {}
+ ~SinusoidalLinearChirpSource() override {}
void Run(size_t frames, float* destination) override;
double Frequency(size_t position);
private:
- enum {
- kMinFrequency = 5
- };
+ enum { kMinFrequency = 5 };
int sample_rate_;
size_t total_samples_;
@@ -52,4 +52,4 @@ class SinusoidalLinearChirpSource : public SincResamplerCallback {
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
+#endif // COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
diff --git a/webrtc/common_audio/ring_buffer.c b/webrtc/common_audio/ring_buffer.c
index 60fb5df..a20ada5 100644
--- a/webrtc/common_audio/ring_buffer.c
+++ b/webrtc/common_audio/ring_buffer.c
@@ -11,26 +11,12 @@
// A ring buffer to hold arbitrary data. Provides no thread safety. Unless
// otherwise specified, functions return 0 on success and -1 on error.
-#include "webrtc/common_audio/ring_buffer.h"
+#include "common_audio/ring_buffer.h"
#include <stddef.h> // size_t
#include <stdlib.h>
#include <string.h>
-enum Wrap {
- SAME_WRAP,
- DIFF_WRAP
-};
-
-struct RingBuffer {
- size_t read_pos;
- size_t write_pos;
- size_t element_count;
- size_t element_size;
- enum Wrap rw_wrap;
- char* data;
-};
-
// Get address of region(s) from which we can read data.
// If the region is contiguous, |data_ptr_bytes_2| will be zero.
// If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second
@@ -132,7 +118,6 @@ size_t WebRtc_ReadBuffer(RingBuffer* self,
&buf_ptr_bytes_1,
&buf_ptr_2,
&buf_ptr_bytes_2);
-
if (buf_ptr_bytes_2 > 0) {
// We have a wrap around when reading the buffer. Copy the buffer data to
// |data| and point to it.
@@ -145,7 +130,7 @@ size_t WebRtc_ReadBuffer(RingBuffer* self,
}
if (data_ptr) {
// |buf_ptr_1| == |data| in the case of a wrap.
- *data_ptr = buf_ptr_1;
+ *data_ptr = read_count == 0 ? NULL : buf_ptr_1;
}
// Update read position
diff --git a/webrtc/common_audio/ring_buffer.h b/webrtc/common_audio/ring_buffer.h
index 4125c48..bcc40e1 100644
--- a/webrtc/common_audio/ring_buffer.h
+++ b/webrtc/common_audio/ring_buffer.h
@@ -11,8 +11,10 @@
// A ring buffer to hold arbitrary data. Provides no thread safety. Unless
// otherwise specified, functions return 0 on success and -1 on error.
-#ifndef WEBRTC_COMMON_AUDIO_RING_BUFFER_H_
-#define WEBRTC_COMMON_AUDIO_RING_BUFFER_H_
+#ifndef COMMON_AUDIO_RING_BUFFER_H_
+#define COMMON_AUDIO_RING_BUFFER_H_
+
+// TODO(alessiob): Used by AEC, AECm and AudioRingBuffer. Remove when possible.
#ifdef __cplusplus
extern "C" {
@@ -20,21 +22,31 @@ extern "C" {
#include <stddef.h> // size_t
-typedef struct RingBuffer RingBuffer;
+enum Wrap { SAME_WRAP, DIFF_WRAP };
+
+typedef struct RingBuffer {
+ size_t read_pos;
+ size_t write_pos;
+ size_t element_count;
+ size_t element_size;
+ enum Wrap rw_wrap;
+ char* data;
+} RingBuffer;
-// Creates and initializes the buffer. Returns NULL on failure.
+// Creates and initializes the buffer. Returns null on failure.
RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size);
void WebRtc_InitBuffer(RingBuffer* handle);
void WebRtc_FreeBuffer(void* handle);
-// Reads data from the buffer. The |data_ptr| will point to the address where
-// it is located. If all |element_count| data are feasible to read without
-// buffer wrap around |data_ptr| will point to the location in the buffer.
-// Otherwise, the data will be copied to |data| (memory allocation done by the
-// user) and |data_ptr| points to the address of |data|. |data_ptr| is only
-// guaranteed to be valid until the next call to WebRtc_WriteBuffer().
+// Reads data from the buffer. Returns the number of elements that were read.
+// The |data_ptr| will point to the address where the read data is located.
+// If no data can be read, |data_ptr| is set to |NULL|. If all data can be read
+// without buffer wrap around then |data_ptr| will point to the location in the
+// buffer. Otherwise, the data will be copied to |data| (memory allocation done
+// by the user) and |data_ptr| points to the address of |data|. |data_ptr| is
+// only guaranteed to be valid until the next call to WebRtc_WriteBuffer().
//
-// To force a copying to |data|, pass a NULL |data_ptr|.
+// To force a copying to |data|, pass a null |data_ptr|.
//
// Returns number of elements read.
size_t WebRtc_ReadBuffer(RingBuffer* handle,
@@ -43,7 +55,8 @@ size_t WebRtc_ReadBuffer(RingBuffer* handle,
size_t element_count);
// Writes |data| to buffer and returns the number of elements written.
-size_t WebRtc_WriteBuffer(RingBuffer* handle, const void* data,
+size_t WebRtc_WriteBuffer(RingBuffer* handle,
+ const void* data,
size_t element_count);
// Moves the buffer read position and returns the number of elements moved.
@@ -63,4 +76,4 @@ size_t WebRtc_available_write(const RingBuffer* handle);
}
#endif
-#endif // WEBRTC_COMMON_AUDIO_RING_BUFFER_H_
+#endif // COMMON_AUDIO_RING_BUFFER_H_
diff --git a/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c b/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c
index f99dd62..a3ec24f 100644
--- a/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c
+++ b/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
void WebRtcSpl_AutoCorrToReflCoef(const int32_t *R, int use_order, int16_t *K)
{
diff --git a/webrtc/common_audio/signal_processing/auto_correlation.c b/webrtc/common_audio/signal_processing/auto_correlation.c
index fda4fff..1455820 100644
--- a/webrtc/common_audio/signal_processing/auto_correlation.c
+++ b/webrtc/common_audio/signal_processing/auto_correlation.c
@@ -8,9 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
-#include <assert.h>
+#include "rtc_base/checks.h"
size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector,
size_t in_vector_length,
@@ -22,7 +22,7 @@ size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector,
int16_t smax = 0;
int scaling = 0;
- assert(order <= in_vector_length);
+ RTC_DCHECK_LE(order, in_vector_length);
// Find the maximum absolute value of the samples.
smax = WebRtcSpl_MaxAbsValueW16(in_vector, in_vector_length);
diff --git a/webrtc/common_audio/signal_processing/complex_bit_reverse.c b/webrtc/common_audio/signal_processing/complex_bit_reverse.c
index c8bd2dc..1c82cff 100644
--- a/webrtc/common_audio/signal_processing/complex_bit_reverse.c
+++ b/webrtc/common_audio/signal_processing/complex_bit_reverse.c
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
/* Tables for data buffer indexes that are bit reversed and thus need to be
* swapped. Note that, index_7[{0, 2, 4, ...}] are for the left side of the swap
diff --git a/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S b/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S
index 93de99f..be8e181 100644
--- a/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S
+++ b/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S
@@ -12,7 +12,7 @@
@ for ARMv5 platforms.
@ Reference C code is in file complex_bit_reverse.c. Bit-exact.
-#include "webrtc/system_wrappers/include/asm_defines.h"
+#include "rtc_base/system/asm_defines.h"
GLOBAL_FUNCTION WebRtcSpl_ComplexBitReverse
.align 2
diff --git a/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c b/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
index 583fe4f..9007b19 100644
--- a/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
+++ b/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
@@ -9,7 +9,7 @@
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
static int16_t coefTable_7[] = {
4, 256, 8, 128, 12, 384, 16, 64,
diff --git a/webrtc/common_audio/signal_processing/complex_fft.c b/webrtc/common_audio/signal_processing/complex_fft.c
index 97ebacc..ddc9a97 100644
--- a/webrtc/common_audio/signal_processing/complex_fft.c
+++ b/webrtc/common_audio/signal_processing/complex_fft.c
@@ -15,8 +15,9 @@
*
*/
-#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/complex_fft_tables.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/system/arch.h"
#define CFFTSFT 14
#define CFFTRND 1
@@ -134,8 +135,8 @@ int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode)
tr32 >>= 15 - CFFTSFT;
ti32 >>= 15 - CFFTSFT;
- qr32 = ((int32_t)frfi[2 * i]) << CFFTSFT;
- qi32 = ((int32_t)frfi[2 * i + 1]) << CFFTSFT;
+ qr32 = ((int32_t)frfi[2 * i]) * (1 << CFFTSFT);
+ qi32 = ((int32_t)frfi[2 * i + 1]) * (1 << CFFTSFT);
frfi[2 * j] = (int16_t)(
(qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT));
@@ -166,7 +167,7 @@ int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
/* The 1024-value is a constant given from the size of kSinTable1024[],
* and should not be changed depending on the input parameter 'stages'
*/
- n = 1 << stages;
+ n = ((size_t)1) << stages;
if (n > 1024)
return -1;
@@ -276,8 +277,8 @@ int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
tr32 >>= 15 - CIFFTSFT;
ti32 >>= 15 - CIFFTSFT;
- qr32 = ((int32_t)frfi[2 * i]) << CIFFTSFT;
- qi32 = ((int32_t)frfi[2 * i + 1]) << CIFFTSFT;
+ qr32 = ((int32_t)frfi[2 * i]) * (1 << CIFFTSFT);
+ qi32 = ((int32_t)frfi[2 * i + 1]) * (1 << CIFFTSFT);
frfi[2 * j] = (int16_t)(
(qr32 - tr32 + round2) >> (shift + CIFFTSFT));
diff --git a/webrtc/common_audio/signal_processing/complex_fft_mips.c b/webrtc/common_audio/signal_processing/complex_fft_mips.c
index 34c4f23..27071f8 100644
--- a/webrtc/common_audio/signal_processing/complex_fft_mips.c
+++ b/webrtc/common_audio/signal_processing/complex_fft_mips.c
@@ -9,8 +9,8 @@
*/
-#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/complex_fft_tables.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
#define CFFTSFT 14
#define CFFTRND 1
diff --git a/webrtc/common_audio/signal_processing/complex_fft_tables.h b/webrtc/common_audio/signal_processing/complex_fft_tables.h
index ca7b7fe..90fac07 100644
--- a/webrtc/common_audio/signal_processing/complex_fft_tables.h
+++ b/webrtc/common_audio/signal_processing/complex_fft_tables.h
@@ -8,141 +8,125 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
+#define COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
-#ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
-#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
-
-#include "webrtc/typedefs.h"
+#include <stdint.h>
static const int16_t kSinTable1024[] = {
- 0, 201, 402, 603, 804, 1005, 1206, 1406,
- 1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011,
- 3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608,
- 4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195,
- 6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766,
- 7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319,
- 9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849,
- 11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353,
- 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827,
- 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268,
- 15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672,
- 16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036,
- 18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357,
- 19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631,
- 20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855,
- 22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027,
- 23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143,
- 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201,
- 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198,
- 26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132,
- 27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001,
- 28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802,
- 28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534,
- 29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195,
- 30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783,
- 30851, 30918, 30984, 31049, 31113, 31175, 31236, 31297,
- 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735,
- 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097,
- 32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382,
- 32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588,
- 32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717,
- 32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766,
- 32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736,
- 32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628,
- 32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441,
- 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176,
- 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833,
- 31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413,
- 31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918,
- 30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349,
- 30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706,
- 29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992,
- 28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208,
- 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355,
- 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437,
- 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456,
- 25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413,
- 24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311,
- 23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153,
- 22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942,
- 20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680,
- 19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371,
- 18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017,
- 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623,
- 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191,
- 14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724,
- 12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227,
- 11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703,
- 9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156,
- 7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589,
- 6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006,
- 4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411,
- 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808,
- 1607, 1406, 1206, 1005, 804, 603, 402, 201,
- 0, -201, -402, -603, -804, -1005, -1206, -1406,
- -1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011,
- -3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608,
- -4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195,
- -6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766,
- -7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319,
- -9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849,
- -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
- -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
- -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
- -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
- -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
- -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
- -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
- -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
- -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
- -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
- -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
- -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
- -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
- -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
- -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
- -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
- -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
- -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
- -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
- -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
- -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
- -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
- -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
- -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
- -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
- -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736,
- -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
- -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
- -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
- -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833,
- -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
- -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918,
- -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
- -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706,
- -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
- -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208,
- -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
- -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437,
- -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
- -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413,
- -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
- -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153,
- -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
- -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680,
- -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
- -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
- -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
- -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191,
- -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
- -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227,
- -11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703,
- -9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156,
- -7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589,
- -6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006,
- -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
- -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808,
- -1607, -1406, -1206, -1005, -804, -603, -402, -201
-};
+ 0, 201, 402, 603, 804, 1005, 1206, 1406, 1607,
+ 1808, 2009, 2209, 2410, 2610, 2811, 3011, 3211, 3411,
+ 3611, 3811, 4011, 4210, 4409, 4608, 4807, 5006, 5205,
+ 5403, 5601, 5799, 5997, 6195, 6392, 6589, 6786, 6982,
+ 7179, 7375, 7571, 7766, 7961, 8156, 8351, 8545, 8739,
+ 8932, 9126, 9319, 9511, 9703, 9895, 10087, 10278, 10469,
+ 10659, 10849, 11038, 11227, 11416, 11604, 11792, 11980, 12166,
+ 12353, 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827,
+ 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, 15446,
+ 15623, 15799, 15975, 16150, 16325, 16499, 16672, 16845, 17017,
+ 17189, 17360, 17530, 17699, 17868, 18036, 18204, 18371, 18537,
+ 18702, 18867, 19031, 19194, 19357, 19519, 19680, 19840, 20000,
+ 20159, 20317, 20474, 20631, 20787, 20942, 21096, 21249, 21402,
+ 21554, 21705, 21855, 22004, 22153, 22301, 22448, 22594, 22739,
+ 22883, 23027, 23169, 23311, 23452, 23592, 23731, 23869, 24006,
+ 24143, 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201,
+ 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, 26318,
+ 26437, 26556, 26673, 26789, 26905, 27019, 27132, 27244, 27355,
+ 27466, 27575, 27683, 27790, 27896, 28001, 28105, 28208, 28309,
+ 28410, 28510, 28608, 28706, 28802, 28897, 28992, 29085, 29177,
+ 29268, 29358, 29446, 29534, 29621, 29706, 29790, 29873, 29955,
+ 30036, 30116, 30195, 30272, 30349, 30424, 30498, 30571, 30643,
+ 30713, 30783, 30851, 30918, 30984, 31049, 31113, 31175, 31236,
+ 31297, 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735,
+ 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, 32137,
+ 32176, 32213, 32249, 32284, 32318, 32350, 32382, 32412, 32441,
+ 32468, 32495, 32520, 32544, 32567, 32588, 32609, 32628, 32646,
+ 32662, 32678, 32692, 32705, 32717, 32727, 32736, 32744, 32751,
+ 32757, 32761, 32764, 32766, 32767, 32766, 32764, 32761, 32757,
+ 32751, 32744, 32736, 32727, 32717, 32705, 32692, 32678, 32662,
+ 32646, 32628, 32609, 32588, 32567, 32544, 32520, 32495, 32468,
+ 32441, 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176,
+ 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, 31785,
+ 31735, 31684, 31633, 31580, 31525, 31470, 31413, 31356, 31297,
+ 31236, 31175, 31113, 31049, 30984, 30918, 30851, 30783, 30713,
+ 30643, 30571, 30498, 30424, 30349, 30272, 30195, 30116, 30036,
+ 29955, 29873, 29790, 29706, 29621, 29534, 29446, 29358, 29268,
+ 29177, 29085, 28992, 28897, 28802, 28706, 28608, 28510, 28410,
+ 28309, 28208, 28105, 28001, 27896, 27790, 27683, 27575, 27466,
+ 27355, 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437,
+ 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, 25329,
+ 25201, 25072, 24942, 24811, 24679, 24546, 24413, 24278, 24143,
+ 24006, 23869, 23731, 23592, 23452, 23311, 23169, 23027, 22883,
+ 22739, 22594, 22448, 22301, 22153, 22004, 21855, 21705, 21554,
+ 21402, 21249, 21096, 20942, 20787, 20631, 20474, 20317, 20159,
+ 20000, 19840, 19680, 19519, 19357, 19194, 19031, 18867, 18702,
+ 18537, 18371, 18204, 18036, 17868, 17699, 17530, 17360, 17189,
+ 17017, 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623,
+ 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, 14009,
+ 13827, 13645, 13462, 13278, 13094, 12909, 12724, 12539, 12353,
+ 12166, 11980, 11792, 11604, 11416, 11227, 11038, 10849, 10659,
+ 10469, 10278, 10087, 9895, 9703, 9511, 9319, 9126, 8932,
+ 8739, 8545, 8351, 8156, 7961, 7766, 7571, 7375, 7179,
+ 6982, 6786, 6589, 6392, 6195, 5997, 5799, 5601, 5403,
+ 5205, 5006, 4807, 4608, 4409, 4210, 4011, 3811, 3611,
+ 3411, 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808,
+ 1607, 1406, 1206, 1005, 804, 603, 402, 201, 0,
+ -201, -402, -603, -804, -1005, -1206, -1406, -1607, -1808,
+ -2009, -2209, -2410, -2610, -2811, -3011, -3211, -3411, -3611,
+ -3811, -4011, -4210, -4409, -4608, -4807, -5006, -5205, -5403,
+ -5601, -5799, -5997, -6195, -6392, -6589, -6786, -6982, -7179,
+ -7375, -7571, -7766, -7961, -8156, -8351, -8545, -8739, -8932,
+ -9126, -9319, -9511, -9703, -9895, -10087, -10278, -10469, -10659,
+ -10849, -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
+ -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, -14009,
+ -14191, -14372, -14552, -14732, -14911, -15090, -15268, -15446, -15623,
+ -15799, -15975, -16150, -16325, -16499, -16672, -16845, -17017, -17189,
+ -17360, -17530, -17699, -17868, -18036, -18204, -18371, -18537, -18702,
+ -18867, -19031, -19194, -19357, -19519, -19680, -19840, -20000, -20159,
+ -20317, -20474, -20631, -20787, -20942, -21096, -21249, -21402, -21554,
+ -21705, -21855, -22004, -22153, -22301, -22448, -22594, -22739, -22883,
+ -23027, -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
+ -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, -25329,
+ -25456, -25582, -25707, -25831, -25954, -26077, -26198, -26318, -26437,
+ -26556, -26673, -26789, -26905, -27019, -27132, -27244, -27355, -27466,
+ -27575, -27683, -27790, -27896, -28001, -28105, -28208, -28309, -28410,
+ -28510, -28608, -28706, -28802, -28897, -28992, -29085, -29177, -29268,
+ -29358, -29446, -29534, -29621, -29706, -29790, -29873, -29955, -30036,
+ -30116, -30195, -30272, -30349, -30424, -30498, -30571, -30643, -30713,
+ -30783, -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
+ -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, -31785,
+ -31833, -31880, -31926, -31970, -32014, -32056, -32097, -32137, -32176,
+ -32213, -32249, -32284, -32318, -32350, -32382, -32412, -32441, -32468,
+ -32495, -32520, -32544, -32567, -32588, -32609, -32628, -32646, -32662,
+ -32678, -32692, -32705, -32717, -32727, -32736, -32744, -32751, -32757,
+ -32761, -32764, -32766, -32767, -32766, -32764, -32761, -32757, -32751,
+ -32744, -32736, -32727, -32717, -32705, -32692, -32678, -32662, -32646,
+ -32628, -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
+ -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, -32137,
+ -32097, -32056, -32014, -31970, -31926, -31880, -31833, -31785, -31735,
+ -31684, -31633, -31580, -31525, -31470, -31413, -31356, -31297, -31236,
+ -31175, -31113, -31049, -30984, -30918, -30851, -30783, -30713, -30643,
+ -30571, -30498, -30424, -30349, -30272, -30195, -30116, -30036, -29955,
+ -29873, -29790, -29706, -29621, -29534, -29446, -29358, -29268, -29177,
+ -29085, -28992, -28897, -28802, -28706, -28608, -28510, -28410, -28309,
+ -28208, -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
+ -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, -26318,
+ -26198, -26077, -25954, -25831, -25707, -25582, -25456, -25329, -25201,
+ -25072, -24942, -24811, -24679, -24546, -24413, -24278, -24143, -24006,
+ -23869, -23731, -23592, -23452, -23311, -23169, -23027, -22883, -22739,
+ -22594, -22448, -22301, -22153, -22004, -21855, -21705, -21554, -21402,
+ -21249, -21096, -20942, -20787, -20631, -20474, -20317, -20159, -20000,
+ -19840, -19680, -19519, -19357, -19194, -19031, -18867, -18702, -18537,
+ -18371, -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
+ -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, -15446,
+ -15268, -15090, -14911, -14732, -14552, -14372, -14191, -14009, -13827,
+ -13645, -13462, -13278, -13094, -12909, -12724, -12539, -12353, -12166,
+ -11980, -11792, -11604, -11416, -11227, -11038, -10849, -10659, -10469,
+ -10278, -10087, -9895, -9703, -9511, -9319, -9126, -8932, -8739,
+ -8545, -8351, -8156, -7961, -7766, -7571, -7375, -7179, -6982,
+ -6786, -6589, -6392, -6195, -5997, -5799, -5601, -5403, -5205,
+ -5006, -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
+ -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, -1607,
+ -1406, -1206, -1005, -804, -603, -402, -201};
-#endif // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
+#endif // COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
diff --git a/webrtc/common_audio/signal_processing/copy_set_operations.c b/webrtc/common_audio/signal_processing/copy_set_operations.c
index 9d7cf47..ae709d4 100644
--- a/webrtc/common_audio/signal_processing/copy_set_operations.c
+++ b/webrtc/common_audio/signal_processing/copy_set_operations.c
@@ -23,7 +23,7 @@
*/
#include <string.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
void WebRtcSpl_MemSetW16(int16_t *ptr, int16_t set_value, size_t length)
diff --git a/webrtc/common_audio/signal_processing/cross_correlation.c b/webrtc/common_audio/signal_processing/cross_correlation.c
index d7c9f2b..c6267c9 100644
--- a/webrtc/common_audio/signal_processing/cross_correlation.c
+++ b/webrtc/common_audio/signal_processing/cross_correlation.c
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
/* C version of WebRtcSpl_CrossCorrelation() for generic platforms. */
void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation,
diff --git a/webrtc/common_audio/signal_processing/cross_correlation_mips.c b/webrtc/common_audio/signal_processing/cross_correlation_mips.c
index b236402..c395101 100644
--- a/webrtc/common_audio/signal_processing/cross_correlation_mips.c
+++ b/webrtc/common_audio/signal_processing/cross_correlation_mips.c
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation,
const int16_t* seq1,
diff --git a/webrtc/common_audio/signal_processing/cross_correlation_neon.c b/webrtc/common_audio/signal_processing/cross_correlation_neon.c
index 918b671..f2afbdf 100644
--- a/webrtc/common_audio/signal_processing/cross_correlation_neon.c
+++ b/webrtc/common_audio/signal_processing/cross_correlation_neon.c
@@ -8,7 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/system/arch.h"
#include <arm_neon.h>
diff --git a/webrtc/common_audio/signal_processing/division_operations.c b/webrtc/common_audio/signal_processing/division_operations.c
index eaa06a1..c6195e7 100644
--- a/webrtc/common_audio/signal_processing/division_operations.c
+++ b/webrtc/common_audio/signal_processing/division_operations.c
@@ -21,7 +21,8 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/sanitizer.h"
uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den)
{
@@ -97,7 +98,8 @@ int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den)
return div;
}
-int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
+int32_t RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486
+WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
{
int16_t approx, tmp_hi, tmp_low, num_hi, num_low;
int32_t tmpW32;
@@ -110,6 +112,7 @@ int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
// tmpW32 = den * approx
tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
+ // UBSan: 2147483647 - -2 cannot be represented in type 'int'
// Store tmpW32 in hi and low format
tmp_hi = (int16_t)(tmpW32 >> 16);
diff --git a/webrtc/common_audio/signal_processing/dot_product_with_scale.c b/webrtc/common_audio/signal_processing/dot_product_with_scale.cc
index 1302d62..00799da 100644
--- a/webrtc/common_audio/signal_processing/dot_product_with_scale.c
+++ b/webrtc/common_audio/signal_processing/dot_product_with_scale.cc
@@ -8,13 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/dot_product_with_scale.h"
+
+#include "rtc_base/numerics/safe_conversions.h"
int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1,
const int16_t* vector2,
size_t length,
int scaling) {
- int32_t sum = 0;
+ int64_t sum = 0;
size_t i = 0;
/* Unroll the loop to improve performance. */
@@ -28,5 +30,5 @@ int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1,
sum += (vector1[i] * vector2[i]) >> scaling;
}
- return sum;
+ return rtc::saturated_cast<int32_t>(sum);
}
diff --git a/webrtc/common_audio/signal_processing/dot_product_with_scale.h b/webrtc/common_audio/signal_processing/dot_product_with_scale.h
new file mode 100644
index 0000000..bb892d4
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/dot_product_with_scale.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 COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_
+#define COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Calculates the dot product between two (int16_t) vectors.
+//
+// Input:
+// - vector1 : Vector 1
+// - vector2 : Vector 2
+// - vector_length : Number of samples used in the dot product
+// - scaling : The number of right bit shifts to apply on each term
+// during calculation to avoid overflow, i.e., the
+// output will be in Q(-|scaling|)
+//
+// Return value : The dot product in Q(-scaling)
+int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1,
+ const int16_t* vector2,
+ size_t length,
+ int scaling);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+#endif // COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_
diff --git a/webrtc/common_audio/signal_processing/downsample_fast.c b/webrtc/common_audio/signal_processing/downsample_fast.c
index 726a888..80fdc58 100644
--- a/webrtc/common_audio/signal_processing/downsample_fast.c
+++ b/webrtc/common_audio/signal_processing/downsample_fast.c
@@ -8,7 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+
+#include "rtc_base/checks.h"
+#include "rtc_base/sanitizer.h"
// TODO(Bjornv): Change the function parameter order to WebRTC code style.
// C version of WebRtcSpl_DownsampleFast() for generic platforms.
@@ -20,6 +23,7 @@ int WebRtcSpl_DownsampleFastC(const int16_t* data_in,
size_t coefficients_length,
int factor,
size_t delay) {
+ int16_t* const original_data_out = data_out;
size_t i = 0;
size_t j = 0;
int32_t out_s32 = 0;
@@ -31,11 +35,20 @@ int WebRtcSpl_DownsampleFastC(const int16_t* data_in,
return -1;
}
+ rtc_MsanCheckInitialized(coefficients, sizeof(coefficients[0]),
+ coefficients_length);
+
for (i = delay; i < endpos; i += factor) {
out_s32 = 2048; // Round value, 0.5 in Q12.
for (j = 0; j < coefficients_length; j++) {
- out_s32 += coefficients[j] * data_in[i - j]; // Q12.
+ // Negative overflow is permitted here, because this is
+ // auto-regressive filters, and the state for each batch run is
+ // stored in the "negative" positions of the output vector.
+ rtc_MsanCheckInitialized(&data_in[(ptrdiff_t) i - (ptrdiff_t) j],
+ sizeof(data_in[0]), 1);
+ // out_s32 is in Q12 domain.
+ out_s32 += coefficients[j] * data_in[(ptrdiff_t) i - (ptrdiff_t) j];
}
out_s32 >>= 12; // Q0.
@@ -44,5 +57,9 @@ int WebRtcSpl_DownsampleFastC(const int16_t* data_in,
*data_out++ = WebRtcSpl_SatW32ToW16(out_s32);
}
+ RTC_DCHECK_EQ(original_data_out + data_out_length, data_out);
+ rtc_MsanCheckInitialized(original_data_out, sizeof(original_data_out[0]),
+ data_out_length);
+
return 0;
}
diff --git a/webrtc/common_audio/signal_processing/downsample_fast_mips.c b/webrtc/common_audio/signal_processing/downsample_fast_mips.c
index ac39401..0f3f3a0 100644
--- a/webrtc/common_audio/signal_processing/downsample_fast_mips.c
+++ b/webrtc/common_audio/signal_processing/downsample_fast_mips.c
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// Version of WebRtcSpl_DownsampleFast() for MIPS platforms.
int WebRtcSpl_DownsampleFast_mips(const int16_t* data_in,
diff --git a/webrtc/common_audio/signal_processing/downsample_fast_neon.c b/webrtc/common_audio/signal_processing/downsample_fast_neon.c
index 58732da..36fc0c8 100644
--- a/webrtc/common_audio/signal_processing/downsample_fast_neon.c
+++ b/webrtc/common_audio/signal_processing/downsample_fast_neon.c
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
#include <arm_neon.h>
diff --git a/webrtc/common_audio/signal_processing/energy.c b/webrtc/common_audio/signal_processing/energy.c
index e83f1a6..5cce6b8 100644
--- a/webrtc/common_audio/signal_processing/energy.c
+++ b/webrtc/common_audio/signal_processing/energy.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
int32_t WebRtcSpl_Energy(int16_t* vector,
size_t vector_length,
diff --git a/webrtc/common_audio/signal_processing/filter_ar.c b/webrtc/common_audio/signal_processing/filter_ar.c
index dfbc4c2..b1f666d 100644
--- a/webrtc/common_audio/signal_processing/filter_ar.c
+++ b/webrtc/common_audio/signal_processing/filter_ar.c
@@ -15,7 +15,9 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+
+#include "rtc_base/checks.h"
size_t WebRtcSpl_FilterAR(const int16_t* a,
size_t a_length,
@@ -29,7 +31,7 @@ size_t WebRtcSpl_FilterAR(const int16_t* a,
int16_t* filtered_low,
size_t filtered_low_length)
{
- int32_t o;
+ int64_t o;
int32_t oLOW;
size_t i, j, stop;
const int16_t* x_ptr = &x[0];
@@ -40,19 +42,23 @@ size_t WebRtcSpl_FilterAR(const int16_t* a,
{
// Calculate filtered[i] and filtered_low[i]
const int16_t* a_ptr = &a[1];
- int16_t* filtered_ptr = &filtered[i - 1];
- int16_t* filtered_low_ptr = &filtered_low[i - 1];
+ // The index can become negative, but the arrays will never be indexed
+ // with it when negative. Nevertheless, the index cannot be a size_t
+ // because of this.
+ int filtered_ix = (int)i - 1;
int16_t* state_ptr = &state[state_length - 1];
int16_t* state_low_ptr = &state_low[state_length - 1];
- o = (int32_t)(*x_ptr++) << 12;
+ o = (int32_t)(*x_ptr++) * (1 << 12);
oLOW = (int32_t)0;
stop = (i < a_length) ? i + 1 : a_length;
for (j = 1; j < stop; j++)
{
- o -= *a_ptr * *filtered_ptr--;
- oLOW -= *a_ptr++ * *filtered_low_ptr--;
+ RTC_DCHECK_GE(filtered_ix, 0);
+ o -= *a_ptr * filtered[filtered_ix];
+ oLOW -= *a_ptr++ * filtered_low[filtered_ix];
+ --filtered_ix;
}
for (j = i + 1; j < a_length; j++)
{
@@ -62,8 +68,8 @@ size_t WebRtcSpl_FilterAR(const int16_t* a,
o += (oLOW >> 12);
*filteredFINAL_ptr = (int16_t)((o + (int32_t)2048) >> 12);
- *filteredFINAL_LOW_ptr++ = (int16_t)(o - ((int32_t)(*filteredFINAL_ptr++)
- << 12));
+ *filteredFINAL_LOW_ptr++ =
+ (int16_t)(o - ((int32_t)(*filteredFINAL_ptr++) * (1 << 12)));
}
// Save the filter state
@@ -81,7 +87,7 @@ size_t WebRtcSpl_FilterAR(const int16_t* a,
for (i = 0; i < x_length; i++)
{
state[state_length - x_length + i] = filtered[i];
- state[state_length - x_length + i] = filtered_low[i];
+ state_low[state_length - x_length + i] = filtered_low[i];
}
}
diff --git a/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c b/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
index 70001a0..8b8bdb1 100644
--- a/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
+++ b/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
@@ -7,9 +7,11 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <assert.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "stddef.h"
+
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// TODO(bjornv): Change the return type to report errors.
@@ -21,15 +23,18 @@ void WebRtcSpl_FilterARFastQ12(const int16_t* data_in,
size_t i = 0;
size_t j = 0;
- assert(data_length > 0);
- assert(coefficients_length > 1);
+ RTC_DCHECK_GT(data_length, 0);
+ RTC_DCHECK_GT(coefficients_length, 1);
for (i = 0; i < data_length; i++) {
- int32_t output = 0;
- int32_t sum = 0;
+ int64_t output = 0;
+ int64_t sum = 0;
for (j = coefficients_length - 1; j > 0; j--) {
- sum += coefficients[j] * data_out[i - j];
+ // Negative overflow is permitted here, because this is
+ // auto-regressive filters, and the state for each batch run is
+ // stored in the "negative" positions of the output vector.
+ sum += coefficients[j] * data_out[(ptrdiff_t) i - (ptrdiff_t) j];
}
output = coefficients[0] * data_in[i];
diff --git a/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S b/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
index f163627..60319d2 100644
--- a/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
+++ b/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
@@ -35,7 +35,7 @@
@ r11: Scratch
@ r12: &coefficients[j]
-#include "webrtc/system_wrappers/include/asm_defines.h"
+#include "rtc_base/system/asm_defines.h"
GLOBAL_FUNCTION WebRtcSpl_FilterARFastQ12
.align 2
diff --git a/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c b/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
index 0384701..b9ad30f 100644
--- a/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
+++ b/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
@@ -7,9 +7,9 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <assert.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
void WebRtcSpl_FilterARFastQ12(const int16_t* data_in,
int16_t* data_out,
@@ -25,8 +25,8 @@ void WebRtcSpl_FilterARFastQ12(const int16_t* data_in,
int min16 = 0xFFFF8000;
#endif // #if !defined(MIPS_DSP_R1_LE)
- assert(data_length > 0);
- assert(coefficients_length > 1);
+ RTC_DCHECK_GT(data_length, 0);
+ RTC_DCHECK_GT(coefficients_length, 1);
__asm __volatile (
".set push \n\t"
diff --git a/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c b/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
index f4d9a3d..329d47e 100644
--- a/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
+++ b/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
@@ -15,7 +15,9 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+
+#include "rtc_base/sanitizer.h"
void WebRtcSpl_FilterMAFastQ12(const int16_t* in_ptr,
int16_t* out_ptr,
@@ -24,13 +26,21 @@ void WebRtcSpl_FilterMAFastQ12(const int16_t* in_ptr,
size_t length)
{
size_t i, j;
+
+ rtc_MsanCheckInitialized(B, sizeof(B[0]), B_length);
+ rtc_MsanCheckInitialized(in_ptr - B_length + 1, sizeof(in_ptr[0]),
+ B_length + length - 1);
+
for (i = 0; i < length; i++)
{
int32_t o = 0;
for (j = 0; j < B_length; j++)
{
- o += B[j] * in_ptr[i - j];
+ // Negative overflow is permitted here, because this is
+ // auto-regressive filters, and the state for each batch run is
+ // stored in the "negative" positions of the output vector.
+ o += B[j] * in_ptr[(ptrdiff_t) i - (ptrdiff_t) j];
}
// If output is higher than 32768, saturate it. Same with negative side
diff --git a/webrtc/common_audio/signal_processing/get_hanning_window.c b/webrtc/common_audio/signal_processing/get_hanning_window.c
index d83ac21..8f29da8 100644
--- a/webrtc/common_audio/signal_processing/get_hanning_window.c
+++ b/webrtc/common_audio/signal_processing/get_hanning_window.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// Hanning table with 256 entries
static const int16_t kHanningTable[] = {
diff --git a/webrtc/common_audio/signal_processing/get_scaling_square.c b/webrtc/common_audio/signal_processing/get_scaling_square.c
index 82e3c8b..4eb1269 100644
--- a/webrtc/common_audio/signal_processing/get_scaling_square.c
+++ b/webrtc/common_audio/signal_processing/get_scaling_square.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
int16_t WebRtcSpl_GetScalingSquare(int16_t* in_vector,
size_t in_vector_length,
diff --git a/webrtc/common_audio/signal_processing/ilbc_specific_functions.c b/webrtc/common_audio/signal_processing/ilbc_specific_functions.c
index 301a922..cbdd3dc 100644
--- a/webrtc/common_audio/signal_processing/ilbc_specific_functions.c
+++ b/webrtc/common_audio/signal_processing/ilbc_specific_functions.c
@@ -19,7 +19,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
void WebRtcSpl_ReverseOrderMultArrayElements(int16_t *out, const int16_t *in,
const int16_t *win,
@@ -64,7 +64,7 @@ void WebRtcSpl_AddVectorsAndShift(int16_t *out, const int16_t *in1,
}
}
-void WebRtcSpl_AddAffineVectorToVector(int16_t *out, int16_t *in,
+void WebRtcSpl_AddAffineVectorToVector(int16_t *out, const int16_t *in,
int16_t gain, int32_t add_constant,
int16_t right_shifts,
size_t vector_length)
@@ -77,7 +77,7 @@ void WebRtcSpl_AddAffineVectorToVector(int16_t *out, int16_t *in,
}
}
-void WebRtcSpl_AffineTransformVector(int16_t *out, int16_t *in,
+void WebRtcSpl_AffineTransformVector(int16_t *out, const int16_t *in,
int16_t gain, int32_t add_constant,
int16_t right_shifts, size_t vector_length)
{
diff --git a/webrtc/common_audio/signal_processing/include/real_fft.h b/webrtc/common_audio/signal_processing/include/real_fft.h
index e7942f0..8445066 100644
--- a/webrtc/common_audio/signal_processing/include/real_fft.h
+++ b/webrtc/common_audio/signal_processing/include/real_fft.h
@@ -8,15 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
-#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
+#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
+#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
-#include "webrtc/typedefs.h"
+#include <stdint.h>
// For ComplexFFT(), the maximum fft order is 10;
-// for OpenMax FFT in ARM, it is 12;
// WebRTC APM uses orders of only 7 and 8.
-enum {kMaxFFTOrder = 10};
+enum { kMaxFFTOrder = 10 };
struct RealFFT;
@@ -57,7 +56,7 @@ void WebRtcSpl_FreeRealFFT(struct RealFFT* self);
//
// Return Value:
// 0 - FFT calculation is successful.
-// -1 - Error with bad arguments (NULL pointers).
+// -1 - Error with bad arguments (null pointers).
int WebRtcSpl_RealForwardFFT(struct RealFFT* self,
const int16_t* real_data_in,
int16_t* complex_data_out);
@@ -85,7 +84,7 @@ int WebRtcSpl_RealForwardFFT(struct RealFFT* self,
// 0 or a positive number - a value that the elements in the |real_data_out|
// should be shifted left with in order to get
// correct physical values.
-// -1 - Error with bad arguments (NULL pointers).
+// -1 - Error with bad arguments (null pointers).
int WebRtcSpl_RealInverseFFT(struct RealFFT* self,
const int16_t* complex_data_in,
int16_t* real_data_out);
@@ -94,4 +93,4 @@ int WebRtcSpl_RealInverseFFT(struct RealFFT* self,
}
#endif
-#endif // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
+#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
diff --git a/webrtc/common_audio/signal_processing/include/signal_processing_library.h b/webrtc/common_audio/signal_processing/include/signal_processing_library.h
index 2e96883..4ad92c4 100644
--- a/webrtc/common_audio/signal_processing/include/signal_processing_library.h
+++ b/webrtc/common_audio/signal_processing/include/signal_processing_library.h
@@ -8,91 +8,84 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
/*
- * This header file includes all of the fix point signal processing library (SPL) function
- * descriptions and declarations.
- * For specific function calls, see bottom of file.
+ * This header file includes all of the fix point signal processing library
+ * (SPL) function descriptions and declarations. For specific function calls,
+ * see bottom of file.
*/
-#ifndef WEBRTC_SPL_SIGNAL_PROCESSING_LIBRARY_H_
-#define WEBRTC_SPL_SIGNAL_PROCESSING_LIBRARY_H_
+#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_
+#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_
#include <string.h>
-#include "webrtc/typedefs.h"
+
+#include "common_audio/signal_processing/dot_product_with_scale.h"
// Macros specific for the fixed point implementation
-#define WEBRTC_SPL_WORD16_MAX 32767
-#define WEBRTC_SPL_WORD16_MIN -32768
-#define WEBRTC_SPL_WORD32_MAX (int32_t)0x7fffffff
-#define WEBRTC_SPL_WORD32_MIN (int32_t)0x80000000
-#define WEBRTC_SPL_MAX_LPC_ORDER 14
-#define WEBRTC_SPL_MIN(A, B) (A < B ? A : B) // Get min value
-#define WEBRTC_SPL_MAX(A, B) (A > B ? A : B) // Get max value
+#define WEBRTC_SPL_WORD16_MAX 32767
+#define WEBRTC_SPL_WORD16_MIN -32768
+#define WEBRTC_SPL_WORD32_MAX (int32_t)0x7fffffff
+#define WEBRTC_SPL_WORD32_MIN (int32_t)0x80000000
+#define WEBRTC_SPL_MAX_LPC_ORDER 14
+#define WEBRTC_SPL_MIN(A, B) (A < B ? A : B) // Get min value
+#define WEBRTC_SPL_MAX(A, B) (A > B ? A : B) // Get max value
// TODO(kma/bjorn): For the next two macros, investigate how to correct the code
// for inputs of a = WEBRTC_SPL_WORD16_MIN or WEBRTC_SPL_WORD32_MIN.
-#define WEBRTC_SPL_ABS_W16(a) \
- (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a))
-#define WEBRTC_SPL_ABS_W32(a) \
- (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a))
-
-#define WEBRTC_SPL_MUL(a, b) \
- ((int32_t) ((int32_t)(a) * (int32_t)(b)))
-#define WEBRTC_SPL_UMUL(a, b) \
- ((uint32_t) ((uint32_t)(a) * (uint32_t)(b)))
-#define WEBRTC_SPL_UMUL_32_16(a, b) \
- ((uint32_t) ((uint32_t)(a) * (uint16_t)(b)))
-#define WEBRTC_SPL_MUL_16_U16(a, b) \
- ((int32_t)(int16_t)(a) * (uint16_t)(b))
+#define WEBRTC_SPL_ABS_W16(a) (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a))
+#define WEBRTC_SPL_ABS_W32(a) (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a))
+#define WEBRTC_SPL_MUL(a, b) ((int32_t)((int32_t)(a) * (int32_t)(b)))
+#define WEBRTC_SPL_UMUL(a, b) ((uint32_t)((uint32_t)(a) * (uint32_t)(b)))
+#define WEBRTC_SPL_UMUL_32_16(a, b) ((uint32_t)((uint32_t)(a) * (uint16_t)(b)))
+#define WEBRTC_SPL_MUL_16_U16(a, b) ((int32_t)(int16_t)(a) * (uint16_t)(b))
+
+// clang-format off
+// clang-format would choose some identation
+// leading to presubmit error (cpplint.py)
#ifndef WEBRTC_ARCH_ARM_V7
// For ARMv7 platforms, these are inline functions in spl_inl_armv7.h
#ifndef MIPS32_LE
// For MIPS platforms, these are inline functions in spl_inl_mips.h
-#define WEBRTC_SPL_MUL_16_16(a, b) \
- ((int32_t) (((int16_t)(a)) * ((int16_t)(b))))
+#define WEBRTC_SPL_MUL_16_16(a, b) ((int32_t)(((int16_t)(a)) * ((int16_t)(b))))
#define WEBRTC_SPL_MUL_16_32_RSFT16(a, b) \
- (WEBRTC_SPL_MUL_16_16(a, b >> 16) \
- + ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15))
+ (WEBRTC_SPL_MUL_16_16(a, b >> 16) + \
+ ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15))
#endif
#endif
-#define WEBRTC_SPL_MUL_16_32_RSFT11(a, b) \
- ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) << 5) \
- + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10))
-#define WEBRTC_SPL_MUL_16_32_RSFT14(a, b) \
- ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) << 2) \
- + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13))
-#define WEBRTC_SPL_MUL_16_32_RSFT15(a, b) \
- ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) << 1) \
- + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14))
+#define WEBRTC_SPL_MUL_16_32_RSFT11(a, b) \
+ (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 5) + \
+ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10))
+#define WEBRTC_SPL_MUL_16_32_RSFT14(a, b) \
+ (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 2) + \
+ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13))
+#define WEBRTC_SPL_MUL_16_32_RSFT15(a, b) \
+ ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 1)) + \
+ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14))
+// clang-format on
-#define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) \
- (WEBRTC_SPL_MUL_16_16(a, b) >> (c))
+#define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) (WEBRTC_SPL_MUL_16_16(a, b) >> (c))
#define WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, c) \
- ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t) \
- (((int32_t)1) << ((c) - 1)))) >> (c))
+ ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t)(((int32_t)1) << ((c)-1)))) >> (c))
// C + the 32 most significant bits of A * B
#define WEBRTC_SPL_SCALEDIFF32(A, B, C) \
- (C + (B >> 16) * A + (((uint32_t)(0x0000FFFF & B) * A) >> 16))
+ (C + (B >> 16) * A + (((uint32_t)(B & 0x0000FFFF) * A) >> 16))
-#define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b)
+#define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b)
// Shifting with negative numbers allowed
// Positive means left shift
-#define WEBRTC_SPL_SHIFT_W32(x, c) \
- (((c) >= 0) ? ((x) << (c)) : ((x) >> (-(c))))
+#define WEBRTC_SPL_SHIFT_W32(x, c) ((c) >= 0 ? (x) * (1 << (c)) : (x) >> -(c))
// Shifting with negative numbers not allowed
// We cannot do casting here due to signed/unsigned problem
-#define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c))
+#define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c))
-#define WEBRTC_SPL_RSHIFT_U32(x, c) ((uint32_t)(x) >> (c))
+#define WEBRTC_SPL_RSHIFT_U32(x, c) ((uint32_t)(x) >> (c))
-#define WEBRTC_SPL_RAND(a) \
- ((int16_t)((((int16_t)a * 18816) >> 7) & 0x00007fff))
+#define WEBRTC_SPL_RAND(a) ((int16_t)((((int16_t)a * 18816) >> 7) & 0x00007fff))
#ifdef __cplusplus
extern "C" {
@@ -102,17 +95,10 @@ extern "C" {
memcpy(v1, v2, (length) * sizeof(int16_t))
// inline functions:
-#include "webrtc/common_audio/signal_processing/include/spl_inl.h"
-
-// Initialize SPL. Currently it contains only function pointer initialization.
-// If the underlying platform is known to be ARM-Neon (WEBRTC_HAS_NEON defined),
-// the pointers will be assigned to code optimized for Neon; otherwise
-// if run-time Neon detection (WEBRTC_DETECT_NEON) is enabled, the pointers
-// will be assigned to either Neon code or generic C code; otherwise, generic C
-// code will be assigned.
-// Note that this function MUST be called in any application that uses SPL
-// functions.
-void WebRtcSpl_Init();
+#include "common_audio/signal_processing/include/spl_inl.h"
+
+// third party math functions
+#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h"
int16_t WebRtcSpl_GetScalingSquare(int16_t* in_vector,
size_t in_vector_length,
@@ -133,13 +119,10 @@ void WebRtcSpl_CopyFromEndW16(const int16_t* in_vector,
size_t in_vector_length,
size_t samples,
int16_t* out_vector);
-void WebRtcSpl_ZerosArrayW16(int16_t* vector,
- size_t vector_length);
-void WebRtcSpl_ZerosArrayW32(int32_t* vector,
- size_t vector_length);
+void WebRtcSpl_ZerosArrayW16(int16_t* vector, size_t vector_length);
+void WebRtcSpl_ZerosArrayW32(int32_t* vector, size_t vector_length);
// End: Copy and set operations.
-
// Minimum and maximum operation functions and their pointers.
// Implementation in min_max_operations.c.
@@ -151,9 +134,9 @@ void WebRtcSpl_ZerosArrayW32(int32_t* vector,
//
// Return value : Maximum absolute value in vector.
typedef int16_t (*MaxAbsValueW16)(const int16_t* vector, size_t length);
-extern MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16;
+extern const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16;
int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length);
-#if (defined WEBRTC_DETECT_NEON) || (defined WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length);
#endif
#if defined(MIPS32_LE)
@@ -168,9 +151,9 @@ int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length);
//
// Return value : Maximum absolute value in vector.
typedef int32_t (*MaxAbsValueW32)(const int32_t* vector, size_t length);
-extern MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32;
+extern const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32;
int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length);
-#if (defined WEBRTC_DETECT_NEON) || (defined WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
int32_t WebRtcSpl_MaxAbsValueW32Neon(const int32_t* vector, size_t length);
#endif
#if defined(MIPS_DSP_R1_LE)
@@ -185,9 +168,9 @@ int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length);
//
// Return value : Maximum sample value in |vector|.
typedef int16_t (*MaxValueW16)(const int16_t* vector, size_t length);
-extern MaxValueW16 WebRtcSpl_MaxValueW16;
+extern const MaxValueW16 WebRtcSpl_MaxValueW16;
int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length);
-#if (defined WEBRTC_DETECT_NEON) || (defined WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
int16_t WebRtcSpl_MaxValueW16Neon(const int16_t* vector, size_t length);
#endif
#if defined(MIPS32_LE)
@@ -202,9 +185,9 @@ int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length);
//
// Return value : Maximum sample value in |vector|.
typedef int32_t (*MaxValueW32)(const int32_t* vector, size_t length);
-extern MaxValueW32 WebRtcSpl_MaxValueW32;
+extern const MaxValueW32 WebRtcSpl_MaxValueW32;
int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length);
-#if (defined WEBRTC_DETECT_NEON) || (defined WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
int32_t WebRtcSpl_MaxValueW32Neon(const int32_t* vector, size_t length);
#endif
#if defined(MIPS32_LE)
@@ -219,9 +202,9 @@ int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length);
//
// Return value : Minimum sample value in |vector|.
typedef int16_t (*MinValueW16)(const int16_t* vector, size_t length);
-extern MinValueW16 WebRtcSpl_MinValueW16;
+extern const MinValueW16 WebRtcSpl_MinValueW16;
int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length);
-#if (defined WEBRTC_DETECT_NEON) || (defined WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
int16_t WebRtcSpl_MinValueW16Neon(const int16_t* vector, size_t length);
#endif
#if defined(MIPS32_LE)
@@ -236,9 +219,9 @@ int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length);
//
// Return value : Minimum sample value in |vector|.
typedef int32_t (*MinValueW32)(const int32_t* vector, size_t length);
-extern MinValueW32 WebRtcSpl_MinValueW32;
+extern const MinValueW32 WebRtcSpl_MinValueW32;
int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length);
-#if (defined WEBRTC_DETECT_NEON) || (defined WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length);
#endif
#if defined(MIPS32_LE)
@@ -299,7 +282,6 @@ size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length);
// End: Minimum and maximum operations.
-
// Vector scaling operations. Implementation in vector_scaling_operations.c.
// Description at bottom of file.
void WebRtcSpl_VectorBitShiftW16(int16_t* out_vector,
@@ -325,9 +307,11 @@ void WebRtcSpl_ScaleVectorWithSat(const int16_t* in_vector,
size_t vector_length,
int16_t right_shifts);
void WebRtcSpl_ScaleAndAddVectors(const int16_t* in_vector1,
- int16_t gain1, int right_shifts1,
+ int16_t gain1,
+ int right_shifts1,
const int16_t* in_vector2,
- int16_t gain2, int right_shifts2,
+ int16_t gain2,
+ int right_shifts2,
int16_t* out_vector,
size_t vector_length);
@@ -346,8 +330,8 @@ void WebRtcSpl_ScaleAndAddVectors(const int16_t* in_vector1,
//
// Output:
// - out_vector : Output vector
-// Return value : 0 if OK, -1 if (in_vector1 == NULL
-// || in_vector2 == NULL || out_vector == NULL
+// Return value : 0 if OK, -1 if (in_vector1 == null
+// || in_vector2 == null || out_vector == null
// || length <= 0 || right_shift < 0).
typedef int (*ScaleAndAddVectorsWithRound)(const int16_t* in_vector1,
int16_t in_vector1_scale,
@@ -356,7 +340,7 @@ typedef int (*ScaleAndAddVectorsWithRound)(const int16_t* in_vector1,
int right_shifts,
int16_t* out_vector,
size_t length);
-extern ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound;
+extern const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound;
int WebRtcSpl_ScaleAndAddVectorsWithRoundC(const int16_t* in_vector1,
int16_t in_vector1_scale,
const int16_t* in_vector2,
@@ -393,13 +377,13 @@ void WebRtcSpl_AddVectorsAndShift(int16_t* out_vector,
size_t vector_length,
int16_t right_shifts);
void WebRtcSpl_AddAffineVectorToVector(int16_t* out_vector,
- int16_t* in_vector,
+ const int16_t* in_vector,
int16_t gain,
int32_t add_constant,
int16_t right_shifts,
size_t vector_length);
void WebRtcSpl_AffineTransformVector(int16_t* out_vector,
- int16_t* in_vector,
+ const int16_t* in_vector,
int16_t gain,
int32_t add_constant,
int16_t right_shifts,
@@ -523,7 +507,7 @@ typedef void (*CrossCorrelation)(int32_t* cross_correlation,
size_t dim_cross_correlation,
int right_shifts,
int step_seq2);
-extern CrossCorrelation WebRtcSpl_CrossCorrelation;
+extern const CrossCorrelation WebRtcSpl_CrossCorrelation;
void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation,
const int16_t* seq1,
const int16_t* seq2,
@@ -531,7 +515,7 @@ void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation,
size_t dim_cross_correlation,
int right_shifts,
int step_seq2);
-#if (defined WEBRTC_DETECT_NEON) || (defined WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation,
const int16_t* seq1,
const int16_t* seq2,
@@ -585,7 +569,6 @@ int16_t WebRtcSpl_RandUArray(int16_t* vector,
// Math functions
int32_t WebRtcSpl_Sqrt(int32_t value);
-int32_t WebRtcSpl_SqrtFloor(int32_t value);
// Divisions. Implementations collected in division_operations.c and
// descriptions at bottom of this file.
@@ -600,22 +583,6 @@ int32_t WebRtcSpl_Energy(int16_t* vector,
size_t vector_length,
int* scale_factor);
-// Calculates the dot product between two (int16_t) vectors.
-//
-// Input:
-// - vector1 : Vector 1
-// - vector2 : Vector 2
-// - vector_length : Number of samples used in the dot product
-// - scaling : The number of right bit shifts to apply on each term
-// during calculation to avoid overflow, i.e., the
-// output will be in Q(-|scaling|)
-//
-// Return value : The dot product in Q(-scaling)
-int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1,
- const int16_t* vector2,
- size_t length,
- int scaling);
-
// Filter operations.
size_t WebRtcSpl_FilterAR(const int16_t* ar_coef,
size_t ar_coef_length,
@@ -689,7 +656,7 @@ typedef int (*DownsampleFast)(const int16_t* data_in,
size_t coefficients_length,
int factor,
size_t delay);
-extern DownsampleFast WebRtcSpl_DownsampleFast;
+extern const DownsampleFast WebRtcSpl_DownsampleFast;
int WebRtcSpl_DownsampleFastC(const int16_t* data_in,
size_t data_in_length,
int16_t* data_out,
@@ -698,7 +665,7 @@ int WebRtcSpl_DownsampleFastC(const int16_t* data_in,
size_t coefficients_length,
int factor,
size_t delay);
-#if (defined WEBRTC_DETECT_NEON) || (defined WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
size_t data_in_length,
int16_t* data_out,
@@ -795,7 +762,8 @@ typedef struct {
int32_t S_16_8[8];
} WebRtcSpl_State22khzTo8khz;
-void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample22khzTo8khz(const int16_t* in,
+ int16_t* out,
WebRtcSpl_State22khzTo8khz* state,
int32_t* tmpmem);
@@ -808,7 +776,8 @@ typedef struct {
int32_t S_11_22[8];
} WebRtcSpl_State8khzTo22khz;
-void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample8khzTo22khz(const int16_t* in,
+ int16_t* out,
WebRtcSpl_State8khzTo22khz* state,
int32_t* tmpmem);
@@ -848,7 +817,8 @@ typedef struct {
int32_t S_32_16[8];
} WebRtcSpl_State48khzTo16khz;
-void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample48khzTo16khz(const int16_t* in,
+ int16_t* out,
WebRtcSpl_State48khzTo16khz* state,
int32_t* tmpmem);
@@ -860,7 +830,8 @@ typedef struct {
int32_t S_24_48[8];
} WebRtcSpl_State16khzTo48khz;
-void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample16khzTo48khz(const int16_t* in,
+ int16_t* out,
WebRtcSpl_State16khzTo48khz* state,
int32_t* tmpmem);
@@ -873,7 +844,8 @@ typedef struct {
int32_t S_16_8[8];
} WebRtcSpl_State48khzTo8khz;
-void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample48khzTo8khz(const int16_t* in,
+ int16_t* out,
WebRtcSpl_State48khzTo8khz* state,
int32_t* tmpmem);
@@ -886,7 +858,8 @@ typedef struct {
int32_t S_24_48[8];
} WebRtcSpl_State8khzTo48khz;
-void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out,
+void WebRtcSpl_Resample8khzTo48khz(const int16_t* in,
+ int16_t* out,
WebRtcSpl_State8khzTo48khz* state,
int32_t* tmpmem);
@@ -899,11 +872,15 @@ void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state);
*
******************************************************************/
-void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len,
- int16_t* out, int32_t* filtState);
+void WebRtcSpl_DownsampleBy2(const int16_t* in,
+ size_t len,
+ int16_t* out,
+ int32_t* filtState);
-void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len,
- int16_t* out, int32_t* filtState);
+void WebRtcSpl_UpsampleBy2(const int16_t* in,
+ size_t len,
+ int16_t* out,
+ int32_t* filtState);
/************************************************************
* END OF RESAMPLING FUNCTIONS
@@ -924,7 +901,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
#ifdef __cplusplus
}
#endif // __cplusplus
-#endif // WEBRTC_SPL_SIGNAL_PROCESSING_LIBRARY_H_
+#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_
//
// WebRtcSpl_AddSatW16(...)
@@ -1353,23 +1330,6 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
//
//
-// WebRtcSpl_SqrtFloor(...)
-//
-// Returns the square root of the input value |value|. The precision of this
-// function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer.
-// If |value| is a negative number then 0 is returned.
-//
-// Algorithm:
-//
-// An iterative 4 cylce/bit routine
-//
-// Input:
-// - value : Value to calculate sqrt of
-//
-// Return value : Result of the sqrt calculation
-//
-
-//
// WebRtcSpl_DivU32U16(...)
//
// Divides a uint32_t |num| by a uint16_t |den|.
diff --git a/webrtc/common_audio/signal_processing/include/spl_inl.h b/webrtc/common_audio/signal_processing/include/spl_inl.h
index d3cc6de..656a312 100644
--- a/webrtc/common_audio/signal_processing/include/spl_inl.h
+++ b/webrtc/common_audio/signal_processing/include/spl_inl.h
@@ -8,24 +8,71 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
// This header file includes the inline functions in
// the fix point signal processing library.
-#ifndef WEBRTC_SPL_SPL_INL_H_
-#define WEBRTC_SPL_SPL_INL_H_
+#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_
+#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_
+
+#include "rtc_base/compile_assert_c.h"
+
+extern const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64];
+
+// Don't call this directly except in tests!
+static __inline int WebRtcSpl_CountLeadingZeros32_NotBuiltin(uint32_t n) {
+ // Normalize n by rounding up to the nearest number that is a sequence of 0
+ // bits followed by a sequence of 1 bits. This number has the same number of
+ // leading zeros as the original n. There are exactly 33 such values.
+ n |= n >> 1;
+ n |= n >> 2;
+ n |= n >> 4;
+ n |= n >> 8;
+ n |= n >> 16;
+
+ // Multiply the modified n with a constant selected (by exhaustive search)
+ // such that each of the 33 possible values of n give a product whose 6 most
+ // significant bits are unique. Then look up the answer in the table.
+ return kWebRtcSpl_CountLeadingZeros32_Table[(n * 0x8c0b2891) >> 26];
+}
+
+// Don't call this directly except in tests!
+static __inline int WebRtcSpl_CountLeadingZeros64_NotBuiltin(uint64_t n) {
+ const int leading_zeros = n >> 32 == 0 ? 32 : 0;
+ return leading_zeros + WebRtcSpl_CountLeadingZeros32_NotBuiltin(
+ (uint32_t)(n >> (32 - leading_zeros)));
+}
+
+// Returns the number of leading zero bits in the argument.
+static __inline int WebRtcSpl_CountLeadingZeros32(uint32_t n) {
+#ifdef __GNUC__
+ RTC_COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t));
+ return n == 0 ? 32 : __builtin_clz(n);
+#else
+ return WebRtcSpl_CountLeadingZeros32_NotBuiltin(n);
+#endif
+}
+
+// Returns the number of leading zero bits in the argument.
+static __inline int WebRtcSpl_CountLeadingZeros64(uint64_t n) {
+#ifdef __GNUC__
+ RTC_COMPILE_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t)); // NOLINT
+ return n == 0 ? 64 : __builtin_clzll(n);
+#else
+ return WebRtcSpl_CountLeadingZeros64_NotBuiltin(n);
+#endif
+}
#ifdef WEBRTC_ARCH_ARM_V7
-#include "webrtc/common_audio/signal_processing/include/spl_inl_armv7.h"
+#include "common_audio/signal_processing/include/spl_inl_armv7.h"
#else
#if defined(MIPS32_LE)
-#include "webrtc/common_audio/signal_processing/include/spl_inl_mips.h"
+#include "common_audio/signal_processing/include/spl_inl_mips.h"
#endif
#if !defined(MIPS_DSP_R1_LE)
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
- int16_t out16 = (int16_t) value32;
+ int16_t out16 = (int16_t)value32;
if (value32 > 32767)
out16 = 32767;
@@ -35,132 +82,65 @@ static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
return out16;
}
-static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
- int32_t l_sum;
-
- // Perform long addition
- l_sum = l_var1 + l_var2;
+static __inline int32_t WebRtcSpl_AddSatW32(int32_t a, int32_t b) {
+ // Do the addition in unsigned numbers, since signed overflow is undefined
+ // behavior.
+ const int32_t sum = (int32_t)((uint32_t)a + (uint32_t)b);
- if (l_var1 < 0) { // Check for underflow.
- if ((l_var2 < 0) && (l_sum >= 0)) {
- l_sum = (int32_t)0x80000000;
- }
- } else { // Check for overflow.
- if ((l_var2 > 0) && (l_sum < 0)) {
- l_sum = (int32_t)0x7FFFFFFF;
- }
+ // a + b can't overflow if a and b have different signs. If they have the
+ // same sign, a + b also has the same sign iff it didn't overflow.
+ if ((a < 0) == (b < 0) && (a < 0) != (sum < 0)) {
+ // The direction of the overflow is obvious from the sign of a + b.
+ return sum < 0 ? INT32_MAX : INT32_MIN;
}
-
- return l_sum;
+ return sum;
}
-static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
- int32_t l_diff;
+static __inline int32_t WebRtcSpl_SubSatW32(int32_t a, int32_t b) {
+ // Do the subtraction in unsigned numbers, since signed overflow is undefined
+ // behavior.
+ const int32_t diff = (int32_t)((uint32_t)a - (uint32_t)b);
- // Perform subtraction.
- l_diff = l_var1 - l_var2;
-
- if (l_var1 < 0) { // Check for underflow.
- if ((l_var2 > 0) && (l_diff > 0)) {
- l_diff = (int32_t)0x80000000;
- }
- } else { // Check for overflow.
- if ((l_var2 < 0) && (l_diff < 0)) {
- l_diff = (int32_t)0x7FFFFFFF;
- }
+ // a - b can't overflow if a and b have the same sign. If they have different
+ // signs, a - b has the same sign as a iff it didn't overflow.
+ if ((a < 0) != (b < 0) && (a < 0) != (diff < 0)) {
+ // The direction of the overflow is obvious from the sign of a - b.
+ return diff < 0 ? INT32_MAX : INT32_MIN;
}
-
- return l_diff;
+ return diff;
}
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
- return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b);
+ return WebRtcSpl_SatW32ToW16((int32_t)a + (int32_t)b);
}
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
- return WebRtcSpl_SatW32ToW16((int32_t) var1 - (int32_t) var2);
+ return WebRtcSpl_SatW32ToW16((int32_t)var1 - (int32_t)var2);
}
#endif // #if !defined(MIPS_DSP_R1_LE)
#if !defined(MIPS32_LE)
static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
- int16_t bits;
-
- if (0xFFFF0000 & n) {
- bits = 16;
- } else {
- bits = 0;
- }
- if (0x0000FF00 & (n >> bits)) bits += 8;
- if (0x000000F0 & (n >> bits)) bits += 4;
- if (0x0000000C & (n >> bits)) bits += 2;
- if (0x00000002 & (n >> bits)) bits += 1;
- if (0x00000001 & (n >> bits)) bits += 1;
-
- return bits;
+ return 32 - WebRtcSpl_CountLeadingZeros32(n);
}
+// Return the number of steps a can be left-shifted without overflow,
+// or 0 if a == 0.
static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
- int16_t zeros;
-
- if (a == 0) {
- return 0;
- }
- else if (a < 0) {
- a = ~a;
- }
-
- if (!(0xFFFF8000 & a)) {
- zeros = 16;
- } else {
- zeros = 0;
- }
- if (!(0xFF800000 & (a << zeros))) zeros += 8;
- if (!(0xF8000000 & (a << zeros))) zeros += 4;
- if (!(0xE0000000 & (a << zeros))) zeros += 2;
- if (!(0xC0000000 & (a << zeros))) zeros += 1;
-
- return zeros;
+ return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a : a) - 1;
}
+// Return the number of steps a can be left-shifted without overflow,
+// or 0 if a == 0.
static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
- int16_t zeros;
-
- if (a == 0) return 0;
-
- if (!(0xFFFF0000 & a)) {
- zeros = 16;
- } else {
- zeros = 0;
- }
- if (!(0xFF000000 & (a << zeros))) zeros += 8;
- if (!(0xF0000000 & (a << zeros))) zeros += 4;
- if (!(0xC0000000 & (a << zeros))) zeros += 2;
- if (!(0x80000000 & (a << zeros))) zeros += 1;
-
- return zeros;
+ return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a);
}
+// Return the number of steps a can be left-shifted without overflow,
+// or 0 if a == 0.
static __inline int16_t WebRtcSpl_NormW16(int16_t a) {
- int16_t zeros;
-
- if (a == 0) {
- return 0;
- }
- else if (a < 0) {
- a = ~a;
- }
-
- if (!(0xFF80 & a)) {
- zeros = 8;
- } else {
- zeros = 0;
- }
- if (!(0xF800 & (a << zeros))) zeros += 4;
- if (!(0xE000 & (a << zeros))) zeros += 2;
- if (!(0xC000 & (a << zeros))) zeros += 1;
-
- return zeros;
+ const int32_t a32 = a;
+ return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a32 : a32) - 17;
}
static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
@@ -170,4 +150,4 @@ static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
#endif // WEBRTC_ARCH_ARM_V7
-#endif // WEBRTC_SPL_SPL_INL_H_
+#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_
diff --git a/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h b/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
index 2718801..930e91e 100644
--- a/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
+++ b/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
@@ -8,13 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
/* This header file includes the inline functions for ARM processors in
* the fix point signal processing library.
*/
-#ifndef WEBRTC_SPL_SPL_INL_ARMV7_H_
-#define WEBRTC_SPL_SPL_INL_ARMV7_H_
+#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_
+#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_
/* TODO(kma): Replace some assembly code with GCC intrinsics
* (e.g. __builtin_clz).
@@ -26,35 +25,37 @@
*/
static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) {
int32_t tmp = 0;
- __asm __volatile ("smulwb %0, %1, %2":"=r"(tmp):"r"(b), "r"(a));
+ __asm __volatile("smulwb %0, %1, %2" : "=r"(tmp) : "r"(b), "r"(a));
return tmp;
}
static __inline int32_t WEBRTC_SPL_MUL_16_16(int16_t a, int16_t b) {
int32_t tmp = 0;
- __asm __volatile ("smulbb %0, %1, %2":"=r"(tmp):"r"(a), "r"(b));
+ __asm __volatile("smulbb %0, %1, %2" : "=r"(tmp) : "r"(a), "r"(b));
return tmp;
}
// TODO(kma): add unit test.
static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
int32_t tmp = 0;
- __asm __volatile ("smlabb %0, %1, %2, %3":"=r"(tmp):"r"(a), "r"(b), "r"(c));
+ __asm __volatile("smlabb %0, %1, %2, %3"
+ : "=r"(tmp)
+ : "r"(a), "r"(b), "r"(c));
return tmp;
}
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
int32_t s_sum = 0;
- __asm __volatile ("qadd16 %0, %1, %2":"=r"(s_sum):"r"(a), "r"(b));
+ __asm __volatile("qadd16 %0, %1, %2" : "=r"(s_sum) : "r"(a), "r"(b));
- return (int16_t) s_sum;
+ return (int16_t)s_sum;
}
static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
int32_t l_sum = 0;
- __asm __volatile ("qadd %0, %1, %2":"=r"(l_sum):"r"(l_var1), "r"(l_var2));
+ __asm __volatile("qadd %0, %1, %2" : "=r"(l_sum) : "r"(l_var1), "r"(l_var2));
return l_sum;
}
@@ -62,7 +63,7 @@ static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
int32_t l_sub = 0;
- __asm __volatile ("qsub %0, %1, %2":"=r"(l_sub):"r"(l_var1), "r"(l_var2));
+ __asm __volatile("qsub %0, %1, %2" : "=r"(l_sub) : "r"(l_var1), "r"(l_var2));
return l_sub;
}
@@ -70,7 +71,7 @@ static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
int32_t s_sub = 0;
- __asm __volatile ("qsub16 %0, %1, %2":"=r"(s_sub):"r"(var1), "r"(var2));
+ __asm __volatile("qsub16 %0, %1, %2" : "=r"(s_sub) : "r"(var1), "r"(var2));
return (int16_t)s_sub;
}
@@ -78,7 +79,7 @@ static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
int32_t tmp = 0;
- __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(n));
+ __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(n));
return (int16_t)(32 - tmp);
}
@@ -88,12 +89,11 @@ static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
if (a == 0) {
return 0;
- }
- else if (a < 0) {
+ } else if (a < 0) {
a ^= 0xFFFFFFFF;
}
- __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
+ __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a));
return (int16_t)(tmp - 1);
}
@@ -101,9 +101,10 @@ static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
int tmp = 0;
- if (a == 0) return 0;
+ if (a == 0)
+ return 0;
- __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
+ __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a));
return (int16_t)tmp;
}
@@ -114,12 +115,11 @@ static __inline int16_t WebRtcSpl_NormW16(int16_t a) {
if (a_32 == 0) {
return 0;
- }
- else if (a_32 < 0) {
+ } else if (a_32 < 0) {
a_32 ^= 0xFFFFFFFF;
}
- __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a_32));
+ __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a_32));
return (int16_t)(tmp - 17);
}
@@ -128,9 +128,9 @@ static __inline int16_t WebRtcSpl_NormW16(int16_t a) {
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
int32_t out = 0;
- __asm __volatile ("ssat %0, #16, %1" : "=r"(out) : "r"(value32));
+ __asm __volatile("ssat %0, #16, %1" : "=r"(out) : "r"(value32));
return (int16_t)out;
}
-#endif // WEBRTC_SPL_SPL_INL_ARMV7_H_
+#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_
diff --git a/webrtc/common_audio/signal_processing/include/spl_inl_mips.h b/webrtc/common_audio/signal_processing/include/spl_inl_mips.h
index cd04bdd..1db95e8 100644
--- a/webrtc/common_audio/signal_processing/include/spl_inl_mips.h
+++ b/webrtc/common_audio/signal_processing/include/spl_inl_mips.h
@@ -8,72 +8,65 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
// This header file includes the inline functions in
// the fix point signal processing library.
-#ifndef WEBRTC_SPL_SPL_INL_MIPS_H_
-#define WEBRTC_SPL_SPL_INL_MIPS_H_
+#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_
+#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_
-static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a,
- int32_t b) {
+static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a, int32_t b) {
int32_t value32 = 0;
int32_t a1 = 0, b1 = 0;
__asm __volatile(
#if defined(MIPS32_R2_LE)
- "seh %[a1], %[a] \n\t"
- "seh %[b1], %[b] \n\t"
+ "seh %[a1], %[a] \n\t"
+ "seh %[b1], %[b] \n\t"
#else
- "sll %[a1], %[a], 16 \n\t"
- "sll %[b1], %[b], 16 \n\t"
- "sra %[a1], %[a1], 16 \n\t"
- "sra %[b1], %[b1], 16 \n\t"
+ "sll %[a1], %[a], 16 \n\t"
+ "sll %[b1], %[b], 16 \n\t"
+ "sra %[a1], %[a1], 16 \n\t"
+ "sra %[b1], %[b1], 16 \n\t"
#endif
- "mul %[value32], %[a1], %[b1] \n\t"
- : [value32] "=r" (value32), [a1] "=&r" (a1), [b1] "=&r" (b1)
- : [a] "r" (a), [b] "r" (b)
- : "hi", "lo"
- );
+ "mul %[value32], %[a1], %[b1] \n\t"
+ : [value32] "=r"(value32), [a1] "=&r"(a1), [b1] "=&r"(b1)
+ : [a] "r"(a), [b] "r"(b)
+ : "hi", "lo");
return value32;
}
-static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a,
- int32_t b) {
+static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) {
int32_t value32 = 0, b1 = 0, b2 = 0;
int32_t a1 = 0;
__asm __volatile(
#if defined(MIPS32_R2_LE)
- "seh %[a1], %[a] \n\t"
+ "seh %[a1], %[a] \n\t"
#else
- "sll %[a1], %[a], 16 \n\t"
- "sra %[a1], %[a1], 16 \n\t"
+ "sll %[a1], %[a], 16 \n\t"
+ "sra %[a1], %[a1], 16 \n\t"
#endif
- "andi %[b2], %[b], 0xFFFF \n\t"
- "sra %[b1], %[b], 16 \n\t"
- "sra %[b2], %[b2], 1 \n\t"
- "mul %[value32], %[a1], %[b1] \n\t"
- "mul %[b2], %[a1], %[b2] \n\t"
- "addiu %[b2], %[b2], 0x4000 \n\t"
- "sra %[b2], %[b2], 15 \n\t"
- "addu %[value32], %[value32], %[b2] \n\t"
- : [value32] "=&r" (value32), [b1] "=&r" (b1), [b2] "=&r" (b2),
- [a1] "=&r" (a1)
- : [a] "r" (a), [b] "r" (b)
- : "hi", "lo"
- );
+ "andi %[b2], %[b], 0xFFFF \n\t"
+ "sra %[b1], %[b], 16 \n\t"
+ "sra %[b2], %[b2], 1 \n\t"
+ "mul %[value32], %[a1], %[b1] \n\t"
+ "mul %[b2], %[a1], %[b2] \n\t"
+ "addiu %[b2], %[b2], 0x4000 \n\t"
+ "sra %[b2], %[b2], 15 \n\t"
+ "addu %[value32], %[value32], %[b2] \n\t"
+ : [value32] "=&r"(value32), [b1] "=&r"(b1), [b2] "=&r"(b2), [a1] "=&r"(a1)
+ : [a] "r"(a), [b] "r"(b)
+ : "hi", "lo");
return value32;
}
#if defined(MIPS_DSP_R1_LE)
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
__asm __volatile(
- "shll_s.w %[value32], %[value32], 16 \n\t"
- "sra %[value32], %[value32], 16 \n\t"
- : [value32] "+r" (value32)
- :
- );
+ "shll_s.w %[value32], %[value32], 16 \n\t"
+ "sra %[value32], %[value32], 16 \n\t"
+ : [value32] "+r"(value32)
+ :);
int16_t out16 = (int16_t)value32;
return out16;
}
@@ -81,11 +74,9 @@ static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
int32_t value32 = 0;
- __asm __volatile(
- "addq_s.ph %[value32], %[a], %[b] \n\t"
- : [value32] "=r" (value32)
- : [a] "r" (a), [b] "r" (b)
- );
+ __asm __volatile("addq_s.ph %[value32], %[a], %[b] \n\t"
+ : [value32] "=r"(value32)
+ : [a] "r"(a), [b] "r"(b));
return (int16_t)value32;
}
@@ -93,10 +84,9 @@ static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
int32_t l_sum;
__asm __volatile(
- "addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t"
- : [l_sum] "=r" (l_sum)
- : [l_var1] "r" (l_var1), [l_var2] "r" (l_var2)
- );
+ "addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t"
+ : [l_sum] "=r"(l_sum)
+ : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2));
return l_sum;
}
@@ -104,11 +94,9 @@ static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
int32_t value32;
- __asm __volatile(
- "subq_s.ph %[value32], %[var1], %[var2] \n\t"
- : [value32] "=r" (value32)
- : [var1] "r" (var1), [var2] "r" (var2)
- );
+ __asm __volatile("subq_s.ph %[value32], %[var1], %[var2] \n\t"
+ : [value32] "=r"(value32)
+ : [var1] "r"(var1), [var2] "r"(var2));
return (int16_t)value32;
}
@@ -117,10 +105,9 @@ static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
int32_t l_diff;
__asm __volatile(
- "subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t"
- : [l_diff] "=r" (l_diff)
- : [l_var1] "r" (l_var1), [l_var2] "r" (l_var2)
- );
+ "subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t"
+ : [l_diff] "=r"(l_diff)
+ : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2));
return l_diff;
}
@@ -131,11 +118,10 @@ static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
int i32 = 32;
__asm __volatile(
- "clz %[bits], %[n] \n\t"
- "subu %[bits], %[i32], %[bits] \n\t"
- : [bits] "=&r" (bits)
- : [n] "r" (n), [i32] "r" (i32)
- );
+ "clz %[bits], %[n] \n\t"
+ "subu %[bits], %[i32], %[bits] \n\t"
+ : [bits] "=&r"(bits)
+ : [n] "r"(n), [i32] "r"(i32));
return (int16_t)bits;
}
@@ -144,21 +130,20 @@ static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
int zeros = 0;
__asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "bnez %[a], 1f \n\t"
- " sra %[zeros], %[a], 31 \n\t"
- "b 2f \n\t"
- " move %[zeros], $zero \n\t"
- "1: \n\t"
- "xor %[zeros], %[a], %[zeros] \n\t"
- "clz %[zeros], %[zeros] \n\t"
- "addiu %[zeros], %[zeros], -1 \n\t"
- "2: \n\t"
- ".set pop \n\t"
- : [zeros]"=&r"(zeros)
- : [a] "r" (a)
- );
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "bnez %[a], 1f \n\t"
+ " sra %[zeros], %[a], 31 \n\t"
+ "b 2f \n\t"
+ " move %[zeros], $zero \n\t"
+ "1: \n\t"
+ "xor %[zeros], %[a], %[zeros] \n\t"
+ "clz %[zeros], %[zeros] \n\t"
+ "addiu %[zeros], %[zeros], -1 \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [zeros] "=&r"(zeros)
+ : [a] "r"(a));
return (int16_t)zeros;
}
@@ -166,11 +151,9 @@ static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
int zeros = 0;
- __asm __volatile(
- "clz %[zeros], %[a] \n\t"
- : [zeros] "=r" (zeros)
- : [a] "r" (a)
- );
+ __asm __volatile("clz %[zeros], %[a] \n\t"
+ : [zeros] "=r"(zeros)
+ : [a] "r"(a));
return (int16_t)(zeros & 0x1f);
}
@@ -180,46 +163,42 @@ static __inline int16_t WebRtcSpl_NormW16(int16_t a) {
int a0 = a << 16;
__asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "bnez %[a0], 1f \n\t"
- " sra %[zeros], %[a0], 31 \n\t"
- "b 2f \n\t"
- " move %[zeros], $zero \n\t"
- "1: \n\t"
- "xor %[zeros], %[a0], %[zeros] \n\t"
- "clz %[zeros], %[zeros] \n\t"
- "addiu %[zeros], %[zeros], -1 \n\t"
- "2: \n\t"
- ".set pop \n\t"
- : [zeros]"=&r"(zeros)
- : [a0] "r" (a0)
- );
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "bnez %[a0], 1f \n\t"
+ " sra %[zeros], %[a0], 31 \n\t"
+ "b 2f \n\t"
+ " move %[zeros], $zero \n\t"
+ "1: \n\t"
+ "xor %[zeros], %[a0], %[zeros] \n\t"
+ "clz %[zeros], %[zeros] \n\t"
+ "addiu %[zeros], %[zeros], -1 \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [zeros] "=&r"(zeros)
+ : [a0] "r"(a0));
return (int16_t)zeros;
}
-static __inline int32_t WebRtc_MulAccumW16(int16_t a,
- int16_t b,
- int32_t c) {
+static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
int32_t res = 0, c1 = 0;
__asm __volatile(
#if defined(MIPS32_R2_LE)
- "seh %[a], %[a] \n\t"
- "seh %[b], %[b] \n\t"
+ "seh %[a], %[a] \n\t"
+ "seh %[b], %[b] \n\t"
#else
- "sll %[a], %[a], 16 \n\t"
- "sll %[b], %[b], 16 \n\t"
- "sra %[a], %[a], 16 \n\t"
- "sra %[b], %[b], 16 \n\t"
+ "sll %[a], %[a], 16 \n\t"
+ "sll %[b], %[b], 16 \n\t"
+ "sra %[a], %[a], 16 \n\t"
+ "sra %[b], %[b], 16 \n\t"
#endif
- "mul %[res], %[a], %[b] \n\t"
- "addu %[c1], %[c], %[res] \n\t"
- : [c1] "=r" (c1), [res] "=&r" (res)
- : [a] "r" (a), [b] "r" (b), [c] "r" (c)
- : "hi", "lo"
- );
+ "mul %[res], %[a], %[b] \n\t"
+ "addu %[c1], %[c], %[res] \n\t"
+ : [c1] "=r"(c1), [res] "=&r"(res)
+ : [a] "r"(a), [b] "r"(b), [c] "r"(c)
+ : "hi", "lo");
return (c1);
}
-#endif // WEBRTC_SPL_SPL_INL_MIPS_H_
+#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_
diff --git a/webrtc/common_audio/signal_processing/levinson_durbin.c b/webrtc/common_audio/signal_processing/levinson_durbin.c
index d46e551..2c5cbae 100644
--- a/webrtc/common_audio/signal_processing/levinson_durbin.c
+++ b/webrtc/common_audio/signal_processing/levinson_durbin.c
@@ -15,12 +15,14 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/sanitizer.h"
#define SPL_LEVINSON_MAXORDER 20
-int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
- size_t order)
+int16_t RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486
+WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
+ size_t order)
{
size_t i, j;
// Auto-correlation coefficients in high precision
@@ -43,16 +45,17 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
for (i = 0; i <= order; ++i)
{
- temp1W32 = WEBRTC_SPL_LSHIFT_W32(R[i], norm);
+ temp1W32 = R[i] * (1 << norm);
+ // UBSan: 12 * 268435456 cannot be represented in type 'int'
+
// Put R in hi and low format
R_hi[i] = (int16_t)(temp1W32 >> 16);
- R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] << 16)) >> 1);
+ R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] * 65536)) >> 1);
}
// K = A[1] = -R[1] / R[0]
- temp2W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[1],16)
- + WEBRTC_SPL_LSHIFT_W32((int32_t)R_low[1],1); // R[1] in Q31
+ temp2W32 = R[1] * (1 << norm); // R[1] in Q31
temp3W32 = WEBRTC_SPL_ABS_W32(temp2W32); // abs R[1]
temp1W32 = WebRtcSpl_DivW32HiLow(temp3W32, R_hi[0], R_low[0]); // abs(R[1])/R[0] in Q31
// Put back the sign on R[1]
@@ -63,7 +66,7 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
// Put K in hi and low format
K_hi = (int16_t)(temp1W32 >> 16);
- K_low = (int16_t)((temp1W32 - ((int32_t)K_hi << 16)) >> 1);
+ K_low = (int16_t)((temp1W32 - ((int32_t)K_hi * 65536)) >> 1);
// Store first reflection coefficient
K[0] = K_hi;
@@ -72,11 +75,11 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
// Put A[1] in hi and low format
A_hi[1] = (int16_t)(temp1W32 >> 16);
- A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] << 16)) >> 1);
+ A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] * 65536)) >> 1);
// Alpha = R[0] * (1-K^2)
- temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) << 1; // = k^2 in Q31
+ temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) * 2; // = k^2 in Q31
temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); // Guard against <0
temp1W32 = (int32_t)0x7fffffffL - temp1W32; // temp1W32 = (1 - K[0]*K[0]) in Q31
@@ -112,14 +115,14 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
for (j = 1; j < i; j++)
{
// temp1W32 is in Q31
- temp1W32 += (R_hi[j] * A_hi[i - j] << 1) +
+ temp1W32 += (R_hi[j] * A_hi[i - j] * 2) +
(((R_hi[j] * A_low[i - j] >> 15) +
- (R_low[j] * A_hi[i - j] >> 15)) << 1);
+ (R_low[j] * A_hi[i - j] >> 15)) * 2);
}
- temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, 4);
- temp1W32 += (WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[i], 16)
- + WEBRTC_SPL_LSHIFT_W32((int32_t)R_low[i], 1));
+ temp1W32 = temp1W32 * 16;
+ temp1W32 += ((int32_t)R_hi[i] * 65536)
+ + WEBRTC_SPL_LSHIFT_W32((int32_t)R_low[i], 1);
// K = -temp1W32 / Alpha
temp2W32 = WEBRTC_SPL_ABS_W32(temp1W32); // abs(temp1W32)
@@ -135,7 +138,7 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
norm = WebRtcSpl_NormW32(temp3W32);
if ((Alpha_exp <= norm) || (temp3W32 == 0))
{
- temp3W32 = WEBRTC_SPL_LSHIFT_W32(temp3W32, Alpha_exp);
+ temp3W32 = temp3W32 * (1 << Alpha_exp);
} else
{
if (temp3W32 > 0)
@@ -149,7 +152,7 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
// Put K on hi and low format
K_hi = (int16_t)(temp3W32 >> 16);
- K_low = (int16_t)((temp3W32 - ((int32_t)K_hi << 16)) >> 1);
+ K_low = (int16_t)((temp3W32 - ((int32_t)K_hi * 65536)) >> 1);
// Store Reflection coefficient in Q15
K[i - 1] = K_hi;
@@ -171,17 +174,17 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
for (j = 1; j < i; j++)
{
// temp1W32 = A[j] in Q27
- temp1W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[j],16)
+ temp1W32 = (int32_t)A_hi[j] * 65536
+ WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[j],1);
// temp1W32 += K*A[i-j] in Q27
temp1W32 += (K_hi * A_hi[i - j] + (K_hi * A_low[i - j] >> 15) +
- (K_low * A_hi[i - j] >> 15)) << 1;
+ (K_low * A_hi[i - j] >> 15)) * 2;
// Put Anew in hi and low format
A_upd_hi[j] = (int16_t)(temp1W32 >> 16);
A_upd_low[j] = (int16_t)(
- (temp1W32 - ((int32_t)A_upd_hi[j] << 16)) >> 1);
+ (temp1W32 - ((int32_t)A_upd_hi[j] * 65536)) >> 1);
}
// temp3W32 = K in Q27 (Convert from Q31 to Q27)
@@ -190,11 +193,11 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
// Store Anew in hi and low format
A_upd_hi[i] = (int16_t)(temp3W32 >> 16);
A_upd_low[i] = (int16_t)(
- (temp3W32 - ((int32_t)A_upd_hi[i] << 16)) >> 1);
+ (temp3W32 - ((int32_t)A_upd_hi[i] * 65536)) >> 1);
// Alpha = Alpha * (1-K^2)
- temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) << 1; // K*K in Q31
+ temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) * 2; // K*K in Q31
temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); // Guard against <0
temp1W32 = (int32_t)0x7fffffffL - temp1W32; // 1 - K*K in Q31
@@ -237,10 +240,10 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K,
for (i = 1; i <= order; i++)
{
// temp1W32 in Q27
- temp1W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[i], 16)
+ temp1W32 = (int32_t)A_hi[i] * 65536
+ WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[i], 1);
// Round and store upper word
- A[i] = (int16_t)(((temp1W32 << 1) + 32768) >> 16);
+ A[i] = (int16_t)(((temp1W32 * 2) + 32768) >> 16);
}
return 1; // Stable filters
}
diff --git a/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c b/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c
index edcebd4..7a5e251 100644
--- a/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c
+++ b/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
#define SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER 50
diff --git a/webrtc/common_audio/signal_processing/min_max_operations.c b/webrtc/common_audio/signal_processing/min_max_operations.c
index 4a962f8..d249a02 100644
--- a/webrtc/common_audio/signal_processing/min_max_operations.c
+++ b/webrtc/common_audio/signal_processing/min_max_operations.c
@@ -24,10 +24,10 @@
*
*/
-#include <assert.h>
#include <stdlib.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// TODO(bjorn/kma): Consolidate function pairs (e.g. combine
// WebRtcSpl_MaxAbsValueW16C and WebRtcSpl_MaxAbsIndexW16 into a single one.)
@@ -38,7 +38,7 @@ int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length) {
size_t i = 0;
int absolute = 0, maximum = 0;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
absolute = abs((int)vector[i]);
@@ -64,7 +64,7 @@ int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length) {
uint32_t absolute = 0, maximum = 0;
size_t i = 0;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
absolute = abs((int)vector[i]);
@@ -83,7 +83,7 @@ int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length) {
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
size_t i = 0;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
if (vector[i] > maximum)
@@ -97,7 +97,7 @@ int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length) {
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
size_t i = 0;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
if (vector[i] > maximum)
@@ -111,7 +111,7 @@ int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length) {
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
size_t i = 0;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
if (vector[i] < minimum)
@@ -125,7 +125,7 @@ int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length) {
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
size_t i = 0;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
if (vector[i] < minimum)
@@ -141,7 +141,7 @@ size_t WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, size_t length) {
size_t i = 0, index = 0;
int absolute = 0, maximum = 0;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
absolute = abs((int)vector[i]);
@@ -160,7 +160,7 @@ size_t WebRtcSpl_MaxIndexW16(const int16_t* vector, size_t length) {
size_t i = 0, index = 0;
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
if (vector[i] > maximum) {
@@ -177,7 +177,7 @@ size_t WebRtcSpl_MaxIndexW32(const int32_t* vector, size_t length) {
size_t i = 0, index = 0;
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
if (vector[i] > maximum) {
@@ -194,7 +194,7 @@ size_t WebRtcSpl_MinIndexW16(const int16_t* vector, size_t length) {
size_t i = 0, index = 0;
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
if (vector[i] < minimum) {
@@ -211,7 +211,7 @@ size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length) {
size_t i = 0, index = 0;
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
for (i = 0; i < length; i++) {
if (vector[i] < minimum) {
diff --git a/webrtc/common_audio/signal_processing/min_max_operations_mips.c b/webrtc/common_audio/signal_processing/min_max_operations_mips.c
index 28de45b..8a7fc65 100644
--- a/webrtc/common_audio/signal_processing/min_max_operations_mips.c
+++ b/webrtc/common_audio/signal_processing/min_max_operations_mips.c
@@ -16,9 +16,8 @@
*
*/
-#include <assert.h>
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// Maximum absolute value of word16 vector.
int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length) {
@@ -26,7 +25,7 @@ int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length) {
int32_t tmp32_0, tmp32_1, tmp32_2, tmp32_3;
size_t i, loop_size;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
#if defined(MIPS_DSP_R1)
const int32_t* tmpvec32 = (int32_t*)vector;
@@ -230,7 +229,7 @@ int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length) {
uint32_t absolute = 0, maximum = 0;
int tmp1 = 0, max_value = 0x7fffffff;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
__asm__ volatile (
".set push \n\t"
@@ -264,7 +263,7 @@ int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length) {
int tmp1;
int16_t value;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
__asm__ volatile (
".set push \n\t"
@@ -292,7 +291,7 @@ int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length) {
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
int tmp1, value;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
__asm__ volatile (
".set push \n\t"
@@ -322,7 +321,7 @@ int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length) {
int tmp1;
int16_t value;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
__asm__ volatile (
".set push \n\t"
@@ -351,7 +350,7 @@ int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length) {
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
int tmp1, value;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
__asm__ volatile (
".set push \n\t"
diff --git a/webrtc/common_audio/signal_processing/min_max_operations_neon.c b/webrtc/common_audio/signal_processing/min_max_operations_neon.c
index 6fbbf94..53217df 100644
--- a/webrtc/common_audio/signal_processing/min_max_operations_neon.c
+++ b/webrtc/common_audio/signal_processing/min_max_operations_neon.c
@@ -9,16 +9,16 @@
*/
#include <arm_neon.h>
-#include <assert.h>
#include <stdlib.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// Maximum absolute value of word16 vector. C version for generic platforms.
int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length) {
int absolute = 0, maximum = 0;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
const int16_t* p_start = vector;
size_t rest = length & 7;
@@ -76,7 +76,7 @@ int32_t WebRtcSpl_MaxAbsValueW32Neon(const int32_t* vector, size_t length) {
size_t i = 0;
size_t residual = length & 0x7;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
const int32_t* p_start = vector;
uint32x4_t max32x4_0 = vdupq_n_u32(0);
@@ -128,7 +128,7 @@ int16_t WebRtcSpl_MaxValueW16Neon(const int16_t* vector, size_t length) {
size_t i = 0;
size_t residual = length & 0x7;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
const int16_t* p_start = vector;
int16x8_t max16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MIN);
@@ -166,7 +166,7 @@ int32_t WebRtcSpl_MaxValueW32Neon(const int32_t* vector, size_t length) {
size_t i = 0;
size_t residual = length & 0x7;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
const int32_t* p_start = vector;
int32x4_t max32x4_0 = vdupq_n_s32(WEBRTC_SPL_WORD32_MIN);
@@ -208,7 +208,7 @@ int16_t WebRtcSpl_MinValueW16Neon(const int16_t* vector, size_t length) {
size_t i = 0;
size_t residual = length & 0x7;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
const int16_t* p_start = vector;
int16x8_t min16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MAX);
@@ -246,7 +246,7 @@ int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length) {
size_t i = 0;
size_t residual = length & 0x7;
- assert(length > 0);
+ RTC_DCHECK_GT(length, 0);
const int32_t* p_start = vector;
int32x4_t min32x4_0 = vdupq_n_s32(WEBRTC_SPL_WORD32_MAX);
diff --git a/webrtc/common_audio/signal_processing/randomization_functions.c b/webrtc/common_audio/signal_processing/randomization_functions.c
index 73f2409..a445c57 100644
--- a/webrtc/common_audio/signal_processing/randomization_functions.c
+++ b/webrtc/common_audio/signal_processing/randomization_functions.c
@@ -19,7 +19,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
static const uint32_t kMaxSeedUsed = 0x80000000;
diff --git a/webrtc/common_audio/signal_processing/real_fft.c b/webrtc/common_audio/signal_processing/real_fft.c
index 92daae4..780e517 100644
--- a/webrtc/common_audio/signal_processing/real_fft.c
+++ b/webrtc/common_audio/signal_processing/real_fft.c
@@ -8,11 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/signal_processing/include/real_fft.h"
+#include "common_audio/signal_processing/include/real_fft.h"
#include <stdlib.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
struct RealFFT {
int order;
diff --git a/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c b/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c
index 06a29b6..b0858b2 100644
--- a/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c
+++ b/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
void WebRtcSpl_ReflCoefToLpc(const int16_t *k, int use_order, int16_t *a)
{
diff --git a/webrtc/common_audio/signal_processing/resample.c b/webrtc/common_audio/signal_processing/resample.c
index 45fe52a..d4b2736 100644
--- a/webrtc/common_audio/signal_processing/resample.c
+++ b/webrtc/common_audio/signal_processing/resample.c
@@ -15,8 +15,8 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/signal_processing/resample_by_2_internal.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/resample_by_2_internal.h"
// Declaration of internally used functions
static void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In, int16_t *Out,
diff --git a/webrtc/common_audio/signal_processing/resample_48khz.c b/webrtc/common_audio/signal_processing/resample_48khz.c
index 2220cc3..8518e7b 100644
--- a/webrtc/common_audio/signal_processing/resample_48khz.c
+++ b/webrtc/common_audio/signal_processing/resample_48khz.c
@@ -16,8 +16,8 @@
*/
#include <string.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/signal_processing/resample_by_2_internal.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/resample_by_2_internal.h"
////////////////////////////
///// 48 kHz -> 16 kHz /////
diff --git a/webrtc/common_audio/signal_processing/resample_by_2.c b/webrtc/common_audio/signal_processing/resample_by_2.c
index dcba82e..73e1950 100644
--- a/webrtc/common_audio/signal_processing/resample_by_2.c
+++ b/webrtc/common_audio/signal_processing/resample_by_2.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
#ifdef WEBRTC_ARCH_ARM_V7
@@ -83,7 +83,7 @@ void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len,
for (i = (len >> 1); i > 0; i--) {
// lower allpass filter
- in32 = (int32_t)(*in++) << 10;
+ in32 = (int32_t)(*in++) * (1 << 10);
diff = in32 - state1;
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
state0 = in32;
@@ -95,7 +95,7 @@ void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len,
state2 = tmp2;
// upper allpass filter
- in32 = (int32_t)(*in++) << 10;
+ in32 = (int32_t)(*in++) * (1 << 10);
diff = in32 - state5;
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
state4 = in32;
@@ -141,7 +141,7 @@ void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len,
for (i = len; i > 0; i--) {
// lower allpass filter
- in32 = (int32_t)(*in++) << 10;
+ in32 = (int32_t)(*in++) * (1 << 10);
diff = in32 - state1;
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0);
state0 = in32;
diff --git a/webrtc/common_audio/signal_processing/resample_by_2_internal.c b/webrtc/common_audio/signal_processing/resample_by_2_internal.c
index 085069c..99592b2 100644
--- a/webrtc/common_audio/signal_processing/resample_by_2_internal.c
+++ b/webrtc/common_audio/signal_processing/resample_by_2_internal.c
@@ -14,7 +14,8 @@
*
*/
-#include "webrtc/common_audio/signal_processing/resample_by_2_internal.h"
+#include "common_audio/signal_processing/resample_by_2_internal.h"
+#include "rtc_base/sanitizer.h"
// allpass filter coefficients.
static const int16_t kResampleAllpass[2][3] = {
@@ -28,8 +29,9 @@ static const int16_t kResampleAllpass[2][3] = {
// output: int16_t (saturated) (of length len/2)
// state: filter state array; length = 8
-void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
- int32_t *state)
+void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486
+WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
+ int32_t *state)
{
int32_t tmp0, tmp1, diff;
int32_t i;
@@ -41,6 +43,8 @@ void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
{
tmp0 = in[i << 1];
diff = tmp0 - state[1];
+ // UBSan: -1771017321 - 999586185 cannot be represented in type 'int'
+
// scale down and round
diff = (diff + (1 << 13)) >> 14;
tmp1 = state[0] + diff * kResampleAllpass[1][0];
@@ -121,10 +125,11 @@ void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
// output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len/2)
// state: filter state array; length = 8
-void WebRtcSpl_DownBy2ShortToInt(const int16_t *in,
- int32_t len,
- int32_t *out,
- int32_t *state)
+void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486
+WebRtcSpl_DownBy2ShortToInt(const int16_t *in,
+ int32_t len,
+ int32_t *out,
+ int32_t *state)
{
int32_t tmp0, tmp1, diff;
int32_t i;
@@ -141,6 +146,8 @@ void WebRtcSpl_DownBy2ShortToInt(const int16_t *in,
tmp1 = state[0] + diff * kResampleAllpass[1][0];
state[0] = tmp0;
diff = tmp1 - state[2];
+ // UBSan: -1379909682 - 834099714 cannot be represented in type 'int'
+
// scale down and truncate
diff = diff >> 14;
if (diff < 0)
@@ -549,8 +556,9 @@ void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len, int32_t* out,
// input: int32_t (shifted 15 positions to the left, + offset 16384)
// output: int32_t (normalized, not saturated)
// state: filter state array; length = 8
-void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
- int32_t* state)
+void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486
+WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
+ int32_t* state)
{
int32_t tmp0, tmp1, diff;
int32_t i;
@@ -594,6 +602,8 @@ void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
{
tmp0 = in[i << 1];
diff = tmp0 - state[5];
+ // UBSan: -794814117 - 1566149201 cannot be represented in type 'int'
+
// scale down and round
diff = (diff + (1 << 13)) >> 14;
tmp1 = state[4] + diff * kResampleAllpass[0][0];
diff --git a/webrtc/common_audio/signal_processing/resample_by_2_internal.h b/webrtc/common_audio/signal_processing/resample_by_2_internal.h
index 5c9533e..145395a 100644
--- a/webrtc/common_audio/signal_processing/resample_by_2_internal.h
+++ b/webrtc/common_audio/signal_processing/resample_by_2_internal.h
@@ -8,40 +8,53 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
/*
* This header file contains some internal resampling functions.
*
*/
-#ifndef WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
-#define WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
+#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_
+#define COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_
-#include "webrtc/typedefs.h"
+#include <stdint.h>
/*******************************************************************
* resample_by_2_fast.c
* Functions for internal use in the other resample functions
******************************************************************/
-void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
- int32_t *state);
-
-void WebRtcSpl_DownBy2ShortToInt(const int16_t *in, int32_t len,
- int32_t *out, int32_t *state);
-
-void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len,
- int32_t *out, int32_t *state);
-
-void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out,
- int32_t *state);
+void WebRtcSpl_DownBy2IntToShort(int32_t* in,
+ int32_t len,
+ int16_t* out,
+ int32_t* state);
+
+void WebRtcSpl_DownBy2ShortToInt(const int16_t* in,
+ int32_t len,
+ int32_t* out,
+ int32_t* state);
+
+void WebRtcSpl_UpBy2ShortToInt(const int16_t* in,
+ int32_t len,
+ int32_t* out,
+ int32_t* state);
+
+void WebRtcSpl_UpBy2IntToInt(const int32_t* in,
+ int32_t len,
+ int32_t* out,
+ int32_t* state);
-void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len,
- int16_t *out, int32_t *state);
+void WebRtcSpl_UpBy2IntToShort(const int32_t* in,
+ int32_t len,
+ int16_t* out,
+ int32_t* state);
-void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len,
- int32_t* out, int32_t* state);
+void WebRtcSpl_LPBy2ShortToInt(const int16_t* in,
+ int32_t len,
+ int32_t* out,
+ int32_t* state);
-void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
+void WebRtcSpl_LPBy2IntToInt(const int32_t* in,
+ int32_t len,
+ int32_t* out,
int32_t* state);
-#endif // WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
+#endif // COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_
diff --git a/webrtc/common_audio/signal_processing/resample_by_2_mips.c b/webrtc/common_audio/signal_processing/resample_by_2_mips.c
index ec5fc8b..f41bab7 100644
--- a/webrtc/common_audio/signal_processing/resample_by_2_mips.c
+++ b/webrtc/common_audio/signal_processing/resample_by_2_mips.c
@@ -17,11 +17,13 @@
#if defined(MIPS32_LE)
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#if !defined(MIPS_DSP_R2_LE)
// allpass filter coefficients.
static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528};
static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255};
+#endif
// Multiply a 32-bit value with a 16-bit value and accumulate to another input:
#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
diff --git a/webrtc/common_audio/signal_processing/resample_fractional.c b/webrtc/common_audio/signal_processing/resample_fractional.c
index 6409fba..9ffe0ac 100644
--- a/webrtc/common_audio/signal_processing/resample_fractional.c
+++ b/webrtc/common_audio/signal_processing/resample_fractional.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// interpolation coefficients
static const int16_t kCoefficients48To32[2][8] = {
diff --git a/webrtc/common_audio/signal_processing/spl_init.c b/webrtc/common_audio/signal_processing/spl_init.c
index fdab038..cf37d47 100644
--- a/webrtc/common_audio/signal_processing/spl_init.c
+++ b/webrtc/common_audio/signal_processing/spl_init.c
@@ -8,133 +8,62 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-/* The global function contained in this file initializes SPL function
- * pointers, currently only for ARM platforms.
- *
- * Some code came from common/rtcd.c in the WebM project.
- */
+// Some code came from common/rtcd.c in the WebM project.
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
-/* Declare function pointers. */
-MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16;
-MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32;
-MaxValueW16 WebRtcSpl_MaxValueW16;
-MaxValueW32 WebRtcSpl_MaxValueW32;
-MinValueW16 WebRtcSpl_MinValueW16;
-MinValueW32 WebRtcSpl_MinValueW32;
-CrossCorrelation WebRtcSpl_CrossCorrelation;
-DownsampleFast WebRtcSpl_DownsampleFast;
-ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound;
+// TODO(bugs.webrtc.org/9553): These function pointers are useless. Refactor
+// things so that we simply have a bunch of regular functions with different
+// implementations for different platforms.
-#if (defined(WEBRTC_DETECT_NEON) || !defined(WEBRTC_HAS_NEON)) && \
- !defined(MIPS32_LE)
-/* Initialize function pointers to the generic C version. */
-static void InitPointersToC() {
- WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C;
- WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
- WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C;
- WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C;
- WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C;
- WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C;
- WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationC;
- WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastC;
- WebRtcSpl_ScaleAndAddVectorsWithRound =
- WebRtcSpl_ScaleAndAddVectorsWithRoundC;
-}
-#endif
+#if defined(WEBRTC_HAS_NEON)
-#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
-/* Initialize function pointers to the Neon version. */
-static void InitPointersToNeon() {
- WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon;
- WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon;
- WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon;
- WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon;
- WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon;
- WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon;
- WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationNeon;
- WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastNeon;
- WebRtcSpl_ScaleAndAddVectorsWithRound =
- WebRtcSpl_ScaleAndAddVectorsWithRoundC;
-}
-#endif
+const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon;
+const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon;
+const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon;
+const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon;
+const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon;
+const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon;
+const CrossCorrelation WebRtcSpl_CrossCorrelation =
+ WebRtcSpl_CrossCorrelationNeon;
+const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastNeon;
+const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound =
+ WebRtcSpl_ScaleAndAddVectorsWithRoundC;
-#if defined(MIPS32_LE)
-/* Initialize function pointers to the MIPS version. */
-static void InitPointersToMIPS() {
- WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips;
- WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips;
- WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips;
- WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips;
- WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips;
- WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelation_mips;
- WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFast_mips;
-#if defined(MIPS_DSP_R1_LE)
- WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32_mips;
- WebRtcSpl_ScaleAndAddVectorsWithRound =
- WebRtcSpl_ScaleAndAddVectorsWithRound_mips;
+#elif defined(MIPS32_LE)
+
+const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips;
+const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 =
+#ifdef MIPS_DSP_R1_LE
+ WebRtcSpl_MaxAbsValueW32_mips;
#else
- WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
- WebRtcSpl_ScaleAndAddVectorsWithRound =
- WebRtcSpl_ScaleAndAddVectorsWithRoundC;
+ WebRtcSpl_MaxAbsValueW32C;
#endif
-}
+const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips;
+const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips;
+const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips;
+const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips;
+const CrossCorrelation WebRtcSpl_CrossCorrelation =
+ WebRtcSpl_CrossCorrelation_mips;
+const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFast_mips;
+const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound =
+#ifdef MIPS_DSP_R1_LE
+ WebRtcSpl_ScaleAndAddVectorsWithRound_mips;
+#else
+ WebRtcSpl_ScaleAndAddVectorsWithRoundC;
#endif
-static void InitFunctionPointers(void) {
-#if defined(WEBRTC_DETECT_NEON)
- if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
- InitPointersToNeon();
- } else {
- InitPointersToC();
- }
-#elif defined(WEBRTC_HAS_NEON)
- InitPointersToNeon();
-#elif defined(MIPS32_LE)
- InitPointersToMIPS();
#else
- InitPointersToC();
-#endif /* WEBRTC_DETECT_NEON */
-}
-#if defined(WEBRTC_POSIX)
-#include <pthread.h>
+const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C;
+const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
+const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C;
+const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C;
+const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C;
+const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C;
+const CrossCorrelation WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationC;
+const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastC;
+const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound =
+ WebRtcSpl_ScaleAndAddVectorsWithRoundC;
-static void once(void (*func)(void)) {
- static pthread_once_t lock = PTHREAD_ONCE_INIT;
- pthread_once(&lock, func);
-}
-
-#elif defined(_WIN32)
-#include <windows.h>
-
-static void once(void (*func)(void)) {
- /* Didn't use InitializeCriticalSection() since there's no race-free context
- * in which to execute it.
- *
- * TODO(kma): Change to different implementation (e.g.
- * InterlockedCompareExchangePointer) to avoid issues similar to
- * http://code.google.com/p/webm/issues/detail?id=467.
- */
- static CRITICAL_SECTION lock = {(void *)((size_t)-1), -1, 0, 0, 0, 0};
- static int done = 0;
-
- EnterCriticalSection(&lock);
- if (!done) {
- func();
- done = 1;
- }
- LeaveCriticalSection(&lock);
-}
-
-/* There's no fallback version as an #else block here to ensure thread safety.
- * In case of neither pthread for WEBRTC_POSIX nor _WIN32 is present, build
- * system should pick it up.
- */
-#endif /* WEBRTC_POSIX */
-
-void WebRtcSpl_Init() {
- once(InitFunctionPointers);
-}
+#endif
diff --git a/webrtc/common_audio/signal_processing/spl_inl.c b/webrtc/common_audio/signal_processing/spl_inl.c
new file mode 100644
index 0000000..d09e308
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/spl_inl.c
@@ -0,0 +1,24 @@
+/*
+ * 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 <stdint.h>
+
+#include "common_audio/signal_processing/include/spl_inl.h"
+
+// Table used by WebRtcSpl_CountLeadingZeros32_NotBuiltin. For each uint32_t n
+// that's a sequence of 0 bits followed by a sequence of 1 bits, the entry at
+// index (n * 0x8c0b2891) >> 26 in this table gives the number of zero bits in
+// n.
+const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64] = {
+ 32, 8, 17, -1, -1, 14, -1, -1, -1, 20, -1, -1, -1, 28, -1, 18,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 26, 25, 24,
+ 4, 11, 23, 31, 3, 7, 10, 16, 22, 30, -1, -1, 2, 6, 13, 9,
+ -1, 15, -1, 21, -1, 29, 19, -1, -1, -1, -1, -1, 1, 27, 5, 12,
+};
diff --git a/webrtc/common_audio/signal_processing/spl_sqrt.c b/webrtc/common_audio/signal_processing/spl_sqrt.c
index 24db4f8..cf9448a 100644
--- a/webrtc/common_audio/signal_processing/spl_sqrt.c
+++ b/webrtc/common_audio/signal_processing/spl_sqrt.c
@@ -15,9 +15,8 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-
-#include <assert.h>
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
int32_t WebRtcSpl_SqrtLocal(int32_t in);
@@ -139,8 +138,19 @@ int32_t WebRtcSpl_Sqrt(int32_t value)
A = value;
- if (A == 0)
- return (int32_t)0; // sqrt(0) = 0
+ // The convention in this function is to calculate sqrt(abs(A)). Negate the
+ // input if it is negative.
+ if (A < 0) {
+ if (A == WEBRTC_SPL_WORD32_MIN) {
+ // This number cannot be held in an int32_t after negating.
+ // Map it to the maximum positive value.
+ A = WEBRTC_SPL_WORD32_MAX;
+ } else {
+ A = -A;
+ }
+ } else if (A == 0) {
+ return 0; // sqrt(0) = 0
+ }
sh = WebRtcSpl_NormW32(A); // # shifts to normalize A
A = WEBRTC_SPL_LSHIFT_W32(A, sh); // Normalize A
@@ -155,7 +165,7 @@ int32_t WebRtcSpl_Sqrt(int32_t value)
x_norm = (int16_t)(A >> 16); // x_norm = AH
nshift = (sh / 2);
- assert(nshift >= 0);
+ RTC_DCHECK_GE(nshift, 0);
A = (int32_t)WEBRTC_SPL_LSHIFT_W32((int32_t)x_norm, 16);
A = WEBRTC_SPL_ABS_W32(A); // A = abs(x_norm<<16)
diff --git a/webrtc/common_audio/signal_processing/splitting_filter.c b/webrtc/common_audio/signal_processing/splitting_filter.c
index 36fcf35..399433f 100644
--- a/webrtc/common_audio/signal_processing/splitting_filter.c
+++ b/webrtc/common_audio/signal_processing/splitting_filter.c
@@ -13,9 +13,8 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-
-#include <assert.h>
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// Maximum number of samples in a low/high-band frame.
enum
@@ -136,14 +135,14 @@ void WebRtcSpl_AnalysisQMF(const int16_t* in_data, size_t in_data_length,
int32_t filter1[kMaxBandFrameLength];
int32_t filter2[kMaxBandFrameLength];
const size_t band_length = in_data_length / 2;
- assert(in_data_length % 2 == 0);
- assert(band_length <= kMaxBandFrameLength);
+ RTC_DCHECK_EQ(0, in_data_length % 2);
+ RTC_DCHECK_LE(band_length, kMaxBandFrameLength);
// Split even and odd samples. Also shift them to Q10.
for (i = 0, k = 0; i < band_length; i++, k += 2)
{
- half_in2[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)in_data[k], 10);
- half_in1[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)in_data[k + 1], 10);
+ half_in2[i] = ((int32_t)in_data[k]) * (1 << 10);
+ half_in1[i] = ((int32_t)in_data[k + 1]) * (1 << 10);
}
// All pass filter even and odd samples, independently.
@@ -175,16 +174,16 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band, const int16_t* high_band,
int32_t filter2[kMaxBandFrameLength];
size_t i;
int16_t k;
- assert(band_length <= kMaxBandFrameLength);
+ RTC_DCHECK_LE(band_length, kMaxBandFrameLength);
// Obtain the sum and difference channels out of upper and lower-band channels.
// Also shift to Q10 domain.
for (i = 0; i < band_length; i++)
{
tmp = (int32_t)low_band[i] + (int32_t)high_band[i];
- half_in1[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 10);
+ half_in1[i] = tmp * (1 << 10);
tmp = (int32_t)low_band[i] - (int32_t)high_band[i];
- half_in2[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 10);
+ half_in2[i] = tmp * (1 << 10);
}
// all-pass filter the sum and difference channels
diff --git a/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c b/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c
index ff78b52..a77fd40 100644
--- a/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c
+++ b/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c
@@ -15,7 +15,7 @@
*
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
void WebRtcSpl_SqrtOfOneMinusXSquared(int16_t *xQ15, size_t vector_length,
int16_t *yQ15)
diff --git a/webrtc/common_audio/signal_processing/vector_scaling_operations.c b/webrtc/common_audio/signal_processing/vector_scaling_operations.c
index fdefd06..7307dc7 100644
--- a/webrtc/common_audio/signal_processing/vector_scaling_operations.c
+++ b/webrtc/common_audio/signal_processing/vector_scaling_operations.c
@@ -20,7 +20,7 @@
* WebRtcSpl_ScaleAndAddVectorsWithRoundC()
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
void WebRtcSpl_VectorBitShiftW16(int16_t *res, size_t length,
const int16_t *in, int16_t right_shifts)
@@ -37,7 +37,7 @@ void WebRtcSpl_VectorBitShiftW16(int16_t *res, size_t length,
{
for (i = length; i > 0; i--)
{
- (*res++) = ((*in++) << (-right_shifts));
+ (*res++) = ((*in++) * (1 << (-right_shifts)));
}
}
}
diff --git a/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c b/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
index dd73eea..ba2d26d 100644
--- a/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
+++ b/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
@@ -14,7 +14,7 @@
* WebRtcSpl_ScaleAndAddVectorsWithRound_mips()
*/
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1,
int16_t in_vector1_scale,
diff --git a/webrtc/common_audio/smoothing_filter.cc b/webrtc/common_audio/smoothing_filter.cc
new file mode 100644
index 0000000..961f4a1
--- /dev/null
+++ b/webrtc/common_audio/smoothing_filter.cc
@@ -0,0 +1,147 @@
+/*
+ * 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 "common_audio/smoothing_filter.h"
+
+#include <math.h>
+
+#include <cmath>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+
+SmoothingFilterImpl::SmoothingFilterImpl(int init_time_ms)
+ : init_time_ms_(init_time_ms),
+ // Duing the initalization time, we use an increasing alpha. Specifically,
+ // alpha(n) = exp(-powf(init_factor_, n)),
+ // where |init_factor_| is chosen such that
+ // alpha(init_time_ms_) = exp(-1.0f / init_time_ms_),
+ init_factor_(init_time_ms_ == 0
+ ? 0.0f
+ : powf(init_time_ms_, -1.0f / init_time_ms_)),
+ // |init_const_| is to a factor to help the calculation during
+ // initialization phase.
+ init_const_(init_time_ms_ == 0
+ ? 0.0f
+ : init_time_ms_ -
+ powf(init_time_ms_, 1.0f - 1.0f / init_time_ms_)) {
+ UpdateAlpha(init_time_ms_);
+}
+
+SmoothingFilterImpl::~SmoothingFilterImpl() = default;
+
+void SmoothingFilterImpl::AddSample(float sample) {
+ const int64_t now_ms = rtc::TimeMillis();
+
+ if (!init_end_time_ms_) {
+ // This is equivalent to assuming the filter has been receiving the same
+ // value as the first sample since time -infinity.
+ state_ = last_sample_ = sample;
+ init_end_time_ms_ = now_ms + init_time_ms_;
+ last_state_time_ms_ = now_ms;
+ return;
+ }
+
+ ExtrapolateLastSample(now_ms);
+ last_sample_ = sample;
+}
+
+absl::optional<float> SmoothingFilterImpl::GetAverage() {
+ if (!init_end_time_ms_) {
+ // |init_end_time_ms_| undefined since we have not received any sample.
+ return absl::nullopt;
+ }
+ ExtrapolateLastSample(rtc::TimeMillis());
+ return state_;
+}
+
+bool SmoothingFilterImpl::SetTimeConstantMs(int time_constant_ms) {
+ if (!init_end_time_ms_ || last_state_time_ms_ < *init_end_time_ms_) {
+ return false;
+ }
+ UpdateAlpha(time_constant_ms);
+ return true;
+}
+
+void SmoothingFilterImpl::UpdateAlpha(int time_constant_ms) {
+ alpha_ = time_constant_ms == 0 ? 0.0f : std::exp(-1.0f / time_constant_ms);
+}
+
+void SmoothingFilterImpl::ExtrapolateLastSample(int64_t time_ms) {
+ RTC_DCHECK_GE(time_ms, last_state_time_ms_);
+ RTC_DCHECK(init_end_time_ms_);
+
+ float multiplier = 0.0f;
+
+ if (time_ms <= *init_end_time_ms_) {
+ // Current update is to be made during initialization phase.
+ // We update the state as if the |alpha| has been increased according
+ // alpha(n) = exp(-powf(init_factor_, n)),
+ // where n is the time (in millisecond) since the first sample received.
+ // With algebraic derivation as shown in the Appendix, we can find that the
+ // state can be updated in a similar manner as if alpha is a constant,
+ // except for a different multiplier.
+ if (init_time_ms_ == 0) {
+ // This means |init_factor_| = 0.
+ multiplier = 0.0f;
+ } else if (init_time_ms_ == 1) {
+ // This means |init_factor_| = 1.
+ multiplier = std::exp(last_state_time_ms_ - time_ms);
+ } else {
+ multiplier = std::exp(
+ -(powf(init_factor_, last_state_time_ms_ - *init_end_time_ms_) -
+ powf(init_factor_, time_ms - *init_end_time_ms_)) /
+ init_const_);
+ }
+ } else {
+ if (last_state_time_ms_ < *init_end_time_ms_) {
+ // The latest state update was made during initialization phase.
+ // We first extrapolate to the initialization time.
+ ExtrapolateLastSample(*init_end_time_ms_);
+ // Then extrapolate the rest by the following.
+ }
+ multiplier = powf(alpha_, time_ms - last_state_time_ms_);
+ }
+
+ state_ = multiplier * state_ + (1.0f - multiplier) * last_sample_;
+ last_state_time_ms_ = time_ms;
+}
+
+} // namespace webrtc
+
+// Appendix: derivation of extrapolation during initialization phase.
+// (LaTeX syntax)
+// Assuming
+// \begin{align}
+// y(n) &= \alpha_{n-1} y(n-1) + \left(1 - \alpha_{n-1}\right) x(m) \\*
+// &= \left(\prod_{i=m}^{n-1} \alpha_i\right) y(m) +
+// \left(1 - \prod_{i=m}^{n-1} \alpha_i \right) x(m)
+// \end{align}
+// Taking $\alpha_{n} = \exp(-\gamma^n)$, $\gamma$ denotes init\_factor\_, the
+// multiplier becomes
+// \begin{align}
+// \prod_{i=m}^{n-1} \alpha_i
+// &= \exp\left(-\sum_{i=m}^{n-1} \gamma^i \right) \\*
+// &= \begin{cases}
+// \exp\left(-\frac{\gamma^m - \gamma^n}{1 - \gamma} \right)
+// & \gamma \neq 1 \\*
+// m-n & \gamma = 1
+// \end{cases}
+// \end{align}
+// We know $\gamma = T^{-\frac{1}{T}}$, where $T$ denotes init\_time\_ms\_. Then
+// $1 - \gamma$ approaches zero when $T$ increases. This can cause numerical
+// difficulties. We multiply $T$ (if $T > 0$) to both numerator and denominator
+// in the fraction. See.
+// \begin{align}
+// \frac{\gamma^m - \gamma^n}{1 - \gamma}
+// &= \frac{T^\frac{T-m}{T} - T^\frac{T-n}{T}}{T - T^{1-\frac{1}{T}}}
+// \end{align}
diff --git a/webrtc/common_audio/smoothing_filter.h b/webrtc/common_audio/smoothing_filter.h
new file mode 100644
index 0000000..e96d52a
--- /dev/null
+++ b/webrtc/common_audio/smoothing_filter.h
@@ -0,0 +1,75 @@
+/*
+ * 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 COMMON_AUDIO_SMOOTHING_FILTER_H_
+#define COMMON_AUDIO_SMOOTHING_FILTER_H_
+
+#include <stdint.h>
+
+#include "absl/types/optional.h"
+
+namespace webrtc {
+
+class SmoothingFilter {
+ public:
+ virtual ~SmoothingFilter() = default;
+ virtual void AddSample(float sample) = 0;
+ virtual absl::optional<float> GetAverage() = 0;
+ virtual bool SetTimeConstantMs(int time_constant_ms) = 0;
+};
+
+// SmoothingFilterImpl applies an exponential filter
+// alpha = exp(-1.0 / time_constant_ms);
+// y[t] = alpha * y[t-1] + (1 - alpha) * sample;
+// This implies a sample rate of 1000 Hz, i.e., 1 sample / ms.
+// But SmoothingFilterImpl allows sparse samples. All missing samples will be
+// assumed to equal the last received sample.
+class SmoothingFilterImpl final : public SmoothingFilter {
+ public:
+ // |init_time_ms| is initialization time. It defines a period starting from
+ // the arriving time of the first sample. During this period, the exponential
+ // filter uses a varying time constant so that a smaller time constant will be
+ // applied to the earlier samples. This is to allow the the filter to adapt to
+ // earlier samples quickly. After the initialization period, the time constant
+ // will be set to |init_time_ms| first and can be changed through
+ // |SetTimeConstantMs|.
+ explicit SmoothingFilterImpl(int init_time_ms);
+
+ SmoothingFilterImpl() = delete;
+ SmoothingFilterImpl(const SmoothingFilterImpl&) = delete;
+ SmoothingFilterImpl& operator=(const SmoothingFilterImpl&) = delete;
+
+ ~SmoothingFilterImpl() override;
+
+ void AddSample(float sample) override;
+ absl::optional<float> GetAverage() override;
+ bool SetTimeConstantMs(int time_constant_ms) override;
+
+ // Methods used for unittests.
+ float alpha() const { return alpha_; }
+
+ private:
+ void UpdateAlpha(int time_constant_ms);
+ void ExtrapolateLastSample(int64_t time_ms);
+
+ const int init_time_ms_;
+ const float init_factor_;
+ const float init_const_;
+
+ absl::optional<int64_t> init_end_time_ms_;
+ float last_sample_;
+ float alpha_;
+ float state_;
+ int64_t last_state_time_ms_;
+};
+
+} // namespace webrtc
+
+#endif // COMMON_AUDIO_SMOOTHING_FILTER_H_
diff --git a/webrtc/common_audio/sparse_fir_filter.cc b/webrtc/common_audio/sparse_fir_filter.cc
deleted file mode 100644
index 5862b7c..0000000
--- a/webrtc/common_audio/sparse_fir_filter.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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 "webrtc/common_audio/sparse_fir_filter.h"
-
-#include "webrtc/base/checks.h"
-
-namespace webrtc {
-
-SparseFIRFilter::SparseFIRFilter(const float* nonzero_coeffs,
- size_t num_nonzero_coeffs,
- size_t sparsity,
- size_t offset)
- : sparsity_(sparsity),
- offset_(offset),
- nonzero_coeffs_(nonzero_coeffs, nonzero_coeffs + num_nonzero_coeffs),
- state_(sparsity_ * (num_nonzero_coeffs - 1) + offset_, 0.f) {
- RTC_CHECK_GE(num_nonzero_coeffs, 1u);
- RTC_CHECK_GE(sparsity, 1u);
-}
-
-void SparseFIRFilter::Filter(const float* in, size_t length, float* out) {
- // Convolves the input signal |in| with the filter kernel |nonzero_coeffs_|
- // taking into account the previous state.
- for (size_t i = 0; i < length; ++i) {
- out[i] = 0.f;
- size_t j;
- for (j = 0; i >= j * sparsity_ + offset_ &&
- j < nonzero_coeffs_.size(); ++j) {
- out[i] += in[i - j * sparsity_ - offset_] * nonzero_coeffs_[j];
- }
- for (; j < nonzero_coeffs_.size(); ++j) {
- out[i] += state_[i + (nonzero_coeffs_.size() - j - 1) * sparsity_] *
- nonzero_coeffs_[j];
- }
- }
-
- // Update current state.
- if (state_.size() > 0u) {
- if (length >= state_.size()) {
- std::memcpy(&state_[0],
- &in[length - state_.size()],
- state_.size() * sizeof(*in));
- } else {
- std::memmove(&state_[0],
- &state_[length],
- (state_.size() - length) * sizeof(state_[0]));
- std::memcpy(&state_[state_.size() - length], in, length * sizeof(*in));
- }
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/common_audio/sparse_fir_filter.h b/webrtc/common_audio/sparse_fir_filter.h
deleted file mode 100644
index 2ba5cf4..0000000
--- a/webrtc/common_audio/sparse_fir_filter.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 WEBRTC_COMMON_AUDIO_SPARSE_FIR_FILTER_H_
-#define WEBRTC_COMMON_AUDIO_SPARSE_FIR_FILTER_H_
-
-#include <cstring>
-#include <vector>
-
-#include "webrtc/base/constructormagic.h"
-
-namespace webrtc {
-
-// A Finite Impulse Response filter implementation which takes advantage of a
-// sparse structure with uniformly distributed non-zero coefficients.
-class SparseFIRFilter final {
- public:
- // |num_nonzero_coeffs| is the number of non-zero coefficients,
- // |nonzero_coeffs|. They are assumed to be uniformly distributed every
- // |sparsity| samples and with an initial |offset|. The rest of the filter
- // coefficients will be assumed zeros. For example, with sparsity = 3, and
- // offset = 1 the filter coefficients will be:
- // B = [0 coeffs[0] 0 0 coeffs[1] 0 0 coeffs[2] ... ]
- // All initial state values will be zeros.
- SparseFIRFilter(const float* nonzero_coeffs,
- size_t num_nonzero_coeffs,
- size_t sparsity,
- size_t offset);
-
- // Filters the |in| data supplied.
- // |out| must be previously allocated and it must be at least of |length|.
- void Filter(const float* in, size_t length, float* out);
-
- private:
- const size_t sparsity_;
- const size_t offset_;
- const std::vector<float> nonzero_coeffs_;
- std::vector<float> state_;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(SparseFIRFilter);
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_COMMON_AUDIO_SPARSE_FIR_FILTER_H_
diff --git a/webrtc/common_audio/third_party/ooura/BUILD.gn b/webrtc/common_audio/third_party/ooura/BUILD.gn
new file mode 100644
index 0000000..0cdf98e
--- /dev/null
+++ b/webrtc/common_audio/third_party/ooura/BUILD.gn
@@ -0,0 +1,58 @@
+# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the ../../../LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../../webrtc.gni")
+
+rtc_library("fft_size_128") {
+ sources = [
+ "fft_size_128/ooura_fft.cc",
+ "fft_size_128/ooura_fft.h",
+ "fft_size_128/ooura_fft_tables_common.h",
+ ]
+ deps = [
+ "../../../rtc_base/system:arch",
+ "../../../system_wrappers",
+ ]
+ cflags = []
+
+ if (current_cpu == "x86" || current_cpu == "x64") {
+ sources += [
+ "fft_size_128/ooura_fft_sse2.cc",
+ "fft_size_128/ooura_fft_tables_neon_sse2.h",
+ ]
+ if (is_posix || is_fuchsia) {
+ cflags += [ "-msse2" ]
+ }
+ }
+
+ if (rtc_build_with_neon) {
+ sources += [
+ "fft_size_128/ooura_fft_neon.cc",
+ "fft_size_128/ooura_fft_tables_neon_sse2.h",
+ ]
+
+ deps += [ "../../../common_audio" ]
+
+ if (current_cpu != "arm64") {
+ # Enable compilation for the NEON instruction set.
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags += [ "-mfpu=neon" ]
+ }
+ }
+
+ if (current_cpu == "mipsel" && mips_float_abi == "hard") {
+ sources += [ "fft_size_128/ooura_fft_mips.cc" ]
+ }
+}
+
+rtc_library("fft_size_256") {
+ sources = [
+ "fft_size_256/fft4g.cc",
+ "fft_size_256/fft4g.h",
+ ]
+}
diff --git a/webrtc/common_audio/third_party/ooura/LICENSE b/webrtc/common_audio/third_party/ooura/LICENSE
new file mode 100644
index 0000000..3bf870a
--- /dev/null
+++ b/webrtc/common_audio/third_party/ooura/LICENSE
@@ -0,0 +1,8 @@
+/*
+ * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
+ * Copyright Takuya OOURA, 1996-2001
+ *
+ * You may use, copy, modify and distribute this code for any purpose (include
+ * commercial use) and without fee. Please refer to this package when you modify
+ * this code.
+ */
diff --git a/webrtc/modules/audio_processing/aec/aec_rdft.c b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.cc
index 03efc10..6933120 100644
--- a/webrtc/modules/audio_processing/aec/aec_rdft.c
+++ b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.cc
@@ -10,6 +10,8 @@
* - Trivial type modifications.
* - Minimal code subset to do rdft of length 128.
* - Optimizations because of known length.
+ * - Removed the global variables by moving the code in to a class in order
+ * to make it thread safe.
*
* All changes are covered by the WebRTC license and IP grant:
* Use of this source code is governed by a BSD-style license
@@ -19,184 +21,17 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
-#include <math.h>
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h"
+#include "rtc_base/system/arch.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
-#include "webrtc/typedefs.h"
+namespace webrtc {
-// These tables used to be computed at run-time. For example, refer to:
-// https://code.google.com/p/webrtc/source/browse/trunk/webrtc/modules/audio_processing/aec/aec_rdft.c?r=6564
-// to see the initialization code.
-const float rdft_w[64] = {
- 1.0000000000f, 0.0000000000f, 0.7071067691f, 0.7071067691f,
- 0.9238795638f, 0.3826834559f, 0.3826834559f, 0.9238795638f,
- 0.9807852507f, 0.1950903237f, 0.5555702448f, 0.8314695954f,
- 0.8314695954f, 0.5555702448f, 0.1950903237f, 0.9807852507f,
- 0.9951847196f, 0.0980171412f, 0.6343933344f, 0.7730104327f,
- 0.8819212914f, 0.4713967443f, 0.2902846634f, 0.9569403529f,
- 0.9569403529f, 0.2902846634f, 0.4713967443f, 0.8819212914f,
- 0.7730104327f, 0.6343933344f, 0.0980171412f, 0.9951847196f,
- 0.7071067691f, 0.4993977249f, 0.4975923598f, 0.4945882559f,
- 0.4903926253f, 0.4850156307f, 0.4784701765f, 0.4707720280f,
- 0.4619397819f, 0.4519946277f, 0.4409606457f, 0.4288643003f,
- 0.4157347977f, 0.4016037583f, 0.3865052164f, 0.3704755902f,
- 0.3535533845f, 0.3357794881f, 0.3171966672f, 0.2978496552f,
- 0.2777851224f, 0.2570513785f, 0.2356983721f, 0.2137775421f,
- 0.1913417280f, 0.1684449315f, 0.1451423317f, 0.1214900985f,
- 0.0975451618f, 0.0733652338f, 0.0490085706f, 0.0245338380f,
-};
-const float rdft_wk3ri_first[16] = {
- 1.000000000f, 0.000000000f, 0.382683456f, 0.923879564f,
- 0.831469536f, 0.555570245f, -0.195090353f, 0.980785251f,
- 0.956940353f, 0.290284693f, 0.098017156f, 0.995184720f,
- 0.634393334f, 0.773010492f, -0.471396863f, 0.881921172f,
-};
-const float rdft_wk3ri_second[16] = {
- -0.707106769f, 0.707106769f, -0.923879564f, -0.382683456f,
- -0.980785251f, 0.195090353f, -0.555570245f, -0.831469536f,
- -0.881921172f, 0.471396863f, -0.773010492f, -0.634393334f,
- -0.995184720f, -0.098017156f, -0.290284693f, -0.956940353f,
-};
-ALIGN16_BEG const float ALIGN16_END rdft_wk1r[32] = {
- 1.000000000f, 1.000000000f, 0.707106769f, 0.707106769f,
- 0.923879564f, 0.923879564f, 0.382683456f, 0.382683456f,
- 0.980785251f, 0.980785251f, 0.555570245f, 0.555570245f,
- 0.831469595f, 0.831469595f, 0.195090324f, 0.195090324f,
- 0.995184720f, 0.995184720f, 0.634393334f, 0.634393334f,
- 0.881921291f, 0.881921291f, 0.290284663f, 0.290284663f,
- 0.956940353f, 0.956940353f, 0.471396744f, 0.471396744f,
- 0.773010433f, 0.773010433f, 0.098017141f, 0.098017141f,
-};
-ALIGN16_BEG const float ALIGN16_END rdft_wk2r[32] = {
- 1.000000000f, 1.000000000f, -0.000000000f, -0.000000000f,
- 0.707106769f, 0.707106769f, -0.707106769f, -0.707106769f,
- 0.923879564f, 0.923879564f, -0.382683456f, -0.382683456f,
- 0.382683456f, 0.382683456f, -0.923879564f, -0.923879564f,
- 0.980785251f, 0.980785251f, -0.195090324f, -0.195090324f,
- 0.555570245f, 0.555570245f, -0.831469595f, -0.831469595f,
- 0.831469595f, 0.831469595f, -0.555570245f, -0.555570245f,
- 0.195090324f, 0.195090324f, -0.980785251f, -0.980785251f,
-};
-ALIGN16_BEG const float ALIGN16_END rdft_wk3r[32] = {
- 1.000000000f, 1.000000000f, -0.707106769f, -0.707106769f,
- 0.382683456f, 0.382683456f, -0.923879564f, -0.923879564f,
- 0.831469536f, 0.831469536f, -0.980785251f, -0.980785251f,
- -0.195090353f, -0.195090353f, -0.555570245f, -0.555570245f,
- 0.956940353f, 0.956940353f, -0.881921172f, -0.881921172f,
- 0.098017156f, 0.098017156f, -0.773010492f, -0.773010492f,
- 0.634393334f, 0.634393334f, -0.995184720f, -0.995184720f,
- -0.471396863f, -0.471396863f, -0.290284693f, -0.290284693f,
-};
-ALIGN16_BEG const float ALIGN16_END rdft_wk1i[32] = {
- -0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f,
- -0.382683456f, 0.382683456f, -0.923879564f, 0.923879564f,
- -0.195090324f, 0.195090324f, -0.831469595f, 0.831469595f,
- -0.555570245f, 0.555570245f, -0.980785251f, 0.980785251f,
- -0.098017141f, 0.098017141f, -0.773010433f, 0.773010433f,
- -0.471396744f, 0.471396744f, -0.956940353f, 0.956940353f,
- -0.290284663f, 0.290284663f, -0.881921291f, 0.881921291f,
- -0.634393334f, 0.634393334f, -0.995184720f, 0.995184720f,
-};
-ALIGN16_BEG const float ALIGN16_END rdft_wk2i[32] = {
- -0.000000000f, 0.000000000f, -1.000000000f, 1.000000000f,
- -0.707106769f, 0.707106769f, -0.707106769f, 0.707106769f,
- -0.382683456f, 0.382683456f, -0.923879564f, 0.923879564f,
- -0.923879564f, 0.923879564f, -0.382683456f, 0.382683456f,
- -0.195090324f, 0.195090324f, -0.980785251f, 0.980785251f,
- -0.831469595f, 0.831469595f, -0.555570245f, 0.555570245f,
- -0.555570245f, 0.555570245f, -0.831469595f, 0.831469595f,
- -0.980785251f, 0.980785251f, -0.195090324f, 0.195090324f,
-};
-ALIGN16_BEG const float ALIGN16_END rdft_wk3i[32] = {
- -0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f,
- -0.923879564f, 0.923879564f, 0.382683456f, -0.382683456f,
- -0.555570245f, 0.555570245f, -0.195090353f, 0.195090353f,
- -0.980785251f, 0.980785251f, 0.831469536f, -0.831469536f,
- -0.290284693f, 0.290284693f, -0.471396863f, 0.471396863f,
- -0.995184720f, 0.995184720f, 0.634393334f, -0.634393334f,
- -0.773010492f, 0.773010492f, 0.098017156f, -0.098017156f,
- -0.881921172f, 0.881921172f, 0.956940353f, -0.956940353f,
-};
-ALIGN16_BEG const float ALIGN16_END cftmdl_wk1r[4] = {
- 0.707106769f, 0.707106769f, 0.707106769f, -0.707106769f,
-};
-
-static void bitrv2_128_C(float* a) {
- /*
- Following things have been attempted but are no faster:
- (a) Storing the swap indexes in a LUT (index calculations are done
- for 'free' while waiting on memory/L1).
- (b) Consolidate the load/store of two consecutive floats by a 64 bit
- integer (execution is memory/L1 bound).
- (c) Do a mix of floats and 64 bit integer to maximize register
- utilization (execution is memory/L1 bound).
- (d) Replacing ip[i] by ((k<<31)>>25) + ((k >> 1)<<5).
- (e) Hard-coding of the offsets to completely eliminates index
- calculations.
- */
-
- unsigned int j, j1, k, k1;
- float xr, xi, yr, yi;
-
- static const int ip[4] = {0, 64, 32, 96};
- for (k = 0; k < 4; k++) {
- for (j = 0; j < k; j++) {
- j1 = 2 * j + ip[k];
- k1 = 2 * k + ip[j];
- xr = a[j1 + 0];
- xi = a[j1 + 1];
- yr = a[k1 + 0];
- yi = a[k1 + 1];
- a[j1 + 0] = yr;
- a[j1 + 1] = yi;
- a[k1 + 0] = xr;
- a[k1 + 1] = xi;
- j1 += 8;
- k1 += 16;
- xr = a[j1 + 0];
- xi = a[j1 + 1];
- yr = a[k1 + 0];
- yi = a[k1 + 1];
- a[j1 + 0] = yr;
- a[j1 + 1] = yi;
- a[k1 + 0] = xr;
- a[k1 + 1] = xi;
- j1 += 8;
- k1 -= 8;
- xr = a[j1 + 0];
- xi = a[j1 + 1];
- yr = a[k1 + 0];
- yi = a[k1 + 1];
- a[j1 + 0] = yr;
- a[j1 + 1] = yi;
- a[k1 + 0] = xr;
- a[k1 + 1] = xi;
- j1 += 8;
- k1 += 16;
- xr = a[j1 + 0];
- xi = a[j1 + 1];
- yr = a[k1 + 0];
- yi = a[k1 + 1];
- a[j1 + 0] = yr;
- a[j1 + 1] = yi;
- a[k1 + 0] = xr;
- a[k1 + 1] = xi;
- }
- j1 = 2 * k + 8 + ip[k];
- k1 = j1 + 8;
- xr = a[j1 + 0];
- xi = a[j1 + 1];
- yr = a[k1 + 0];
- yi = a[k1 + 1];
- a[j1 + 0] = yr;
- a[j1 + 1] = yi;
- a[k1 + 0] = xr;
- a[k1 + 1] = xi;
- }
-}
+namespace {
+#if !(defined(MIPS_FPU_LE) || defined(WEBRTC_HAS_NEON))
static void cft1st_128_C(float* a) {
const int n = 128;
int j, k1, k2;
@@ -431,67 +266,6 @@ static void cftmdl_128_C(float* a) {
}
}
-static void cftfsub_128_C(float* a) {
- int j, j1, j2, j3, l;
- float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
-
- cft1st_128(a);
- cftmdl_128(a);
- l = 32;
- for (j = 0; j < l; j += 2) {
- j1 = j + l;
- j2 = j1 + l;
- j3 = j2 + l;
- x0r = a[j] + a[j1];
- x0i = a[j + 1] + a[j1 + 1];
- x1r = a[j] - a[j1];
- x1i = a[j + 1] - a[j1 + 1];
- x2r = a[j2] + a[j3];
- x2i = a[j2 + 1] + a[j3 + 1];
- x3r = a[j2] - a[j3];
- x3i = a[j2 + 1] - a[j3 + 1];
- a[j] = x0r + x2r;
- a[j + 1] = x0i + x2i;
- a[j2] = x0r - x2r;
- a[j2 + 1] = x0i - x2i;
- a[j1] = x1r - x3i;
- a[j1 + 1] = x1i + x3r;
- a[j3] = x1r + x3i;
- a[j3 + 1] = x1i - x3r;
- }
-}
-
-static void cftbsub_128_C(float* a) {
- int j, j1, j2, j3, l;
- float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
-
- cft1st_128(a);
- cftmdl_128(a);
- l = 32;
-
- for (j = 0; j < l; j += 2) {
- j1 = j + l;
- j2 = j1 + l;
- j3 = j2 + l;
- x0r = a[j] + a[j1];
- x0i = -a[j + 1] - a[j1 + 1];
- x1r = a[j] - a[j1];
- x1i = -a[j + 1] + a[j1 + 1];
- x2r = a[j2] + a[j3];
- x2i = a[j2 + 1] + a[j3 + 1];
- x3r = a[j2] - a[j3];
- x3i = a[j2 + 1] - a[j3 + 1];
- a[j] = x0r + x2r;
- a[j + 1] = x0i - x2i;
- a[j2] = x0r - x2r;
- a[j2 + 1] = x0i + x2i;
- a[j1] = x1r - x3i;
- a[j1 + 1] = x1i - x3r;
- a[j3] = x1r + x3i;
- a[j3 + 1] = x1i + x3r;
- }
-}
-
static void rftfsub_128_C(float* a) {
const float* c = rdft_w + 32;
int j1, j2, k1, k2;
@@ -535,8 +309,29 @@ static void rftbsub_128_C(float* a) {
}
a[65] = -a[65];
}
+#endif
+
+} // namespace
+
+OouraFft::OouraFft(bool sse2_available) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ use_sse2_ = sse2_available;
+#else
+ use_sse2_ = false;
+#endif
+}
-void aec_rdft_forward_128(float* a) {
+OouraFft::OouraFft() {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ use_sse2_ = (GetCPUInfo(kSSE2) != 0);
+#else
+ use_sse2_ = false;
+#endif
+}
+
+OouraFft::~OouraFft() = default;
+
+void OouraFft::Fft(float* a) const {
float xi;
bitrv2_128(a);
cftfsub_128(a);
@@ -545,8 +340,7 @@ void aec_rdft_forward_128(float* a) {
a[0] += a[1];
a[1] = xi;
}
-
-void aec_rdft_inverse_128(float* a) {
+void OouraFft::InverseFft(float* a) const {
a[1] = 0.5f * (a[0] - a[1]);
a[0] -= a[1];
rftbsub_128(a);
@@ -554,36 +348,201 @@ void aec_rdft_inverse_128(float* a) {
cftbsub_128(a);
}
-// code path selection
-RftSub128 cft1st_128;
-RftSub128 cftmdl_128;
-RftSub128 rftfsub_128;
-RftSub128 rftbsub_128;
-RftSub128 cftfsub_128;
-RftSub128 cftbsub_128;
-RftSub128 bitrv2_128;
-
-void aec_rdft_init(void) {
- cft1st_128 = cft1st_128_C;
- cftmdl_128 = cftmdl_128_C;
- rftfsub_128 = rftfsub_128_C;
- rftbsub_128 = rftbsub_128_C;
- cftfsub_128 = cftfsub_128_C;
- cftbsub_128 = cftbsub_128_C;
- bitrv2_128 = bitrv2_128_C;
-#if defined(WEBRTC_ARCH_X86_FAMILY)
- if (WebRtc_GetCPUInfo(kSSE2)) {
- aec_rdft_init_sse2();
+void OouraFft::cft1st_128(float* a) const {
+#if defined(MIPS_FPU_LE)
+ cft1st_128_mips(a);
+#elif defined(WEBRTC_HAS_NEON)
+ cft1st_128_neon(a);
+#elif defined(WEBRTC_ARCH_X86_FAMILY)
+ if (use_sse2_) {
+ cft1st_128_SSE2(a);
+ } else {
+ cft1st_128_C(a);
}
+#else
+ cft1st_128_C(a);
#endif
+}
+void OouraFft::cftmdl_128(float* a) const {
#if defined(MIPS_FPU_LE)
- aec_rdft_init_mips();
+ cftmdl_128_mips(a);
+#elif defined(WEBRTC_HAS_NEON)
+ cftmdl_128_neon(a);
+#elif defined(WEBRTC_ARCH_X86_FAMILY)
+ if (use_sse2_) {
+ cftmdl_128_SSE2(a);
+ } else {
+ cftmdl_128_C(a);
+ }
+#else
+ cftmdl_128_C(a);
#endif
-#if defined(WEBRTC_HAS_NEON)
- aec_rdft_init_neon();
-#elif defined(WEBRTC_DETECT_NEON)
- if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
- aec_rdft_init_neon();
+}
+void OouraFft::rftfsub_128(float* a) const {
+#if defined(MIPS_FPU_LE)
+ rftfsub_128_mips(a);
+#elif defined(WEBRTC_HAS_NEON)
+ rftfsub_128_neon(a);
+#elif defined(WEBRTC_ARCH_X86_FAMILY)
+ if (use_sse2_) {
+ rftfsub_128_SSE2(a);
+ } else {
+ rftfsub_128_C(a);
+ }
+#else
+ rftfsub_128_C(a);
+#endif
+}
+
+void OouraFft::rftbsub_128(float* a) const {
+#if defined(MIPS_FPU_LE)
+ rftbsub_128_mips(a);
+#elif defined(WEBRTC_HAS_NEON)
+ rftbsub_128_neon(a);
+#elif defined(WEBRTC_ARCH_X86_FAMILY)
+ if (use_sse2_) {
+ rftbsub_128_SSE2(a);
+ } else {
+ rftbsub_128_C(a);
}
+#else
+ rftbsub_128_C(a);
#endif
}
+
+void OouraFft::cftbsub_128(float* a) const {
+ int j, j1, j2, j3, l;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ cft1st_128(a);
+ cftmdl_128(a);
+ l = 32;
+
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = -a[j + 1] - a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = -a[j + 1] + a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i - x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i + x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i - x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i + x3r;
+ }
+}
+
+void OouraFft::cftfsub_128(float* a) const {
+ int j, j1, j2, j3, l;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ cft1st_128(a);
+ cftmdl_128(a);
+ l = 32;
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i - x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ }
+}
+
+void OouraFft::bitrv2_128(float* a) const {
+ /*
+ Following things have been attempted but are no faster:
+ (a) Storing the swap indexes in a LUT (index calculations are done
+ for 'free' while waiting on memory/L1).
+ (b) Consolidate the load/store of two consecutive floats by a 64 bit
+ integer (execution is memory/L1 bound).
+ (c) Do a mix of floats and 64 bit integer to maximize register
+ utilization (execution is memory/L1 bound).
+ (d) Replacing ip[i] by ((k<<31)>>25) + ((k >> 1)<<5).
+ (e) Hard-coding of the offsets to completely eliminates index
+ calculations.
+ */
+
+ unsigned int j, j1, k, k1;
+ float xr, xi, yr, yi;
+
+ const int ip[4] = {0, 64, 32, 96};
+ for (k = 0; k < 4; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1 + 0];
+ xi = a[j1 + 1];
+ yr = a[k1 + 0];
+ yi = a[k1 + 1];
+ a[j1 + 0] = yr;
+ a[j1 + 1] = yi;
+ a[k1 + 0] = xr;
+ a[k1 + 1] = xi;
+ j1 += 8;
+ k1 += 16;
+ xr = a[j1 + 0];
+ xi = a[j1 + 1];
+ yr = a[k1 + 0];
+ yi = a[k1 + 1];
+ a[j1 + 0] = yr;
+ a[j1 + 1] = yi;
+ a[k1 + 0] = xr;
+ a[k1 + 1] = xi;
+ j1 += 8;
+ k1 -= 8;
+ xr = a[j1 + 0];
+ xi = a[j1 + 1];
+ yr = a[k1 + 0];
+ yi = a[k1 + 1];
+ a[j1 + 0] = yr;
+ a[j1 + 1] = yi;
+ a[k1 + 0] = xr;
+ a[k1 + 1] = xi;
+ j1 += 8;
+ k1 += 16;
+ xr = a[j1 + 0];
+ xi = a[j1 + 1];
+ yr = a[k1 + 0];
+ yi = a[k1 + 1];
+ a[j1 + 0] = yr;
+ a[j1 + 1] = yi;
+ a[k1 + 0] = xr;
+ a[k1 + 1] = xi;
+ }
+ j1 = 2 * k + 8 + ip[k];
+ k1 = j1 + 8;
+ xr = a[j1 + 0];
+ xi = a[j1 + 1];
+ yr = a[k1 + 0];
+ yi = a[k1 + 1];
+ a[j1 + 0] = yr;
+ a[j1 + 1] = yi;
+ a[k1 + 0] = xr;
+ a[k1 + 1] = xi;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.h b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.h
new file mode 100644
index 0000000..8273dfe
--- /dev/null
+++ b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.h
@@ -0,0 +1,64 @@
+/*
+ * 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_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_
+
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+void cft1st_128_SSE2(float* a);
+void cftmdl_128_SSE2(float* a);
+void rftfsub_128_SSE2(float* a);
+void rftbsub_128_SSE2(float* a);
+#endif
+
+#if defined(MIPS_FPU_LE)
+void cft1st_128_mips(float* a);
+void cftmdl_128_mips(float* a);
+void rftfsub_128_mips(float* a);
+void rftbsub_128_mips(float* a);
+#endif
+
+#if defined(WEBRTC_HAS_NEON)
+void cft1st_128_neon(float* a);
+void cftmdl_128_neon(float* a);
+void rftfsub_128_neon(float* a);
+void rftbsub_128_neon(float* a);
+#endif
+
+class OouraFft {
+ public:
+ // Ctor allowing the availability of SSE2 support to be specified.
+ explicit OouraFft(bool sse2_available);
+
+ // Deprecated: This Ctor will soon be removed.
+ OouraFft();
+ ~OouraFft();
+ void Fft(float* a) const;
+ void InverseFft(float* a) const;
+
+ private:
+ void cft1st_128(float* a) const;
+ void cftmdl_128(float* a) const;
+ void rftfsub_128(float* a) const;
+ void rftbsub_128(float* a) const;
+
+ void cftfsub_128(float* a) const;
+ void cftbsub_128(float* a) const;
+ void bitrv2_128(float* a) const;
+ bool use_sse2_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_
diff --git a/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc
new file mode 100644
index 0000000..4c231e3
--- /dev/null
+++ b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc
@@ -0,0 +1,1245 @@
+/*
+ * 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 "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h"
+
+namespace webrtc {
+
+#if defined(MIPS_FPU_LE)
+void bitrv2_128_mips(float* a) {
+ // n is 128
+ float xr, xi, yr, yi;
+
+ xr = a[8];
+ xi = a[9];
+ yr = a[16];
+ yi = a[17];
+ a[8] = yr;
+ a[9] = yi;
+ a[16] = xr;
+ a[17] = xi;
+
+ xr = a[64];
+ xi = a[65];
+ yr = a[2];
+ yi = a[3];
+ a[64] = yr;
+ a[65] = yi;
+ a[2] = xr;
+ a[3] = xi;
+
+ xr = a[72];
+ xi = a[73];
+ yr = a[18];
+ yi = a[19];
+ a[72] = yr;
+ a[73] = yi;
+ a[18] = xr;
+ a[19] = xi;
+
+ xr = a[80];
+ xi = a[81];
+ yr = a[10];
+ yi = a[11];
+ a[80] = yr;
+ a[81] = yi;
+ a[10] = xr;
+ a[11] = xi;
+
+ xr = a[88];
+ xi = a[89];
+ yr = a[26];
+ yi = a[27];
+ a[88] = yr;
+ a[89] = yi;
+ a[26] = xr;
+ a[27] = xi;
+
+ xr = a[74];
+ xi = a[75];
+ yr = a[82];
+ yi = a[83];
+ a[74] = yr;
+ a[75] = yi;
+ a[82] = xr;
+ a[83] = xi;
+
+ xr = a[32];
+ xi = a[33];
+ yr = a[4];
+ yi = a[5];
+ a[32] = yr;
+ a[33] = yi;
+ a[4] = xr;
+ a[5] = xi;
+
+ xr = a[40];
+ xi = a[41];
+ yr = a[20];
+ yi = a[21];
+ a[40] = yr;
+ a[41] = yi;
+ a[20] = xr;
+ a[21] = xi;
+
+ xr = a[48];
+ xi = a[49];
+ yr = a[12];
+ yi = a[13];
+ a[48] = yr;
+ a[49] = yi;
+ a[12] = xr;
+ a[13] = xi;
+
+ xr = a[56];
+ xi = a[57];
+ yr = a[28];
+ yi = a[29];
+ a[56] = yr;
+ a[57] = yi;
+ a[28] = xr;
+ a[29] = xi;
+
+ xr = a[34];
+ xi = a[35];
+ yr = a[68];
+ yi = a[69];
+ a[34] = yr;
+ a[35] = yi;
+ a[68] = xr;
+ a[69] = xi;
+
+ xr = a[42];
+ xi = a[43];
+ yr = a[84];
+ yi = a[85];
+ a[42] = yr;
+ a[43] = yi;
+ a[84] = xr;
+ a[85] = xi;
+
+ xr = a[50];
+ xi = a[51];
+ yr = a[76];
+ yi = a[77];
+ a[50] = yr;
+ a[51] = yi;
+ a[76] = xr;
+ a[77] = xi;
+
+ xr = a[58];
+ xi = a[59];
+ yr = a[92];
+ yi = a[93];
+ a[58] = yr;
+ a[59] = yi;
+ a[92] = xr;
+ a[93] = xi;
+
+ xr = a[44];
+ xi = a[45];
+ yr = a[52];
+ yi = a[53];
+ a[44] = yr;
+ a[45] = yi;
+ a[52] = xr;
+ a[53] = xi;
+
+ xr = a[96];
+ xi = a[97];
+ yr = a[6];
+ yi = a[7];
+ a[96] = yr;
+ a[97] = yi;
+ a[6] = xr;
+ a[7] = xi;
+
+ xr = a[104];
+ xi = a[105];
+ yr = a[22];
+ yi = a[23];
+ a[104] = yr;
+ a[105] = yi;
+ a[22] = xr;
+ a[23] = xi;
+
+ xr = a[112];
+ xi = a[113];
+ yr = a[14];
+ yi = a[15];
+ a[112] = yr;
+ a[113] = yi;
+ a[14] = xr;
+ a[15] = xi;
+
+ xr = a[120];
+ xi = a[121];
+ yr = a[30];
+ yi = a[31];
+ a[120] = yr;
+ a[121] = yi;
+ a[30] = xr;
+ a[31] = xi;
+
+ xr = a[98];
+ xi = a[99];
+ yr = a[70];
+ yi = a[71];
+ a[98] = yr;
+ a[99] = yi;
+ a[70] = xr;
+ a[71] = xi;
+
+ xr = a[106];
+ xi = a[107];
+ yr = a[86];
+ yi = a[87];
+ a[106] = yr;
+ a[107] = yi;
+ a[86] = xr;
+ a[87] = xi;
+
+ xr = a[114];
+ xi = a[115];
+ yr = a[78];
+ yi = a[79];
+ a[114] = yr;
+ a[115] = yi;
+ a[78] = xr;
+ a[79] = xi;
+
+ xr = a[122];
+ xi = a[123];
+ yr = a[94];
+ yi = a[95];
+ a[122] = yr;
+ a[123] = yi;
+ a[94] = xr;
+ a[95] = xi;
+
+ xr = a[100];
+ xi = a[101];
+ yr = a[38];
+ yi = a[39];
+ a[100] = yr;
+ a[101] = yi;
+ a[38] = xr;
+ a[39] = xi;
+
+ xr = a[108];
+ xi = a[109];
+ yr = a[54];
+ yi = a[55];
+ a[108] = yr;
+ a[109] = yi;
+ a[54] = xr;
+ a[55] = xi;
+
+ xr = a[116];
+ xi = a[117];
+ yr = a[46];
+ yi = a[47];
+ a[116] = yr;
+ a[117] = yi;
+ a[46] = xr;
+ a[47] = xi;
+
+ xr = a[124];
+ xi = a[125];
+ yr = a[62];
+ yi = a[63];
+ a[124] = yr;
+ a[125] = yi;
+ a[62] = xr;
+ a[63] = xi;
+
+ xr = a[110];
+ xi = a[111];
+ yr = a[118];
+ yi = a[119];
+ a[110] = yr;
+ a[111] = yi;
+ a[118] = xr;
+ a[119] = xi;
+}
+
+void cft1st_128_mips(float* a) {
+ float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14;
+ int a_ptr, p1_rdft, p2_rdft, count;
+ const float* first = rdft_wk3ri_first;
+ const float* second = rdft_wk3ri_second;
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ // first 8
+ "lwc1 %[f0], 0(%[a]) \n\t"
+ "lwc1 %[f1], 4(%[a]) \n\t"
+ "lwc1 %[f2], 8(%[a]) \n\t"
+ "lwc1 %[f3], 12(%[a]) \n\t"
+ "lwc1 %[f4], 16(%[a]) \n\t"
+ "lwc1 %[f5], 20(%[a]) \n\t"
+ "lwc1 %[f6], 24(%[a]) \n\t"
+ "lwc1 %[f7], 28(%[a]) \n\t"
+ "add.s %[f8], %[f0], %[f2] \n\t"
+ "sub.s %[f0], %[f0], %[f2] \n\t"
+ "add.s %[f2], %[f4], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "add.s %[f6], %[f1], %[f3] \n\t"
+ "sub.s %[f1], %[f1], %[f3] \n\t"
+ "add.s %[f3], %[f5], %[f7] \n\t"
+ "sub.s %[f5], %[f5], %[f7] \n\t"
+ "add.s %[f7], %[f8], %[f2] \n\t"
+ "sub.s %[f8], %[f8], %[f2] \n\t"
+ "sub.s %[f2], %[f1], %[f4] \n\t"
+ "add.s %[f1], %[f1], %[f4] \n\t"
+ "add.s %[f4], %[f6], %[f3] \n\t"
+ "sub.s %[f6], %[f6], %[f3] \n\t"
+ "sub.s %[f3], %[f0], %[f5] \n\t"
+ "add.s %[f0], %[f0], %[f5] \n\t"
+ "swc1 %[f7], 0(%[a]) \n\t"
+ "swc1 %[f8], 16(%[a]) \n\t"
+ "swc1 %[f2], 28(%[a]) \n\t"
+ "swc1 %[f1], 12(%[a]) \n\t"
+ "swc1 %[f4], 4(%[a]) \n\t"
+ "swc1 %[f6], 20(%[a]) \n\t"
+ "swc1 %[f3], 8(%[a]) \n\t"
+ "swc1 %[f0], 24(%[a]) \n\t"
+ // second 8
+ "lwc1 %[f0], 32(%[a]) \n\t"
+ "lwc1 %[f1], 36(%[a]) \n\t"
+ "lwc1 %[f2], 40(%[a]) \n\t"
+ "lwc1 %[f3], 44(%[a]) \n\t"
+ "lwc1 %[f4], 48(%[a]) \n\t"
+ "lwc1 %[f5], 52(%[a]) \n\t"
+ "lwc1 %[f6], 56(%[a]) \n\t"
+ "lwc1 %[f7], 60(%[a]) \n\t"
+ "add.s %[f8], %[f4], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "add.s %[f6], %[f1], %[f3] \n\t"
+ "sub.s %[f1], %[f1], %[f3] \n\t"
+ "add.s %[f3], %[f0], %[f2] \n\t"
+ "sub.s %[f0], %[f0], %[f2] \n\t"
+ "add.s %[f2], %[f5], %[f7] \n\t"
+ "sub.s %[f5], %[f5], %[f7] \n\t"
+ "add.s %[f7], %[f4], %[f1] \n\t"
+ "sub.s %[f4], %[f4], %[f1] \n\t"
+ "add.s %[f1], %[f3], %[f8] \n\t"
+ "sub.s %[f3], %[f3], %[f8] \n\t"
+ "sub.s %[f8], %[f0], %[f5] \n\t"
+ "add.s %[f0], %[f0], %[f5] \n\t"
+ "add.s %[f5], %[f6], %[f2] \n\t"
+ "sub.s %[f6], %[f2], %[f6] \n\t"
+ "lwc1 %[f9], 8(%[rdft_w]) \n\t"
+ "sub.s %[f2], %[f8], %[f7] \n\t"
+ "add.s %[f8], %[f8], %[f7] \n\t"
+ "sub.s %[f7], %[f4], %[f0] \n\t"
+ "add.s %[f4], %[f4], %[f0] \n\t"
+ // prepare for loop
+ "addiu %[a_ptr], %[a], 64 \n\t"
+ "addiu %[p1_rdft], %[rdft_w], 8 \n\t"
+ "addiu %[p2_rdft], %[rdft_w], 16 \n\t"
+ "addiu %[count], $zero, 7 \n\t"
+ // finish second 8
+ "mul.s %[f2], %[f9], %[f2] \n\t"
+ "mul.s %[f8], %[f9], %[f8] \n\t"
+ "mul.s %[f7], %[f9], %[f7] \n\t"
+ "mul.s %[f4], %[f9], %[f4] \n\t"
+ "swc1 %[f1], 32(%[a]) \n\t"
+ "swc1 %[f3], 52(%[a]) \n\t"
+ "swc1 %[f5], 36(%[a]) \n\t"
+ "swc1 %[f6], 48(%[a]) \n\t"
+ "swc1 %[f2], 40(%[a]) \n\t"
+ "swc1 %[f8], 44(%[a]) \n\t"
+ "swc1 %[f7], 56(%[a]) \n\t"
+ "swc1 %[f4], 60(%[a]) \n\t"
+ // loop
+ "1: \n\t"
+ "lwc1 %[f0], 0(%[a_ptr]) \n\t"
+ "lwc1 %[f1], 4(%[a_ptr]) \n\t"
+ "lwc1 %[f2], 8(%[a_ptr]) \n\t"
+ "lwc1 %[f3], 12(%[a_ptr]) \n\t"
+ "lwc1 %[f4], 16(%[a_ptr]) \n\t"
+ "lwc1 %[f5], 20(%[a_ptr]) \n\t"
+ "lwc1 %[f6], 24(%[a_ptr]) \n\t"
+ "lwc1 %[f7], 28(%[a_ptr]) \n\t"
+ "add.s %[f8], %[f0], %[f2] \n\t"
+ "sub.s %[f0], %[f0], %[f2] \n\t"
+ "add.s %[f2], %[f4], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "add.s %[f6], %[f1], %[f3] \n\t"
+ "sub.s %[f1], %[f1], %[f3] \n\t"
+ "add.s %[f3], %[f5], %[f7] \n\t"
+ "sub.s %[f5], %[f5], %[f7] \n\t"
+ "lwc1 %[f10], 4(%[p1_rdft]) \n\t"
+ "lwc1 %[f11], 0(%[p2_rdft]) \n\t"
+ "lwc1 %[f12], 4(%[p2_rdft]) \n\t"
+ "lwc1 %[f13], 8(%[first]) \n\t"
+ "lwc1 %[f14], 12(%[first]) \n\t"
+ "add.s %[f7], %[f8], %[f2] \n\t"
+ "sub.s %[f8], %[f8], %[f2] \n\t"
+ "add.s %[f2], %[f6], %[f3] \n\t"
+ "sub.s %[f6], %[f6], %[f3] \n\t"
+ "add.s %[f3], %[f0], %[f5] \n\t"
+ "sub.s %[f0], %[f0], %[f5] \n\t"
+ "add.s %[f5], %[f1], %[f4] \n\t"
+ "sub.s %[f1], %[f1], %[f4] \n\t"
+ "swc1 %[f7], 0(%[a_ptr]) \n\t"
+ "swc1 %[f2], 4(%[a_ptr]) \n\t"
+ "mul.s %[f4], %[f9], %[f8] \n\t"
+#if defined(MIPS32_R2_LE)
+ "mul.s %[f8], %[f10], %[f8] \n\t"
+ "mul.s %[f7], %[f11], %[f0] \n\t"
+ "mul.s %[f0], %[f12], %[f0] \n\t"
+ "mul.s %[f2], %[f13], %[f3] \n\t"
+ "mul.s %[f3], %[f14], %[f3] \n\t"
+ "nmsub.s %[f4], %[f4], %[f10], %[f6] \n\t"
+ "madd.s %[f8], %[f8], %[f9], %[f6] \n\t"
+ "nmsub.s %[f7], %[f7], %[f12], %[f5] \n\t"
+ "madd.s %[f0], %[f0], %[f11], %[f5] \n\t"
+ "nmsub.s %[f2], %[f2], %[f14], %[f1] \n\t"
+ "madd.s %[f3], %[f3], %[f13], %[f1] \n\t"
+#else
+ "mul.s %[f7], %[f10], %[f6] \n\t"
+ "mul.s %[f6], %[f9], %[f6] \n\t"
+ "mul.s %[f8], %[f10], %[f8] \n\t"
+ "mul.s %[f2], %[f11], %[f0] \n\t"
+ "mul.s %[f11], %[f11], %[f5] \n\t"
+ "mul.s %[f5], %[f12], %[f5] \n\t"
+ "mul.s %[f0], %[f12], %[f0] \n\t"
+ "mul.s %[f12], %[f13], %[f3] \n\t"
+ "mul.s %[f13], %[f13], %[f1] \n\t"
+ "mul.s %[f1], %[f14], %[f1] \n\t"
+ "mul.s %[f3], %[f14], %[f3] \n\t"
+ "sub.s %[f4], %[f4], %[f7] \n\t"
+ "add.s %[f8], %[f6], %[f8] \n\t"
+ "sub.s %[f7], %[f2], %[f5] \n\t"
+ "add.s %[f0], %[f11], %[f0] \n\t"
+ "sub.s %[f2], %[f12], %[f1] \n\t"
+ "add.s %[f3], %[f13], %[f3] \n\t"
+#endif
+ "swc1 %[f4], 16(%[a_ptr]) \n\t"
+ "swc1 %[f8], 20(%[a_ptr]) \n\t"
+ "swc1 %[f7], 8(%[a_ptr]) \n\t"
+ "swc1 %[f0], 12(%[a_ptr]) \n\t"
+ "swc1 %[f2], 24(%[a_ptr]) \n\t"
+ "swc1 %[f3], 28(%[a_ptr]) \n\t"
+ "lwc1 %[f0], 32(%[a_ptr]) \n\t"
+ "lwc1 %[f1], 36(%[a_ptr]) \n\t"
+ "lwc1 %[f2], 40(%[a_ptr]) \n\t"
+ "lwc1 %[f3], 44(%[a_ptr]) \n\t"
+ "lwc1 %[f4], 48(%[a_ptr]) \n\t"
+ "lwc1 %[f5], 52(%[a_ptr]) \n\t"
+ "lwc1 %[f6], 56(%[a_ptr]) \n\t"
+ "lwc1 %[f7], 60(%[a_ptr]) \n\t"
+ "add.s %[f8], %[f0], %[f2] \n\t"
+ "sub.s %[f0], %[f0], %[f2] \n\t"
+ "add.s %[f2], %[f4], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "add.s %[f6], %[f1], %[f3] \n\t"
+ "sub.s %[f1], %[f1], %[f3] \n\t"
+ "add.s %[f3], %[f5], %[f7] \n\t"
+ "sub.s %[f5], %[f5], %[f7] \n\t"
+ "lwc1 %[f11], 8(%[p2_rdft]) \n\t"
+ "lwc1 %[f12], 12(%[p2_rdft]) \n\t"
+ "lwc1 %[f13], 8(%[second]) \n\t"
+ "lwc1 %[f14], 12(%[second]) \n\t"
+ "add.s %[f7], %[f8], %[f2] \n\t"
+ "sub.s %[f8], %[f2], %[f8] \n\t"
+ "add.s %[f2], %[f6], %[f3] \n\t"
+ "sub.s %[f6], %[f3], %[f6] \n\t"
+ "add.s %[f3], %[f0], %[f5] \n\t"
+ "sub.s %[f0], %[f0], %[f5] \n\t"
+ "add.s %[f5], %[f1], %[f4] \n\t"
+ "sub.s %[f1], %[f1], %[f4] \n\t"
+ "swc1 %[f7], 32(%[a_ptr]) \n\t"
+ "swc1 %[f2], 36(%[a_ptr]) \n\t"
+ "mul.s %[f4], %[f10], %[f8] \n\t"
+#if defined(MIPS32_R2_LE)
+ "mul.s %[f10], %[f10], %[f6] \n\t"
+ "mul.s %[f7], %[f11], %[f0] \n\t"
+ "mul.s %[f11], %[f11], %[f5] \n\t"
+ "mul.s %[f2], %[f13], %[f3] \n\t"
+ "mul.s %[f13], %[f13], %[f1] \n\t"
+ "madd.s %[f4], %[f4], %[f9], %[f6] \n\t"
+ "nmsub.s %[f10], %[f10], %[f9], %[f8] \n\t"
+ "nmsub.s %[f7], %[f7], %[f12], %[f5] \n\t"
+ "madd.s %[f11], %[f11], %[f12], %[f0] \n\t"
+ "nmsub.s %[f2], %[f2], %[f14], %[f1] \n\t"
+ "madd.s %[f13], %[f13], %[f14], %[f3] \n\t"
+#else
+ "mul.s %[f2], %[f9], %[f6] \n\t"
+ "mul.s %[f10], %[f10], %[f6] \n\t"
+ "mul.s %[f9], %[f9], %[f8] \n\t"
+ "mul.s %[f7], %[f11], %[f0] \n\t"
+ "mul.s %[f8], %[f12], %[f5] \n\t"
+ "mul.s %[f11], %[f11], %[f5] \n\t"
+ "mul.s %[f12], %[f12], %[f0] \n\t"
+ "mul.s %[f5], %[f13], %[f3] \n\t"
+ "mul.s %[f0], %[f14], %[f1] \n\t"
+ "mul.s %[f13], %[f13], %[f1] \n\t"
+ "mul.s %[f14], %[f14], %[f3] \n\t"
+ "add.s %[f4], %[f4], %[f2] \n\t"
+ "sub.s %[f10], %[f10], %[f9] \n\t"
+ "sub.s %[f7], %[f7], %[f8] \n\t"
+ "add.s %[f11], %[f11], %[f12] \n\t"
+ "sub.s %[f2], %[f5], %[f0] \n\t"
+ "add.s %[f13], %[f13], %[f14] \n\t"
+#endif
+ "swc1 %[f4], 48(%[a_ptr]) \n\t"
+ "swc1 %[f10], 52(%[a_ptr]) \n\t"
+ "swc1 %[f7], 40(%[a_ptr]) \n\t"
+ "swc1 %[f11], 44(%[a_ptr]) \n\t"
+ "swc1 %[f2], 56(%[a_ptr]) \n\t"
+ "swc1 %[f13], 60(%[a_ptr]) \n\t"
+ "addiu %[count], %[count], -1 \n\t"
+ "lwc1 %[f9], 8(%[p1_rdft]) \n\t"
+ "addiu %[a_ptr], %[a_ptr], 64 \n\t"
+ "addiu %[p1_rdft], %[p1_rdft], 8 \n\t"
+ "addiu %[p2_rdft], %[p2_rdft], 16 \n\t"
+ "addiu %[first], %[first], 8 \n\t"
+ "bgtz %[count], 1b \n\t"
+ " addiu %[second], %[second], 8 \n\t"
+ ".set pop \n\t"
+ : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+ [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+ [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11),
+ [f12] "=&f"(f12), [f13] "=&f"(f13), [f14] "=&f"(f14),
+ [a_ptr] "=&r"(a_ptr), [p1_rdft] "=&r"(p1_rdft), [first] "+r"(first),
+ [p2_rdft] "=&r"(p2_rdft), [count] "=&r"(count), [second] "+r"(second)
+ : [a] "r"(a), [rdft_w] "r"(rdft_w)
+ : "memory");
+}
+
+void cftmdl_128_mips(float* a) {
+ float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14;
+ int tmp_a, count;
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[tmp_a], %[a], 0 \n\t"
+ "addiu %[count], $zero, 4 \n\t"
+ "1: \n\t"
+ "addiu %[count], %[count], -1 \n\t"
+ "lwc1 %[f0], 0(%[tmp_a]) \n\t"
+ "lwc1 %[f2], 32(%[tmp_a]) \n\t"
+ "lwc1 %[f4], 64(%[tmp_a]) \n\t"
+ "lwc1 %[f6], 96(%[tmp_a]) \n\t"
+ "lwc1 %[f1], 4(%[tmp_a]) \n\t"
+ "lwc1 %[f3], 36(%[tmp_a]) \n\t"
+ "lwc1 %[f5], 68(%[tmp_a]) \n\t"
+ "lwc1 %[f7], 100(%[tmp_a]) \n\t"
+ "add.s %[f8], %[f0], %[f2] \n\t"
+ "sub.s %[f0], %[f0], %[f2] \n\t"
+ "add.s %[f2], %[f4], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "add.s %[f6], %[f1], %[f3] \n\t"
+ "sub.s %[f1], %[f1], %[f3] \n\t"
+ "add.s %[f3], %[f5], %[f7] \n\t"
+ "sub.s %[f5], %[f5], %[f7] \n\t"
+ "add.s %[f7], %[f8], %[f2] \n\t"
+ "sub.s %[f8], %[f8], %[f2] \n\t"
+ "add.s %[f2], %[f1], %[f4] \n\t"
+ "sub.s %[f1], %[f1], %[f4] \n\t"
+ "add.s %[f4], %[f6], %[f3] \n\t"
+ "sub.s %[f6], %[f6], %[f3] \n\t"
+ "sub.s %[f3], %[f0], %[f5] \n\t"
+ "add.s %[f0], %[f0], %[f5] \n\t"
+ "swc1 %[f7], 0(%[tmp_a]) \n\t"
+ "swc1 %[f8], 64(%[tmp_a]) \n\t"
+ "swc1 %[f2], 36(%[tmp_a]) \n\t"
+ "swc1 %[f1], 100(%[tmp_a]) \n\t"
+ "swc1 %[f4], 4(%[tmp_a]) \n\t"
+ "swc1 %[f6], 68(%[tmp_a]) \n\t"
+ "swc1 %[f3], 32(%[tmp_a]) \n\t"
+ "swc1 %[f0], 96(%[tmp_a]) \n\t"
+ "bgtz %[count], 1b \n\t"
+ " addiu %[tmp_a], %[tmp_a], 8 \n\t"
+ ".set pop \n\t"
+ : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+ [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+ [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+ : [a] "r"(a)
+ : "memory");
+ f9 = rdft_w[2];
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[tmp_a], %[a], 128 \n\t"
+ "addiu %[count], $zero, 4 \n\t"
+ "1: \n\t"
+ "addiu %[count], %[count], -1 \n\t"
+ "lwc1 %[f0], 0(%[tmp_a]) \n\t"
+ "lwc1 %[f2], 32(%[tmp_a]) \n\t"
+ "lwc1 %[f5], 68(%[tmp_a]) \n\t"
+ "lwc1 %[f7], 100(%[tmp_a]) \n\t"
+ "lwc1 %[f1], 4(%[tmp_a]) \n\t"
+ "lwc1 %[f3], 36(%[tmp_a]) \n\t"
+ "lwc1 %[f4], 64(%[tmp_a]) \n\t"
+ "lwc1 %[f6], 96(%[tmp_a]) \n\t"
+ "sub.s %[f8], %[f0], %[f2] \n\t"
+ "add.s %[f0], %[f0], %[f2] \n\t"
+ "sub.s %[f2], %[f5], %[f7] \n\t"
+ "add.s %[f5], %[f5], %[f7] \n\t"
+ "sub.s %[f7], %[f1], %[f3] \n\t"
+ "add.s %[f1], %[f1], %[f3] \n\t"
+ "sub.s %[f3], %[f4], %[f6] \n\t"
+ "add.s %[f4], %[f4], %[f6] \n\t"
+ "sub.s %[f6], %[f8], %[f2] \n\t"
+ "add.s %[f8], %[f8], %[f2] \n\t"
+ "add.s %[f2], %[f5], %[f1] \n\t"
+ "sub.s %[f5], %[f5], %[f1] \n\t"
+ "add.s %[f1], %[f3], %[f7] \n\t"
+ "sub.s %[f3], %[f3], %[f7] \n\t"
+ "add.s %[f7], %[f0], %[f4] \n\t"
+ "sub.s %[f0], %[f0], %[f4] \n\t"
+ "sub.s %[f4], %[f6], %[f1] \n\t"
+ "add.s %[f6], %[f6], %[f1] \n\t"
+ "sub.s %[f1], %[f3], %[f8] \n\t"
+ "add.s %[f3], %[f3], %[f8] \n\t"
+ "mul.s %[f4], %[f4], %[f9] \n\t"
+ "mul.s %[f6], %[f6], %[f9] \n\t"
+ "mul.s %[f1], %[f1], %[f9] \n\t"
+ "mul.s %[f3], %[f3], %[f9] \n\t"
+ "swc1 %[f7], 0(%[tmp_a]) \n\t"
+ "swc1 %[f2], 4(%[tmp_a]) \n\t"
+ "swc1 %[f5], 64(%[tmp_a]) \n\t"
+ "swc1 %[f0], 68(%[tmp_a]) \n\t"
+ "swc1 %[f4], 32(%[tmp_a]) \n\t"
+ "swc1 %[f6], 36(%[tmp_a]) \n\t"
+ "swc1 %[f1], 96(%[tmp_a]) \n\t"
+ "swc1 %[f3], 100(%[tmp_a]) \n\t"
+ "bgtz %[count], 1b \n\t"
+ " addiu %[tmp_a], %[tmp_a], 8 \n\t"
+ ".set pop \n\t"
+ : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+ [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+ [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+ : [a] "r"(a), [f9] "f"(f9)
+ : "memory");
+ f10 = rdft_w[3];
+ f11 = rdft_w[4];
+ f12 = rdft_w[5];
+ f13 = rdft_wk3ri_first[2];
+ f14 = rdft_wk3ri_first[3];
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[tmp_a], %[a], 256 \n\t"
+ "addiu %[count], $zero, 4 \n\t"
+ "1: \n\t"
+ "addiu %[count], %[count], -1 \n\t"
+ "lwc1 %[f0], 0(%[tmp_a]) \n\t"
+ "lwc1 %[f2], 32(%[tmp_a]) \n\t"
+ "lwc1 %[f4], 64(%[tmp_a]) \n\t"
+ "lwc1 %[f6], 96(%[tmp_a]) \n\t"
+ "lwc1 %[f1], 4(%[tmp_a]) \n\t"
+ "lwc1 %[f3], 36(%[tmp_a]) \n\t"
+ "lwc1 %[f5], 68(%[tmp_a]) \n\t"
+ "lwc1 %[f7], 100(%[tmp_a]) \n\t"
+ "add.s %[f8], %[f0], %[f2] \n\t"
+ "sub.s %[f0], %[f0], %[f2] \n\t"
+ "add.s %[f2], %[f4], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "add.s %[f6], %[f1], %[f3] \n\t"
+ "sub.s %[f1], %[f1], %[f3] \n\t"
+ "add.s %[f3], %[f5], %[f7] \n\t"
+ "sub.s %[f5], %[f5], %[f7] \n\t"
+ "sub.s %[f7], %[f8], %[f2] \n\t"
+ "add.s %[f8], %[f8], %[f2] \n\t"
+ "add.s %[f2], %[f1], %[f4] \n\t"
+ "sub.s %[f1], %[f1], %[f4] \n\t"
+ "sub.s %[f4], %[f6], %[f3] \n\t"
+ "add.s %[f6], %[f6], %[f3] \n\t"
+ "sub.s %[f3], %[f0], %[f5] \n\t"
+ "add.s %[f0], %[f0], %[f5] \n\t"
+ "swc1 %[f8], 0(%[tmp_a]) \n\t"
+ "swc1 %[f6], 4(%[tmp_a]) \n\t"
+ "mul.s %[f5], %[f9], %[f7] \n\t"
+#if defined(MIPS32_R2_LE)
+ "mul.s %[f7], %[f10], %[f7] \n\t"
+ "mul.s %[f8], %[f11], %[f3] \n\t"
+ "mul.s %[f3], %[f12], %[f3] \n\t"
+ "mul.s %[f6], %[f13], %[f0] \n\t"
+ "mul.s %[f0], %[f14], %[f0] \n\t"
+ "nmsub.s %[f5], %[f5], %[f10], %[f4] \n\t"
+ "madd.s %[f7], %[f7], %[f9], %[f4] \n\t"
+ "nmsub.s %[f8], %[f8], %[f12], %[f2] \n\t"
+ "madd.s %[f3], %[f3], %[f11], %[f2] \n\t"
+ "nmsub.s %[f6], %[f6], %[f14], %[f1] \n\t"
+ "madd.s %[f0], %[f0], %[f13], %[f1] \n\t"
+ "swc1 %[f5], 64(%[tmp_a]) \n\t"
+ "swc1 %[f7], 68(%[tmp_a]) \n\t"
+#else
+ "mul.s %[f8], %[f10], %[f4] \n\t"
+ "mul.s %[f4], %[f9], %[f4] \n\t"
+ "mul.s %[f7], %[f10], %[f7] \n\t"
+ "mul.s %[f6], %[f11], %[f3] \n\t"
+ "mul.s %[f3], %[f12], %[f3] \n\t"
+ "sub.s %[f5], %[f5], %[f8] \n\t"
+ "mul.s %[f8], %[f12], %[f2] \n\t"
+ "mul.s %[f2], %[f11], %[f2] \n\t"
+ "add.s %[f7], %[f4], %[f7] \n\t"
+ "mul.s %[f4], %[f13], %[f0] \n\t"
+ "mul.s %[f0], %[f14], %[f0] \n\t"
+ "sub.s %[f8], %[f6], %[f8] \n\t"
+ "mul.s %[f6], %[f14], %[f1] \n\t"
+ "mul.s %[f1], %[f13], %[f1] \n\t"
+ "add.s %[f3], %[f2], %[f3] \n\t"
+ "swc1 %[f5], 64(%[tmp_a]) \n\t"
+ "swc1 %[f7], 68(%[tmp_a]) \n\t"
+ "sub.s %[f6], %[f4], %[f6] \n\t"
+ "add.s %[f0], %[f1], %[f0] \n\t"
+#endif
+ "swc1 %[f8], 32(%[tmp_a]) \n\t"
+ "swc1 %[f3], 36(%[tmp_a]) \n\t"
+ "swc1 %[f6], 96(%[tmp_a]) \n\t"
+ "swc1 %[f0], 100(%[tmp_a]) \n\t"
+ "bgtz %[count], 1b \n\t"
+ " addiu %[tmp_a], %[tmp_a], 8 \n\t"
+ ".set pop \n\t"
+ : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+ [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+ [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+ : [a] "r"(a), [f9] "f"(f9), [f10] "f"(f10), [f11] "f"(f11),
+ [f12] "f"(f12), [f13] "f"(f13), [f14] "f"(f14)
+ : "memory");
+ f11 = rdft_w[6];
+ f12 = rdft_w[7];
+ f13 = rdft_wk3ri_second[2];
+ f14 = rdft_wk3ri_second[3];
+ __asm __volatile(
+ ".set push "
+ "\n\t"
+ ".set noreorder "
+ "\n\t"
+ "addiu %[tmp_a], %[a], 384 "
+ "\n\t"
+ "addiu %[count], $zero, 4 "
+ "\n\t"
+ "1: "
+ "\n\t"
+ "addiu %[count], %[count], -1 "
+ "\n\t"
+ "lwc1 %[f0], 0(%[tmp_a]) "
+ "\n\t"
+ "lwc1 %[f1], 4(%[tmp_a]) "
+ "\n\t"
+ "lwc1 %[f2], 32(%[tmp_a]) "
+ "\n\t"
+ "lwc1 %[f3], 36(%[tmp_a]) "
+ "\n\t"
+ "lwc1 %[f4], 64(%[tmp_a]) "
+ "\n\t"
+ "lwc1 %[f5], 68(%[tmp_a]) "
+ "\n\t"
+ "lwc1 %[f6], 96(%[tmp_a]) "
+ "\n\t"
+ "lwc1 %[f7], 100(%[tmp_a]) "
+ "\n\t"
+ "add.s %[f8], %[f0], %[f2] "
+ "\n\t"
+ "sub.s %[f0], %[f0], %[f2] "
+ "\n\t"
+ "add.s %[f2], %[f4], %[f6] "
+ "\n\t"
+ "sub.s %[f4], %[f4], %[f6] "
+ "\n\t"
+ "add.s %[f6], %[f1], %[f3] "
+ "\n\t"
+ "sub.s %[f1], %[f1], %[f3] "
+ "\n\t"
+ "add.s %[f3], %[f5], %[f7] "
+ "\n\t"
+ "sub.s %[f5], %[f5], %[f7] "
+ "\n\t"
+ "sub.s %[f7], %[f2], %[f8] "
+ "\n\t"
+ "add.s %[f2], %[f2], %[f8] "
+ "\n\t"
+ "add.s %[f8], %[f1], %[f4] "
+ "\n\t"
+ "sub.s %[f1], %[f1], %[f4] "
+ "\n\t"
+ "sub.s %[f4], %[f3], %[f6] "
+ "\n\t"
+ "add.s %[f3], %[f3], %[f6] "
+ "\n\t"
+ "sub.s %[f6], %[f0], %[f5] "
+ "\n\t"
+ "add.s %[f0], %[f0], %[f5] "
+ "\n\t"
+ "swc1 %[f2], 0(%[tmp_a]) "
+ "\n\t"
+ "swc1 %[f3], 4(%[tmp_a]) "
+ "\n\t"
+ "mul.s %[f5], %[f10], %[f7] "
+ "\n\t"
+#if defined(MIPS32_R2_LE)
+ "mul.s %[f7], %[f9], %[f7] "
+ "\n\t"
+ "mul.s %[f2], %[f12], %[f8] "
+ "\n\t"
+ "mul.s %[f8], %[f11], %[f8] "
+ "\n\t"
+ "mul.s %[f3], %[f14], %[f1] "
+ "\n\t"
+ "mul.s %[f1], %[f13], %[f1] "
+ "\n\t"
+ "madd.s %[f5], %[f5], %[f9], %[f4] "
+ "\n\t"
+ "msub.s %[f7], %[f7], %[f10], %[f4] "
+ "\n\t"
+ "msub.s %[f2], %[f2], %[f11], %[f6] "
+ "\n\t"
+ "madd.s %[f8], %[f8], %[f12], %[f6] "
+ "\n\t"
+ "msub.s %[f3], %[f3], %[f13], %[f0] "
+ "\n\t"
+ "madd.s %[f1], %[f1], %[f14], %[f0] "
+ "\n\t"
+ "swc1 %[f5], 64(%[tmp_a]) "
+ "\n\t"
+ "swc1 %[f7], 68(%[tmp_a]) "
+ "\n\t"
+#else
+ "mul.s %[f2], %[f9], %[f4] "
+ "\n\t"
+ "mul.s %[f4], %[f10], %[f4] "
+ "\n\t"
+ "mul.s %[f7], %[f9], %[f7] "
+ "\n\t"
+ "mul.s %[f3], %[f11], %[f6] "
+ "\n\t"
+ "mul.s %[f6], %[f12], %[f6] "
+ "\n\t"
+ "add.s %[f5], %[f5], %[f2] "
+ "\n\t"
+ "sub.s %[f7], %[f4], %[f7] "
+ "\n\t"
+ "mul.s %[f2], %[f12], %[f8] "
+ "\n\t"
+ "mul.s %[f8], %[f11], %[f8] "
+ "\n\t"
+ "mul.s %[f4], %[f14], %[f1] "
+ "\n\t"
+ "mul.s %[f1], %[f13], %[f1] "
+ "\n\t"
+ "sub.s %[f2], %[f3], %[f2] "
+ "\n\t"
+ "mul.s %[f3], %[f13], %[f0] "
+ "\n\t"
+ "mul.s %[f0], %[f14], %[f0] "
+ "\n\t"
+ "add.s %[f8], %[f8], %[f6] "
+ "\n\t"
+ "swc1 %[f5], 64(%[tmp_a]) "
+ "\n\t"
+ "swc1 %[f7], 68(%[tmp_a]) "
+ "\n\t"
+ "sub.s %[f3], %[f3], %[f4] "
+ "\n\t"
+ "add.s %[f1], %[f1], %[f0] "
+ "\n\t"
+#endif
+ "swc1 %[f2], 32(%[tmp_a]) "
+ "\n\t"
+ "swc1 %[f8], 36(%[tmp_a]) "
+ "\n\t"
+ "swc1 %[f3], 96(%[tmp_a]) "
+ "\n\t"
+ "swc1 %[f1], 100(%[tmp_a]) "
+ "\n\t"
+ "bgtz %[count], 1b "
+ "\n\t"
+ " addiu %[tmp_a], %[tmp_a], 8 "
+ "\n\t"
+ ".set pop "
+ "\n\t"
+ : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+ [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+ [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+ : [a] "r"(a), [f9] "f"(f9), [f10] "f"(f10), [f11] "f"(f11),
+ [f12] "f"(f12), [f13] "f"(f13), [f14] "f"(f14)
+ : "memory");
+}
+
+void cftfsub_128_mips(float* a) {
+ float f0, f1, f2, f3, f4, f5, f6, f7, f8;
+ int tmp_a, count;
+
+ cft1st_128_mips(a);
+ cftmdl_128_mips(a);
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[tmp_a], %[a], 0 \n\t"
+ "addiu %[count], $zero, 16 \n\t"
+ "1: \n\t"
+ "addiu %[count], %[count], -1 \n\t"
+ "lwc1 %[f0], 0(%[tmp_a]) \n\t"
+ "lwc1 %[f2], 128(%[tmp_a]) \n\t"
+ "lwc1 %[f4], 256(%[tmp_a]) \n\t"
+ "lwc1 %[f6], 384(%[tmp_a]) \n\t"
+ "lwc1 %[f1], 4(%[tmp_a]) \n\t"
+ "lwc1 %[f3], 132(%[tmp_a]) \n\t"
+ "lwc1 %[f5], 260(%[tmp_a]) \n\t"
+ "lwc1 %[f7], 388(%[tmp_a]) \n\t"
+ "add.s %[f8], %[f0], %[f2] \n\t"
+ "sub.s %[f0], %[f0], %[f2] \n\t"
+ "add.s %[f2], %[f4], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "add.s %[f6], %[f1], %[f3] \n\t"
+ "sub.s %[f1], %[f1], %[f3] \n\t"
+ "add.s %[f3], %[f5], %[f7] \n\t"
+ "sub.s %[f5], %[f5], %[f7] \n\t"
+ "add.s %[f7], %[f8], %[f2] \n\t"
+ "sub.s %[f8], %[f8], %[f2] \n\t"
+ "add.s %[f2], %[f1], %[f4] \n\t"
+ "sub.s %[f1], %[f1], %[f4] \n\t"
+ "add.s %[f4], %[f6], %[f3] \n\t"
+ "sub.s %[f6], %[f6], %[f3] \n\t"
+ "sub.s %[f3], %[f0], %[f5] \n\t"
+ "add.s %[f0], %[f0], %[f5] \n\t"
+ "swc1 %[f7], 0(%[tmp_a]) \n\t"
+ "swc1 %[f8], 256(%[tmp_a]) \n\t"
+ "swc1 %[f2], 132(%[tmp_a]) \n\t"
+ "swc1 %[f1], 388(%[tmp_a]) \n\t"
+ "swc1 %[f4], 4(%[tmp_a]) \n\t"
+ "swc1 %[f6], 260(%[tmp_a]) \n\t"
+ "swc1 %[f3], 128(%[tmp_a]) \n\t"
+ "swc1 %[f0], 384(%[tmp_a]) \n\t"
+ "bgtz %[count], 1b \n\t"
+ " addiu %[tmp_a], %[tmp_a], 8 \n\t"
+ ".set pop \n\t"
+ : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+ [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+ [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+ : [a] "r"(a)
+ : "memory");
+}
+
+void cftbsub_128_mips(float* a) {
+ float f0, f1, f2, f3, f4, f5, f6, f7, f8;
+ int tmp_a, count;
+
+ cft1st_128_mips(a);
+ cftmdl_128_mips(a);
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[tmp_a], %[a], 0 \n\t"
+ "addiu %[count], $zero, 16 \n\t"
+ "1: \n\t"
+ "addiu %[count], %[count], -1 \n\t"
+ "lwc1 %[f0], 0(%[tmp_a]) \n\t"
+ "lwc1 %[f2], 128(%[tmp_a]) \n\t"
+ "lwc1 %[f4], 256(%[tmp_a]) \n\t"
+ "lwc1 %[f6], 384(%[tmp_a]) \n\t"
+ "lwc1 %[f1], 4(%[tmp_a]) \n\t"
+ "lwc1 %[f3], 132(%[tmp_a]) \n\t"
+ "lwc1 %[f5], 260(%[tmp_a]) \n\t"
+ "lwc1 %[f7], 388(%[tmp_a]) \n\t"
+ "add.s %[f8], %[f0], %[f2] \n\t"
+ "sub.s %[f0], %[f0], %[f2] \n\t"
+ "add.s %[f2], %[f4], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "add.s %[f6], %[f1], %[f3] \n\t"
+ "sub.s %[f1], %[f3], %[f1] \n\t"
+ "add.s %[f3], %[f5], %[f7] \n\t"
+ "sub.s %[f5], %[f5], %[f7] \n\t"
+ "add.s %[f7], %[f8], %[f2] \n\t"
+ "sub.s %[f8], %[f8], %[f2] \n\t"
+ "sub.s %[f2], %[f1], %[f4] \n\t"
+ "add.s %[f1], %[f1], %[f4] \n\t"
+ "add.s %[f4], %[f3], %[f6] \n\t"
+ "sub.s %[f6], %[f3], %[f6] \n\t"
+ "sub.s %[f3], %[f0], %[f5] \n\t"
+ "add.s %[f0], %[f0], %[f5] \n\t"
+ "neg.s %[f4], %[f4] \n\t"
+ "swc1 %[f7], 0(%[tmp_a]) \n\t"
+ "swc1 %[f8], 256(%[tmp_a]) \n\t"
+ "swc1 %[f2], 132(%[tmp_a]) \n\t"
+ "swc1 %[f1], 388(%[tmp_a]) \n\t"
+ "swc1 %[f6], 260(%[tmp_a]) \n\t"
+ "swc1 %[f3], 128(%[tmp_a]) \n\t"
+ "swc1 %[f0], 384(%[tmp_a]) \n\t"
+ "swc1 %[f4], 4(%[tmp_a]) \n\t"
+ "bgtz %[count], 1b \n\t"
+ " addiu %[tmp_a], %[tmp_a], 8 \n\t"
+ ".set pop \n\t"
+ : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3),
+ [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7),
+ [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count)
+ : [a] "r"(a)
+ : "memory");
+}
+
+void rftfsub_128_mips(float* a) {
+ const float* c = rdft_w + 32;
+ const float f0 = 0.5f;
+ float* a1 = &a[2];
+ float* a2 = &a[126];
+ const float* c1 = &c[1];
+ const float* c2 = &c[31];
+ float f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
+ int count;
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "lwc1 %[f6], 0(%[c2]) \n\t"
+ "lwc1 %[f1], 0(%[a1]) \n\t"
+ "lwc1 %[f2], 0(%[a2]) \n\t"
+ "lwc1 %[f3], 4(%[a1]) \n\t"
+ "lwc1 %[f4], 4(%[a2]) \n\t"
+ "lwc1 %[f5], 0(%[c1]) \n\t"
+ "sub.s %[f6], %[f0], %[f6] \n\t"
+ "sub.s %[f7], %[f1], %[f2] \n\t"
+ "add.s %[f8], %[f3], %[f4] \n\t"
+ "addiu %[count], $zero, 15 \n\t"
+ "mul.s %[f9], %[f6], %[f7] \n\t"
+ "mul.s %[f6], %[f6], %[f8] \n\t"
+#if !defined(MIPS32_R2_LE)
+ "mul.s %[f8], %[f5], %[f8] \n\t"
+ "mul.s %[f5], %[f5], %[f7] \n\t"
+ "sub.s %[f9], %[f9], %[f8] \n\t"
+ "add.s %[f6], %[f6], %[f5] \n\t"
+#else
+ "nmsub.s %[f9], %[f9], %[f5], %[f8] \n\t"
+ "madd.s %[f6], %[f6], %[f5], %[f7] \n\t"
+#endif
+ "sub.s %[f1], %[f1], %[f9] \n\t"
+ "add.s %[f2], %[f2], %[f9] \n\t"
+ "sub.s %[f3], %[f3], %[f6] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "swc1 %[f1], 0(%[a1]) \n\t"
+ "swc1 %[f2], 0(%[a2]) \n\t"
+ "swc1 %[f3], 4(%[a1]) \n\t"
+ "swc1 %[f4], 4(%[a2]) \n\t"
+ "addiu %[a1], %[a1], 8 \n\t"
+ "addiu %[a2], %[a2], -8 \n\t"
+ "addiu %[c1], %[c1], 4 \n\t"
+ "addiu %[c2], %[c2], -4 \n\t"
+ "1: \n\t"
+ "lwc1 %[f6], 0(%[c2]) \n\t"
+ "lwc1 %[f1], 0(%[a1]) \n\t"
+ "lwc1 %[f2], 0(%[a2]) \n\t"
+ "lwc1 %[f3], 4(%[a1]) \n\t"
+ "lwc1 %[f4], 4(%[a2]) \n\t"
+ "lwc1 %[f5], 0(%[c1]) \n\t"
+ "sub.s %[f6], %[f0], %[f6] \n\t"
+ "sub.s %[f7], %[f1], %[f2] \n\t"
+ "add.s %[f8], %[f3], %[f4] \n\t"
+ "lwc1 %[f10], -4(%[c2]) \n\t"
+ "lwc1 %[f11], 8(%[a1]) \n\t"
+ "lwc1 %[f12], -8(%[a2]) \n\t"
+ "mul.s %[f9], %[f6], %[f7] \n\t"
+ "mul.s %[f6], %[f6], %[f8] \n\t"
+#if !defined(MIPS32_R2_LE)
+ "mul.s %[f8], %[f5], %[f8] \n\t"
+ "mul.s %[f5], %[f5], %[f7] \n\t"
+ "lwc1 %[f13], 12(%[a1]) \n\t"
+ "lwc1 %[f14], -4(%[a2]) \n\t"
+ "lwc1 %[f15], 4(%[c1]) \n\t"
+ "sub.s %[f9], %[f9], %[f8] \n\t"
+ "add.s %[f6], %[f6], %[f5] \n\t"
+#else
+ "lwc1 %[f13], 12(%[a1]) \n\t"
+ "lwc1 %[f14], -4(%[a2]) \n\t"
+ "lwc1 %[f15], 4(%[c1]) \n\t"
+ "nmsub.s %[f9], %[f9], %[f5], %[f8] \n\t"
+ "madd.s %[f6], %[f6], %[f5], %[f7] \n\t"
+#endif
+ "sub.s %[f10], %[f0], %[f10] \n\t"
+ "sub.s %[f5], %[f11], %[f12] \n\t"
+ "add.s %[f7], %[f13], %[f14] \n\t"
+ "sub.s %[f1], %[f1], %[f9] \n\t"
+ "add.s %[f2], %[f2], %[f9] \n\t"
+ "sub.s %[f3], %[f3], %[f6] \n\t"
+ "mul.s %[f8], %[f10], %[f5] \n\t"
+ "mul.s %[f10], %[f10], %[f7] \n\t"
+#if !defined(MIPS32_R2_LE)
+ "mul.s %[f9], %[f15], %[f7] \n\t"
+ "mul.s %[f15], %[f15], %[f5] \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "swc1 %[f1], 0(%[a1]) \n\t"
+ "swc1 %[f2], 0(%[a2]) \n\t"
+ "sub.s %[f8], %[f8], %[f9] \n\t"
+ "add.s %[f10], %[f10], %[f15] \n\t"
+#else
+ "swc1 %[f1], 0(%[a1]) \n\t"
+ "swc1 %[f2], 0(%[a2]) \n\t"
+ "sub.s %[f4], %[f4], %[f6] \n\t"
+ "nmsub.s %[f8], %[f8], %[f15], %[f7] \n\t"
+ "madd.s %[f10], %[f10], %[f15], %[f5] \n\t"
+#endif
+ "swc1 %[f3], 4(%[a1]) \n\t"
+ "swc1 %[f4], 4(%[a2]) \n\t"
+ "sub.s %[f11], %[f11], %[f8] \n\t"
+ "add.s %[f12], %[f12], %[f8] \n\t"
+ "sub.s %[f13], %[f13], %[f10] \n\t"
+ "sub.s %[f14], %[f14], %[f10] \n\t"
+ "addiu %[c2], %[c2], -8 \n\t"
+ "addiu %[c1], %[c1], 8 \n\t"
+ "swc1 %[f11], 8(%[a1]) \n\t"
+ "swc1 %[f12], -8(%[a2]) \n\t"
+ "swc1 %[f13], 12(%[a1]) \n\t"
+ "swc1 %[f14], -4(%[a2]) \n\t"
+ "addiu %[a1], %[a1], 16 \n\t"
+ "addiu %[count], %[count], -1 \n\t"
+ "bgtz %[count], 1b \n\t"
+ " addiu %[a2], %[a2], -16 \n\t"
+ ".set pop \n\t"
+ : [a1] "+r"(a1), [a2] "+r"(a2), [c1] "+r"(c1), [c2] "+r"(c2),
+ [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4),
+ [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8),
+ [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12),
+ [f13] "=&f"(f13), [f14] "=&f"(f14), [f15] "=&f"(f15),
+ [count] "=&r"(count)
+ : [f0] "f"(f0)
+ : "memory");
+}
+
+void rftbsub_128_mips(float* a) {
+ const float* c = rdft_w + 32;
+ const float f0 = 0.5f;
+ float* a1 = &a[2];
+ float* a2 = &a[126];
+ const float* c1 = &c[1];
+ const float* c2 = &c[31];
+ float f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
+ int count;
+
+ a[1] = -a[1];
+ a[65] = -a[65];
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "lwc1 %[f6], 0(%[c2]) \n\t"
+ "lwc1 %[f1], 0(%[a1]) \n\t"
+ "lwc1 %[f2], 0(%[a2]) \n\t"
+ "lwc1 %[f3], 4(%[a1]) \n\t"
+ "lwc1 %[f4], 4(%[a2]) \n\t"
+ "lwc1 %[f5], 0(%[c1]) \n\t"
+ "sub.s %[f6], %[f0], %[f6] \n\t"
+ "sub.s %[f7], %[f1], %[f2] \n\t"
+ "add.s %[f8], %[f3], %[f4] \n\t"
+ "addiu %[count], $zero, 15 \n\t"
+ "mul.s %[f9], %[f6], %[f7] \n\t"
+ "mul.s %[f6], %[f6], %[f8] \n\t"
+#if !defined(MIPS32_R2_LE)
+ "mul.s %[f8], %[f5], %[f8] \n\t"
+ "mul.s %[f5], %[f5], %[f7] \n\t"
+ "add.s %[f9], %[f9], %[f8] \n\t"
+ "sub.s %[f6], %[f6], %[f5] \n\t"
+#else
+ "madd.s %[f9], %[f9], %[f5], %[f8] \n\t"
+ "nmsub.s %[f6], %[f6], %[f5], %[f7] \n\t"
+#endif
+ "sub.s %[f1], %[f1], %[f9] \n\t"
+ "add.s %[f2], %[f2], %[f9] \n\t"
+ "sub.s %[f3], %[f6], %[f3] \n\t"
+ "sub.s %[f4], %[f6], %[f4] \n\t"
+ "swc1 %[f1], 0(%[a1]) \n\t"
+ "swc1 %[f2], 0(%[a2]) \n\t"
+ "swc1 %[f3], 4(%[a1]) \n\t"
+ "swc1 %[f4], 4(%[a2]) \n\t"
+ "addiu %[a1], %[a1], 8 \n\t"
+ "addiu %[a2], %[a2], -8 \n\t"
+ "addiu %[c1], %[c1], 4 \n\t"
+ "addiu %[c2], %[c2], -4 \n\t"
+ "1: \n\t"
+ "lwc1 %[f6], 0(%[c2]) \n\t"
+ "lwc1 %[f1], 0(%[a1]) \n\t"
+ "lwc1 %[f2], 0(%[a2]) \n\t"
+ "lwc1 %[f3], 4(%[a1]) \n\t"
+ "lwc1 %[f4], 4(%[a2]) \n\t"
+ "lwc1 %[f5], 0(%[c1]) \n\t"
+ "sub.s %[f6], %[f0], %[f6] \n\t"
+ "sub.s %[f7], %[f1], %[f2] \n\t"
+ "add.s %[f8], %[f3], %[f4] \n\t"
+ "lwc1 %[f10], -4(%[c2]) \n\t"
+ "lwc1 %[f11], 8(%[a1]) \n\t"
+ "lwc1 %[f12], -8(%[a2]) \n\t"
+ "mul.s %[f9], %[f6], %[f7] \n\t"
+ "mul.s %[f6], %[f6], %[f8] \n\t"
+#if !defined(MIPS32_R2_LE)
+ "mul.s %[f8], %[f5], %[f8] \n\t"
+ "mul.s %[f5], %[f5], %[f7] \n\t"
+ "lwc1 %[f13], 12(%[a1]) \n\t"
+ "lwc1 %[f14], -4(%[a2]) \n\t"
+ "lwc1 %[f15], 4(%[c1]) \n\t"
+ "add.s %[f9], %[f9], %[f8] \n\t"
+ "sub.s %[f6], %[f6], %[f5] \n\t"
+#else
+ "lwc1 %[f13], 12(%[a1]) \n\t"
+ "lwc1 %[f14], -4(%[a2]) \n\t"
+ "lwc1 %[f15], 4(%[c1]) \n\t"
+ "madd.s %[f9], %[f9], %[f5], %[f8] \n\t"
+ "nmsub.s %[f6], %[f6], %[f5], %[f7] \n\t"
+#endif
+ "sub.s %[f10], %[f0], %[f10] \n\t"
+ "sub.s %[f5], %[f11], %[f12] \n\t"
+ "add.s %[f7], %[f13], %[f14] \n\t"
+ "sub.s %[f1], %[f1], %[f9] \n\t"
+ "add.s %[f2], %[f2], %[f9] \n\t"
+ "sub.s %[f3], %[f6], %[f3] \n\t"
+ "mul.s %[f8], %[f10], %[f5] \n\t"
+ "mul.s %[f10], %[f10], %[f7] \n\t"
+#if !defined(MIPS32_R2_LE)
+ "mul.s %[f9], %[f15], %[f7] \n\t"
+ "mul.s %[f15], %[f15], %[f5] \n\t"
+ "sub.s %[f4], %[f6], %[f4] \n\t"
+ "swc1 %[f1], 0(%[a1]) \n\t"
+ "swc1 %[f2], 0(%[a2]) \n\t"
+ "add.s %[f8], %[f8], %[f9] \n\t"
+ "sub.s %[f10], %[f10], %[f15] \n\t"
+#else
+ "swc1 %[f1], 0(%[a1]) \n\t"
+ "swc1 %[f2], 0(%[a2]) \n\t"
+ "sub.s %[f4], %[f6], %[f4] \n\t"
+ "madd.s %[f8], %[f8], %[f15], %[f7] \n\t"
+ "nmsub.s %[f10], %[f10], %[f15], %[f5] \n\t"
+#endif
+ "swc1 %[f3], 4(%[a1]) \n\t"
+ "swc1 %[f4], 4(%[a2]) \n\t"
+ "sub.s %[f11], %[f11], %[f8] \n\t"
+ "add.s %[f12], %[f12], %[f8] \n\t"
+ "sub.s %[f13], %[f10], %[f13] \n\t"
+ "sub.s %[f14], %[f10], %[f14] \n\t"
+ "addiu %[c2], %[c2], -8 \n\t"
+ "addiu %[c1], %[c1], 8 \n\t"
+ "swc1 %[f11], 8(%[a1]) \n\t"
+ "swc1 %[f12], -8(%[a2]) \n\t"
+ "swc1 %[f13], 12(%[a1]) \n\t"
+ "swc1 %[f14], -4(%[a2]) \n\t"
+ "addiu %[a1], %[a1], 16 \n\t"
+ "addiu %[count], %[count], -1 \n\t"
+ "bgtz %[count], 1b \n\t"
+ " addiu %[a2], %[a2], -16 \n\t"
+ ".set pop \n\t"
+ : [a1] "+r"(a1), [a2] "+r"(a2), [c1] "+r"(c1), [c2] "+r"(c2),
+ [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4),
+ [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8),
+ [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12),
+ [f13] "=&f"(f13), [f14] "=&f"(f14), [f15] "=&f"(f15),
+ [count] "=&r"(count)
+ : [f0] "f"(f0)
+ : "memory");
+}
+#endif
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec/aec_rdft_neon.c b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc
index 43b6a68..acab972 100644
--- a/webrtc/modules/audio_processing/aec/aec_rdft_neon.c
+++ b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc
@@ -14,15 +14,16 @@
* Based on the sse2 version.
*/
-
-#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
-
#include <arm_neon.h>
-static const ALIGN16_BEG float ALIGN16_END
- k_swap_sign[4] = {-1.f, 1.f, -1.f, 1.f};
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h"
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h"
+
+namespace webrtc {
-static void cft1st_128_neon(float* a) {
+#if defined(WEBRTC_HAS_NEON)
+void cft1st_128_neon(float* a) {
const float32x4_t vec_swap_sign = vld1q_f32((float32_t*)k_swap_sign);
int j, k2;
@@ -71,7 +72,7 @@ static void cft1st_128_neon(float* a) {
}
}
-static void cftmdl_128_neon(float* a) {
+void cftmdl_128_neon(float* a) {
int j;
const int l = 8;
const float32x4_t vec_swap_sign = vld1q_f32((float32_t*)k_swap_sign);
@@ -185,7 +186,7 @@ __inline static float32x4_t reverse_order_f32x4(float32x4_t in) {
return vrev64q_f32(rev);
}
-static void rftfsub_128_neon(float* a) {
+void rftfsub_128_neon(float* a) {
const float* c = rdft_w + 32;
int j1, j2;
const float32x4_t mm_half = vdupq_n_f32(0.5f);
@@ -264,7 +265,7 @@ static void rftfsub_128_neon(float* a) {
}
}
-static void rftbsub_128_neon(float* a) {
+void rftbsub_128_neon(float* a) {
const float* c = rdft_w + 32;
int j1, j2;
const float32x4_t mm_half = vdupq_n_f32(0.5f);
@@ -274,11 +275,11 @@ static void rftbsub_128_neon(float* a) {
// Note: commented number are indexes for the first iteration of the loop.
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
// Load 'wk'.
- const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4,
- const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31,
- const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31,
- const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28,
- const float32x4_t wki_ = c_j1; // 1, 2, 3, 4,
+ const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4,
+ const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31,
+ const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31,
+ const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28,
+ const float32x4_t wki_ = c_j1; // 1, 2, 3, 4,
// Load and shuffle 'a'.
// 2, 4, 6, 8, 3, 5, 7, 9
float32x4x2_t a_j2_p = vld2q_f32(&a[0 + j2]);
@@ -345,11 +346,6 @@ static void rftbsub_128_neon(float* a) {
}
a[65] = -a[65];
}
+#endif
-void aec_rdft_init_neon(void) {
- cft1st_128 = cft1st_128_neon;
- cftmdl_128 = cftmdl_128_neon;
- rftfsub_128 = rftfsub_128_neon;
- rftbsub_128 = rftbsub_128_neon;
-}
-
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec/aec_rdft_sse2.c b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc
index b4e453f..7f0802d 100644
--- a/webrtc/modules/audio_processing/aec/aec_rdft_sse2.c
+++ b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc
@@ -8,14 +8,33 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
-
#include <emmintrin.h>
+#include <xmmintrin.h>
+
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h"
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h"
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
-static const ALIGN16_BEG float ALIGN16_END
- k_swap_sign[4] = {-1.f, 1.f, -1.f, 1.f};
+namespace {
+// These intrinsics were unavailable before VS 2008.
+// TODO(andrew): move to a common file.
+#if defined(_MSC_VER) && _MSC_VER < 1500
+static __inline __m128 _mm_castsi128_ps(__m128i a) {
+ return *(__m128*)&a;
+}
+static __inline __m128i _mm_castps_si128(__m128 a) {
+ return *(__m128i*)&a;
+}
+#endif
-static void cft1st_128_SSE2(float* a) {
+} // namespace
+
+void cft1st_128_SSE2(float* a) {
const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign);
int j, k2;
@@ -78,7 +97,7 @@ static void cft1st_128_SSE2(float* a) {
}
}
-static void cftmdl_128_SSE2(float* a) {
+void cftmdl_128_SSE2(float* a) {
const int l = 8;
const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign);
int j0;
@@ -89,12 +108,12 @@ static void cftmdl_128_SSE2(float* a) {
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]);
const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]);
- const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
- _mm_castsi128_ps(a_32),
- _MM_SHUFFLE(1, 0, 1, 0));
- const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
- _mm_castsi128_ps(a_40),
- _MM_SHUFFLE(1, 0, 1, 0));
+ const __m128 a_00_32 =
+ _mm_shuffle_ps(_mm_castsi128_ps(a_00), _mm_castsi128_ps(a_32),
+ _MM_SHUFFLE(1, 0, 1, 0));
+ const __m128 a_08_40 =
+ _mm_shuffle_ps(_mm_castsi128_ps(a_08), _mm_castsi128_ps(a_40),
+ _MM_SHUFFLE(1, 0, 1, 0));
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
@@ -102,12 +121,12 @@ static void cftmdl_128_SSE2(float* a) {
const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]);
const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]);
const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]);
- const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
- _mm_castsi128_ps(a_48),
- _MM_SHUFFLE(1, 0, 1, 0));
- const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
- _mm_castsi128_ps(a_56),
- _MM_SHUFFLE(1, 0, 1, 0));
+ const __m128 a_16_48 =
+ _mm_shuffle_ps(_mm_castsi128_ps(a_16), _mm_castsi128_ps(a_48),
+ _MM_SHUFFLE(1, 0, 1, 0));
+ const __m128 a_24_56 =
+ _mm_shuffle_ps(_mm_castsi128_ps(a_24), _mm_castsi128_ps(a_56),
+ _MM_SHUFFLE(1, 0, 1, 0));
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
@@ -163,12 +182,12 @@ static void cftmdl_128_SSE2(float* a) {
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]);
const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]);
- const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
- _mm_castsi128_ps(a_32),
- _MM_SHUFFLE(1, 0, 1, 0));
- const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
- _mm_castsi128_ps(a_40),
- _MM_SHUFFLE(1, 0, 1, 0));
+ const __m128 a_00_32 =
+ _mm_shuffle_ps(_mm_castsi128_ps(a_00), _mm_castsi128_ps(a_32),
+ _MM_SHUFFLE(1, 0, 1, 0));
+ const __m128 a_08_40 =
+ _mm_shuffle_ps(_mm_castsi128_ps(a_08), _mm_castsi128_ps(a_40),
+ _MM_SHUFFLE(1, 0, 1, 0));
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
@@ -176,22 +195,21 @@ static void cftmdl_128_SSE2(float* a) {
const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]);
const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]);
const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]);
- const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
- _mm_castsi128_ps(a_48),
- _MM_SHUFFLE(1, 0, 1, 0));
- const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
- _mm_castsi128_ps(a_56),
- _MM_SHUFFLE(1, 0, 1, 0));
+ const __m128 a_16_48 =
+ _mm_shuffle_ps(_mm_castsi128_ps(a_16), _mm_castsi128_ps(a_48),
+ _MM_SHUFFLE(1, 0, 1, 0));
+ const __m128 a_24_56 =
+ _mm_shuffle_ps(_mm_castsi128_ps(a_24), _mm_castsi128_ps(a_56),
+ _MM_SHUFFLE(1, 0, 1, 0));
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
const __m128 xx2 = _mm_mul_ps(xx1, wk2rv);
- const __m128 xx3 =
- _mm_mul_ps(wk2iv,
- _mm_castsi128_ps(_mm_shuffle_epi32(
- _mm_castps_si128(xx1), _MM_SHUFFLE(2, 3, 0, 1))));
+ const __m128 xx3 = _mm_mul_ps(
+ wk2iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xx1),
+ _MM_SHUFFLE(2, 3, 0, 1))));
const __m128 xx4 = _mm_add_ps(xx2, xx3);
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32(
@@ -202,16 +220,14 @@ static void cftmdl_128_SSE2(float* a) {
const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv);
const __m128 xx11 = _mm_mul_ps(
- wk1iv,
- _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add),
- _MM_SHUFFLE(2, 3, 0, 1))));
+ wk1iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add),
+ _MM_SHUFFLE(2, 3, 0, 1))));
const __m128 xx12 = _mm_add_ps(xx10, xx11);
const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv);
const __m128 xx21 = _mm_mul_ps(
- wk3iv,
- _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub),
- _MM_SHUFFLE(2, 3, 0, 1))));
+ wk3iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub),
+ _MM_SHUFFLE(2, 3, 0, 1))));
const __m128 xx22 = _mm_add_ps(xx20, xx21);
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx));
@@ -237,13 +253,13 @@ static void cftmdl_128_SSE2(float* a) {
}
}
-static void rftfsub_128_SSE2(float* a) {
+void rftfsub_128_SSE2(float* a) {
const float* c = rdft_w + 32;
int j1, j2, k1, k2;
float wkr, wki, xr, xi, yr, yi;
- static const ALIGN16_BEG float ALIGN16_END
- k_half[4] = {0.5f, 0.5f, 0.5f, 0.5f};
+ static const ALIGN16_BEG float ALIGN16_END k_half[4] = {0.5f, 0.5f, 0.5f,
+ 0.5f};
const __m128 mm_half = _mm_load_ps(k_half);
// Vectorized code (four at once).
@@ -327,13 +343,13 @@ static void rftfsub_128_SSE2(float* a) {
}
}
-static void rftbsub_128_SSE2(float* a) {
+void rftbsub_128_SSE2(float* a) {
const float* c = rdft_w + 32;
int j1, j2, k1, k2;
float wkr, wki, xr, xi, yr, yi;
- static const ALIGN16_BEG float ALIGN16_END
- k_half[4] = {0.5f, 0.5f, 0.5f, 0.5f};
+ static const ALIGN16_BEG float ALIGN16_END k_half[4] = {0.5f, 0.5f, 0.5f,
+ 0.5f};
const __m128 mm_half = _mm_load_ps(k_half);
a[1] = -a[1];
@@ -418,10 +434,6 @@ static void rftbsub_128_SSE2(float* a) {
}
a[65] = -a[65];
}
+#endif
-void aec_rdft_init_sse2(void) {
- cft1st_128 = cft1st_128_SSE2;
- cftmdl_128 = cftmdl_128_SSE2;
- rftfsub_128 = rftfsub_128_SSE2;
- rftbsub_128 = rftbsub_128_SSE2;
-}
+} // namespace webrtc
diff --git a/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h
new file mode 100644
index 0000000..6db1dd9
--- /dev/null
+++ b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h
@@ -0,0 +1,54 @@
+/*
+ * 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_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_COMMON_H_
+
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
+
+namespace webrtc {
+
+// This tables used to be computed at run-time. For example, refer to:
+// https://code.google.com/p/webrtc/source/browse/trunk/webrtc/modules/audio_processing/utility/apm_rdft.c?r=6564
+// to see the initialization code.
+// Constants shared by all paths (C, SSE2, NEON).
+const float rdft_w[64] = {
+ 1.0000000000f, 0.0000000000f, 0.7071067691f, 0.7071067691f, 0.9238795638f,
+ 0.3826834559f, 0.3826834559f, 0.9238795638f, 0.9807852507f, 0.1950903237f,
+ 0.5555702448f, 0.8314695954f, 0.8314695954f, 0.5555702448f, 0.1950903237f,
+ 0.9807852507f, 0.9951847196f, 0.0980171412f, 0.6343933344f, 0.7730104327f,
+ 0.8819212914f, 0.4713967443f, 0.2902846634f, 0.9569403529f, 0.9569403529f,
+ 0.2902846634f, 0.4713967443f, 0.8819212914f, 0.7730104327f, 0.6343933344f,
+ 0.0980171412f, 0.9951847196f, 0.7071067691f, 0.4993977249f, 0.4975923598f,
+ 0.4945882559f, 0.4903926253f, 0.4850156307f, 0.4784701765f, 0.4707720280f,
+ 0.4619397819f, 0.4519946277f, 0.4409606457f, 0.4288643003f, 0.4157347977f,
+ 0.4016037583f, 0.3865052164f, 0.3704755902f, 0.3535533845f, 0.3357794881f,
+ 0.3171966672f, 0.2978496552f, 0.2777851224f, 0.2570513785f, 0.2356983721f,
+ 0.2137775421f, 0.1913417280f, 0.1684449315f, 0.1451423317f, 0.1214900985f,
+ 0.0975451618f, 0.0733652338f, 0.0490085706f, 0.0245338380f,
+};
+
+// Constants used by the C and MIPS paths.
+const float rdft_wk3ri_first[16] = {
+ 1.000000000f, 0.000000000f, 0.382683456f, 0.923879564f,
+ 0.831469536f, 0.555570245f, -0.195090353f, 0.980785251f,
+ 0.956940353f, 0.290284693f, 0.098017156f, 0.995184720f,
+ 0.634393334f, 0.773010492f, -0.471396863f, 0.881921172f,
+};
+const float rdft_wk3ri_second[16] = {
+ -0.707106769f, 0.707106769f, -0.923879564f, -0.382683456f,
+ -0.980785251f, 0.195090353f, -0.555570245f, -0.831469536f,
+ -0.881921172f, 0.471396863f, -0.773010492f, -0.634393334f,
+ -0.995184720f, -0.098017156f, -0.290284693f, -0.956940353f,
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_COMMON_H_
diff --git a/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h
new file mode 100644
index 0000000..a63d187
--- /dev/null
+++ b/webrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h
@@ -0,0 +1,98 @@
+/*
+ * 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_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_
+
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
+#include "rtc_base/system/arch.h"
+
+#ifdef _MSC_VER /* visual c++ */
+#define ALIGN16_BEG __declspec(align(16))
+#define ALIGN16_END
+#else /* gcc or icc */
+#define ALIGN16_BEG
+#define ALIGN16_END __attribute__((aligned(16)))
+#endif
+
+namespace webrtc {
+
+// These tables used to be computed at run-time. For example, refer to:
+// https://code.google.com/p/webrtc/source/browse/trunk/webrtc/modules/audio_processing/utility/apm_rdft.c?r=6564
+// to see the initialization code.
+#if defined(WEBRTC_ARCH_X86_FAMILY) || defined(WEBRTC_HAS_NEON)
+// Constants used by SSE2 and NEON but initialized in the C path.
+const ALIGN16_BEG float ALIGN16_END k_swap_sign[4] = {-1.f, 1.f, -1.f, 1.f};
+
+ALIGN16_BEG const float ALIGN16_END rdft_wk1r[32] = {
+ 1.000000000f, 1.000000000f, 0.707106769f, 0.707106769f, 0.923879564f,
+ 0.923879564f, 0.382683456f, 0.382683456f, 0.980785251f, 0.980785251f,
+ 0.555570245f, 0.555570245f, 0.831469595f, 0.831469595f, 0.195090324f,
+ 0.195090324f, 0.995184720f, 0.995184720f, 0.634393334f, 0.634393334f,
+ 0.881921291f, 0.881921291f, 0.290284663f, 0.290284663f, 0.956940353f,
+ 0.956940353f, 0.471396744f, 0.471396744f, 0.773010433f, 0.773010433f,
+ 0.098017141f, 0.098017141f,
+};
+ALIGN16_BEG const float ALIGN16_END rdft_wk2r[32] = {
+ 1.000000000f, 1.000000000f, -0.000000000f, -0.000000000f, 0.707106769f,
+ 0.707106769f, -0.707106769f, -0.707106769f, 0.923879564f, 0.923879564f,
+ -0.382683456f, -0.382683456f, 0.382683456f, 0.382683456f, -0.923879564f,
+ -0.923879564f, 0.980785251f, 0.980785251f, -0.195090324f, -0.195090324f,
+ 0.555570245f, 0.555570245f, -0.831469595f, -0.831469595f, 0.831469595f,
+ 0.831469595f, -0.555570245f, -0.555570245f, 0.195090324f, 0.195090324f,
+ -0.980785251f, -0.980785251f,
+};
+ALIGN16_BEG const float ALIGN16_END rdft_wk3r[32] = {
+ 1.000000000f, 1.000000000f, -0.707106769f, -0.707106769f, 0.382683456f,
+ 0.382683456f, -0.923879564f, -0.923879564f, 0.831469536f, 0.831469536f,
+ -0.980785251f, -0.980785251f, -0.195090353f, -0.195090353f, -0.555570245f,
+ -0.555570245f, 0.956940353f, 0.956940353f, -0.881921172f, -0.881921172f,
+ 0.098017156f, 0.098017156f, -0.773010492f, -0.773010492f, 0.634393334f,
+ 0.634393334f, -0.995184720f, -0.995184720f, -0.471396863f, -0.471396863f,
+ -0.290284693f, -0.290284693f,
+};
+ALIGN16_BEG const float ALIGN16_END rdft_wk1i[32] = {
+ -0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f, -0.382683456f,
+ 0.382683456f, -0.923879564f, 0.923879564f, -0.195090324f, 0.195090324f,
+ -0.831469595f, 0.831469595f, -0.555570245f, 0.555570245f, -0.980785251f,
+ 0.980785251f, -0.098017141f, 0.098017141f, -0.773010433f, 0.773010433f,
+ -0.471396744f, 0.471396744f, -0.956940353f, 0.956940353f, -0.290284663f,
+ 0.290284663f, -0.881921291f, 0.881921291f, -0.634393334f, 0.634393334f,
+ -0.995184720f, 0.995184720f,
+};
+ALIGN16_BEG const float ALIGN16_END rdft_wk2i[32] = {
+ -0.000000000f, 0.000000000f, -1.000000000f, 1.000000000f, -0.707106769f,
+ 0.707106769f, -0.707106769f, 0.707106769f, -0.382683456f, 0.382683456f,
+ -0.923879564f, 0.923879564f, -0.923879564f, 0.923879564f, -0.382683456f,
+ 0.382683456f, -0.195090324f, 0.195090324f, -0.980785251f, 0.980785251f,
+ -0.831469595f, 0.831469595f, -0.555570245f, 0.555570245f, -0.555570245f,
+ 0.555570245f, -0.831469595f, 0.831469595f, -0.980785251f, 0.980785251f,
+ -0.195090324f, 0.195090324f,
+};
+ALIGN16_BEG const float ALIGN16_END rdft_wk3i[32] = {
+ -0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f, -0.923879564f,
+ 0.923879564f, 0.382683456f, -0.382683456f, -0.555570245f, 0.555570245f,
+ -0.195090353f, 0.195090353f, -0.980785251f, 0.980785251f, 0.831469536f,
+ -0.831469536f, -0.290284693f, 0.290284693f, -0.471396863f, 0.471396863f,
+ -0.995184720f, 0.995184720f, 0.634393334f, -0.634393334f, -0.773010492f,
+ 0.773010492f, 0.098017156f, -0.098017156f, -0.881921172f, 0.881921172f,
+ 0.956940353f, -0.956940353f,
+};
+ALIGN16_BEG const float ALIGN16_END cftmdl_wk1r[4] = {
+ 0.707106769f,
+ 0.707106769f,
+ 0.707106769f,
+ -0.707106769f,
+};
+#endif
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_
diff --git a/webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.cc b/webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.cc
new file mode 100644
index 0000000..d2f7c1c
--- /dev/null
+++ b/webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.cc
@@ -0,0 +1,866 @@
+/*
+ * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
+ * Copyright Takuya OOURA, 1996-2001
+ *
+ * You may use, copy, modify and distribute this code for any purpose (include
+ * commercial use) and without fee. Please refer to this package when you modify
+ * this code.
+ *
+ * Changes:
+ * Trivial type modifications by the WebRTC authors.
+ */
+
+/*
+Fast Fourier/Cosine/Sine Transform
+ dimension :one
+ data length :power of 2
+ decimation :frequency
+ radix :4, 2
+ data :inplace
+ table :use
+functions
+ cdft: Complex Discrete Fourier Transform
+ rdft: Real Discrete Fourier Transform
+ ddct: Discrete Cosine Transform
+ ddst: Discrete Sine Transform
+ dfct: Cosine Transform of RDFT (Real Symmetric DFT)
+ dfst: Sine Transform of RDFT (Real Anti-symmetric DFT)
+function prototypes
+ void cdft(int, int, float *, int *, float *);
+ void rdft(size_t, int, float *, size_t *, float *);
+ void ddct(int, int, float *, int *, float *);
+ void ddst(int, int, float *, int *, float *);
+ void dfct(int, float *, float *, int *, float *);
+ void dfst(int, float *, float *, int *, float *);
+
+
+-------- Complex DFT (Discrete Fourier Transform) --------
+ [definition]
+ <case1>
+ X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n
+ <case2>
+ X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n
+ (notes: sum_j=0^n-1 is a summation from j=0 to n-1)
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ cdft(2*n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ cdft(2*n, -1, a, ip, w);
+ [parameters]
+ 2*n :data length (int)
+ n >= 1, n = power of 2
+ a[0...2*n-1] :input/output data (float *)
+ input data
+ a[2*j] = Re(x[j]),
+ a[2*j+1] = Im(x[j]), 0<=j<n
+ output data
+ a[2*k] = Re(X[k]),
+ a[2*k+1] = Im(X[k]), 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ cdft(2*n, -1, a, ip, w);
+ is
+ cdft(2*n, 1, a, ip, w);
+ for (j = 0; j <= 2 * n - 1; j++) {
+ a[j] *= 1.0 / n;
+ }
+ .
+
+
+-------- Real DFT / Inverse of Real DFT --------
+ [definition]
+ <case1> RDFT
+ R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2
+ I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2
+ <case2> IRDFT (excluding scale)
+ a[k] = (R[0] + R[n/2]*cos(pi*k))/2 +
+ sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) +
+ sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ rdft(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ rdft(n, -1, a, ip, w);
+ [parameters]
+ n :data length (size_t)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float *)
+ <case1>
+ output data
+ a[2*k] = R[k], 0<=k<n/2
+ a[2*k+1] = I[k], 0<k<n/2
+ a[1] = R[n/2]
+ <case2>
+ input data
+ a[2*j] = R[j], 0<=j<n/2
+ a[2*j+1] = I[j], 0<j<n/2
+ a[1] = R[n/2]
+ ip[0...*] :work area for bit reversal (size_t *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ rdft(n, 1, a, ip, w);
+ is
+ rdft(n, -1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DCT (Discrete Cosine Transform) / Inverse of DCT --------
+ [definition]
+ <case1> IDCT (excluding scale)
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DCT
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddct(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ ddct(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float *)
+ output data
+ a[k] = C[k], 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddct(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddct(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DST (Discrete Sine Transform) / Inverse of DST --------
+ [definition]
+ <case1> IDST (excluding scale)
+ S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DST
+ S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddst(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ ddst(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float *)
+ <case1>
+ input data
+ a[j] = A[j], 0<j<n
+ a[0] = A[n]
+ output data
+ a[k] = S[k], 0<=k<n
+ <case2>
+ output data
+ a[k] = S[k], 0<k<n
+ a[0] = S[n]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddst(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddst(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Cosine Transform of RDFT (Real Symmetric DFT) --------
+ [definition]
+ C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n
+ [usage]
+ ip[0] = 0; // first time only
+ dfct(n, a, t, ip, w);
+ [parameters]
+ n :data length - 1 (int)
+ n >= 2, n = power of 2
+ a[0...n] :input/output data (float *)
+ output data
+ a[k] = C[k], 0<=k<=n
+ t[0...n/2] :work area (float *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ is
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ for (j = 0; j <= n; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Sine Transform of RDFT (Real Anti-symmetric DFT) --------
+ [definition]
+ S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n
+ [usage]
+ ip[0] = 0; // first time only
+ dfst(n, a, t, ip, w);
+ [parameters]
+ n :data length + 1 (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float *)
+ output data
+ a[k] = S[k], 0<k<n
+ (a[0] is used for work area)
+ t[0...n/2-1] :work area (float *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ dfst(n, a, t, ip, w);
+ is
+ dfst(n, a, t, ip, w);
+ for (j = 1; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+Appendix :
+ The cos/sin table is recalculated when the larger table required.
+ w[] and ip[] are compatible with all routines.
+*/
+
+#include <math.h>
+#include <stddef.h>
+
+#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
+
+namespace webrtc {
+
+namespace {
+
+void makewt(size_t nw, size_t* ip, float* w);
+void makect(size_t nc, size_t* ip, float* c);
+void bitrv2(size_t n, size_t* ip, float* a);
+void cftfsub(size_t n, float* a, float* w);
+void cftbsub(size_t n, float* a, float* w);
+void cft1st(size_t n, float* a, float* w);
+void cftmdl(size_t n, size_t l, float* a, float* w);
+void rftfsub(size_t n, float* a, size_t nc, float* c);
+void rftbsub(size_t n, float* a, size_t nc, float* c);
+
+/* -------- initializing routines -------- */
+
+void makewt(size_t nw, size_t* ip, float* w) {
+ size_t j, nwh;
+ float delta, x, y;
+
+ ip[0] = nw;
+ ip[1] = 1;
+ if (nw > 2) {
+ nwh = nw >> 1;
+ delta = atanf(1.0f) / nwh;
+ w[0] = 1;
+ w[1] = 0;
+ w[nwh] = (float)cos(delta * nwh);
+ w[nwh + 1] = w[nwh];
+ if (nwh > 2) {
+ for (j = 2; j < nwh; j += 2) {
+ x = (float)cos(delta * j);
+ y = (float)sin(delta * j);
+ w[j] = x;
+ w[j + 1] = y;
+ w[nw - j] = y;
+ w[nw - j + 1] = x;
+ }
+ bitrv2(nw, ip + 2, w);
+ }
+ }
+}
+
+void makect(size_t nc, size_t* ip, float* c) {
+ size_t j, nch;
+ float delta;
+
+ ip[1] = nc;
+ if (nc > 1) {
+ nch = nc >> 1;
+ delta = atanf(1.0f) / nch;
+ c[0] = (float)cos(delta * nch);
+ c[nch] = 0.5f * c[0];
+ for (j = 1; j < nch; j++) {
+ c[j] = 0.5f * (float)cos(delta * j);
+ c[nc - j] = 0.5f * (float)sin(delta * j);
+ }
+ }
+}
+
+/* -------- child routines -------- */
+
+void bitrv2(size_t n, size_t* ip, float* a) {
+ size_t j, j1, k, k1, l, m, m2;
+ float xr, xi, yr, yi;
+
+ ip[0] = 0;
+ l = n;
+ m = 1;
+ while ((m << 3) < l) {
+ l >>= 1;
+ for (j = 0; j < m; j++) {
+ ip[m + j] = ip[j] + l;
+ }
+ m <<= 1;
+ }
+ m2 = 2 * m;
+ if ((m << 3) == l) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 -= m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += 2 * m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ j1 = 2 * k + m2 + ip[k];
+ k1 = j1 + m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ } else {
+ for (k = 1; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 2 * j + ip[k];
+ k1 = 2 * k + ip[j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += m2;
+ k1 += m2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ }
+ }
+}
+
+void cftfsub(size_t n, float* a, float* w) {
+ size_t j, j1, j2, j3, l;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ l = 2;
+ if (n > 8) {
+ cft1st(n, a, w);
+ l = 8;
+ while ((l << 2) < n) {
+ cftmdl(n, l, a, w);
+ l <<= 2;
+ }
+ }
+ if ((l << 2) == n) {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i - x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ }
+ } else {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ x0r = a[j] - a[j1];
+ x0i = a[j + 1] - a[j1 + 1];
+ a[j] += a[j1];
+ a[j + 1] += a[j1 + 1];
+ a[j1] = x0r;
+ a[j1 + 1] = x0i;
+ }
+ }
+}
+
+void cftbsub(size_t n, float* a, float* w) {
+ size_t j, j1, j2, j3, l;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ l = 2;
+ if (n > 8) {
+ cft1st(n, a, w);
+ l = 8;
+ while ((l << 2) < n) {
+ cftmdl(n, l, a, w);
+ l <<= 2;
+ }
+ }
+ if ((l << 2) == n) {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = -a[j + 1] - a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = -a[j + 1] + a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i - x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i + x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i - x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i + x3r;
+ }
+ } else {
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ x0r = a[j] - a[j1];
+ x0i = -a[j + 1] + a[j1 + 1];
+ a[j] += a[j1];
+ a[j + 1] = -a[j + 1] - a[j1 + 1];
+ a[j1] = x0r;
+ a[j1 + 1] = x0i;
+ }
+ }
+}
+
+void cft1st(size_t n, float* a, float* w) {
+ size_t j, k1, k2;
+ float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ x0r = a[0] + a[2];
+ x0i = a[1] + a[3];
+ x1r = a[0] - a[2];
+ x1i = a[1] - a[3];
+ x2r = a[4] + a[6];
+ x2i = a[5] + a[7];
+ x3r = a[4] - a[6];
+ x3i = a[5] - a[7];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[4] = x0r - x2r;
+ a[5] = x0i - x2i;
+ a[2] = x1r - x3i;
+ a[3] = x1i + x3r;
+ a[6] = x1r + x3i;
+ a[7] = x1i - x3r;
+ wk1r = w[2];
+ x0r = a[8] + a[10];
+ x0i = a[9] + a[11];
+ x1r = a[8] - a[10];
+ x1i = a[9] - a[11];
+ x2r = a[12] + a[14];
+ x2i = a[13] + a[15];
+ x3r = a[12] - a[14];
+ x3i = a[13] - a[15];
+ a[8] = x0r + x2r;
+ a[9] = x0i + x2i;
+ a[12] = x2i - x0i;
+ a[13] = x0r - x2r;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[10] = wk1r * (x0r - x0i);
+ a[11] = wk1r * (x0r + x0i);
+ x0r = x3i + x1r;
+ x0i = x3r - x1i;
+ a[14] = wk1r * (x0i - x0r);
+ a[15] = wk1r * (x0i + x0r);
+ k1 = 0;
+ for (j = 16; j < n; j += 16) {
+ k1 += 2;
+ k2 = 2 * k1;
+ wk2r = w[k1];
+ wk2i = w[k1 + 1];
+ wk1r = w[k2];
+ wk1i = w[k2 + 1];
+ wk3r = wk1r - 2 * wk2i * wk1i;
+ wk3i = 2 * wk2i * wk1r - wk1i;
+ x0r = a[j] + a[j + 2];
+ x0i = a[j + 1] + a[j + 3];
+ x1r = a[j] - a[j + 2];
+ x1i = a[j + 1] - a[j + 3];
+ x2r = a[j + 4] + a[j + 6];
+ x2i = a[j + 5] + a[j + 7];
+ x3r = a[j + 4] - a[j + 6];
+ x3i = a[j + 5] - a[j + 7];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ x0r -= x2r;
+ x0i -= x2i;
+ a[j + 4] = wk2r * x0r - wk2i * x0i;
+ a[j + 5] = wk2r * x0i + wk2i * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j + 2] = wk1r * x0r - wk1i * x0i;
+ a[j + 3] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j + 6] = wk3r * x0r - wk3i * x0i;
+ a[j + 7] = wk3r * x0i + wk3i * x0r;
+ wk1r = w[k2 + 2];
+ wk1i = w[k2 + 3];
+ wk3r = wk1r - 2 * wk2r * wk1i;
+ wk3i = 2 * wk2r * wk1r - wk1i;
+ x0r = a[j + 8] + a[j + 10];
+ x0i = a[j + 9] + a[j + 11];
+ x1r = a[j + 8] - a[j + 10];
+ x1i = a[j + 9] - a[j + 11];
+ x2r = a[j + 12] + a[j + 14];
+ x2i = a[j + 13] + a[j + 15];
+ x3r = a[j + 12] - a[j + 14];
+ x3i = a[j + 13] - a[j + 15];
+ a[j + 8] = x0r + x2r;
+ a[j + 9] = x0i + x2i;
+ x0r -= x2r;
+ x0i -= x2i;
+ a[j + 12] = -wk2i * x0r - wk2r * x0i;
+ a[j + 13] = -wk2i * x0i + wk2r * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j + 10] = wk1r * x0r - wk1i * x0i;
+ a[j + 11] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j + 14] = wk3r * x0r - wk3i * x0i;
+ a[j + 15] = wk3r * x0i + wk3i * x0r;
+ }
+}
+
+void cftmdl(size_t n, size_t l, float* a, float* w) {
+ size_t j, j1, j2, j3, k, k1, k2, m, m2;
+ float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ m = l << 2;
+ for (j = 0; j < l; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j2] = x0r - x2r;
+ a[j2 + 1] = x0i - x2i;
+ a[j1] = x1r - x3i;
+ a[j1 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ }
+ wk1r = w[2];
+ for (j = m; j < l + m; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j2] = x2i - x0i;
+ a[j2 + 1] = x0r - x2r;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j1] = wk1r * (x0r - x0i);
+ a[j1 + 1] = wk1r * (x0r + x0i);
+ x0r = x3i + x1r;
+ x0i = x3r - x1i;
+ a[j3] = wk1r * (x0i - x0r);
+ a[j3 + 1] = wk1r * (x0i + x0r);
+ }
+ k1 = 0;
+ m2 = 2 * m;
+ for (k = m2; k < n; k += m2) {
+ k1 += 2;
+ k2 = 2 * k1;
+ wk2r = w[k1];
+ wk2i = w[k1 + 1];
+ wk1r = w[k2];
+ wk1i = w[k2 + 1];
+ wk3r = wk1r - 2 * wk2i * wk1i;
+ wk3i = 2 * wk2i * wk1r - wk1i;
+ for (j = k; j < l + k; j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ x0r -= x2r;
+ x0i -= x2i;
+ a[j2] = wk2r * x0r - wk2i * x0i;
+ a[j2 + 1] = wk2r * x0i + wk2i * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j1] = wk1r * x0r - wk1i * x0i;
+ a[j1 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r - wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i + wk3i * x0r;
+ }
+ wk1r = w[k2 + 2];
+ wk1i = w[k2 + 3];
+ wk3r = wk1r - 2 * wk2r * wk1i;
+ wk3i = 2 * wk2r * wk1r - wk1i;
+ for (j = k + m; j < l + (k + m); j += 2) {
+ j1 = j + l;
+ j2 = j1 + l;
+ j3 = j2 + l;
+ x0r = a[j] + a[j1];
+ x0i = a[j + 1] + a[j1 + 1];
+ x1r = a[j] - a[j1];
+ x1i = a[j + 1] - a[j1 + 1];
+ x2r = a[j2] + a[j3];
+ x2i = a[j2 + 1] + a[j3 + 1];
+ x3r = a[j2] - a[j3];
+ x3i = a[j2 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ x0r -= x2r;
+ x0i -= x2i;
+ a[j2] = -wk2i * x0r - wk2r * x0i;
+ a[j2 + 1] = -wk2i * x0i + wk2r * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j1] = wk1r * x0r - wk1i * x0i;
+ a[j1 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r - wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i + wk3i * x0r;
+ }
+ }
+}
+
+void rftfsub(size_t n, float* a, size_t nc, float* c) {
+ size_t j, k, kk, ks, m;
+ float wkr, wki, xr, xi, yr, yi;
+
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = 0.5f - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr - wki * xi;
+ yi = wkr * xi + wki * xr;
+ a[j] -= yr;
+ a[j + 1] -= yi;
+ a[k] += yr;
+ a[k + 1] -= yi;
+ }
+}
+
+void rftbsub(size_t n, float* a, size_t nc, float* c) {
+ size_t j, k, kk, ks, m;
+ float wkr, wki, xr, xi, yr, yi;
+
+ a[1] = -a[1];
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = 0.5f - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr + wki * xi;
+ yi = wkr * xi - wki * xr;
+ a[j] -= yr;
+ a[j + 1] = yi - a[j + 1];
+ a[k] += yr;
+ a[k + 1] = yi - a[k + 1];
+ }
+ a[m + 1] = -a[m + 1];
+}
+
+} // namespace
+
+void WebRtc_rdft(size_t n, int isgn, float* a, size_t* ip, float* w) {
+ size_t nw, nc;
+ float xi;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 2)) {
+ nc = n >> 2;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn >= 0) {
+ if (n > 4) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ xi = a[0] - a[1];
+ a[0] += a[1];
+ a[1] = xi;
+ } else {
+ a[1] = 0.5f * (a[0] - a[1]);
+ a[0] -= a[1];
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ bitrv2(n, ip + 2, a);
+ cftbsub(n, a, w);
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.h b/webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.h
new file mode 100644
index 0000000..d41d2c6
--- /dev/null
+++ b/webrtc/common_audio/third_party/ooura/fft_size_256/fft4g.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the ../../../LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can 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 COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_
+#define COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_
+
+namespace webrtc {
+
+// Refer to fft4g.c for documentation.
+void WebRtc_rdft(size_t n, int isgn, float* a, size_t* ip, float* w);
+
+} // namespace webrtc
+
+#endif // COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_
diff --git a/webrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn b/webrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn
new file mode 100644
index 0000000..ac862c6
--- /dev/null
+++ b/webrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the ../../../LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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_library("spl_sqrt_floor") {
+ visibility = [ "../..:common_audio_c" ]
+ sources = [ "spl_sqrt_floor.h" ]
+ deps = []
+ if (current_cpu == "arm") {
+ sources += [ "spl_sqrt_floor_arm.S" ]
+
+ deps += [ "../../../rtc_base/system:asm_defines" ]
+ } else if (current_cpu == "mipsel") {
+ sources += [ "spl_sqrt_floor_mips.c" ]
+ } else {
+ sources += [ "spl_sqrt_floor.c" ]
+ }
+}
diff --git a/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE b/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE
new file mode 100644
index 0000000..fdf17a2
--- /dev/null
+++ b/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE
@@ -0,0 +1,27 @@
+/*
+ * Written by Wilco Dijkstra, 1996. The following email exchange establishes the
+ * license.
+ *
+ * From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com>
+ * Date: Fri, Jun 24, 2011 at 3:20 AM
+ * Subject: Re: sqrt routine
+ * To: Kevin Ma <kma@google.com>
+ * Hi Kevin,
+ * Thanks for asking. Those routines are public domain (originally posted to
+ * comp.sys.arm a long time ago), so you can use them freely for any purpose.
+ * Cheers,
+ * Wilco
+ *
+ * ----- Original Message -----
+ * From: "Kevin Ma" <kma@google.com>
+ * To: <Wilco.Dijkstra@ntlworld.com>
+ * Sent: Thursday, June 23, 2011 11:44 PM
+ * Subject: Fwd: sqrt routine
+ * Hi Wilco,
+ * I saw your sqrt routine from several web sites, including
+ * http://www.finesse.demon.co.uk/steven/sqrt.html.
+ * Just wonder if there's any copyright information with your Successive
+ * approximation routines, or if I can freely use it for any purpose.
+ * Thanks.
+ * Kevin
+ */
diff --git a/webrtc/common_audio/signal_processing/spl_sqrt_floor.c b/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c
index 370307a..b478a41 100644
--- a/webrtc/common_audio/signal_processing/spl_sqrt_floor.c
+++ b/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c
@@ -28,7 +28,7 @@
// Minor modifications in code style for WebRTC, 2012.
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h"
/*
* Algorithm:
diff --git a/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h b/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h
new file mode 100644
index 0000000..eaa58e3
--- /dev/null
+++ b/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <stdint.h>
+
+//
+// WebRtcSpl_SqrtFloor(...)
+//
+// Returns the square root of the input value |value|. The precision of this
+// function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer.
+// If |value| is a negative number then 0 is returned.
+//
+// Algorithm:
+//
+// An iterative 4 cylce/bit routine
+//
+// Input:
+// - value : Value to calculate sqrt of
+//
+// Return value : Result of the sqrt calculation
+//
+int32_t WebRtcSpl_SqrtFloor(int32_t value);
diff --git a/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S b/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S
index 72cd2d9..228e68e 100644
--- a/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S
+++ b/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S
@@ -32,7 +32,7 @@
@ Output: r0 = INT (SQRT (r0)), precision is 16 bits
@ Registers touched: r1, r2
-#include "webrtc/system_wrappers/include/asm_defines.h"
+#include "rtc_base/system/asm_defines.h"
GLOBAL_FUNCTION WebRtcSpl_SqrtFloor
.align 2
diff --git a/webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c b/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c
index 8716459..04033c1 100644
--- a/webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c
+++ b/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c
@@ -29,7 +29,7 @@
// Minor modifications in code style for WebRTC, 2012.
// Code optimizations for MIPS, 2013.
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h"
/*
* Algorithm:
diff --git a/webrtc/common_audio/vad/include/vad.h b/webrtc/common_audio/vad/include/vad.h
index 087970f..b15275b 100644
--- a/webrtc/common_audio/vad/include/vad.h
+++ b/webrtc/common_audio/vad/include/vad.h
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
-#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+#ifndef COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+#define COMMON_AUDIO_VAD_INCLUDE_VAD_H_
-#include "webrtc/base/checks.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/vad/include/webrtc_vad.h"
-#include "webrtc/typedefs.h"
+#include <memory>
+
+#include "common_audio/vad/include/webrtc_vad.h"
+#include "rtc_base/checks.h"
namespace webrtc {
@@ -43,8 +43,8 @@ class Vad {
};
// Returns a Vad instance that's implemented on top of WebRtcVad.
-rtc::scoped_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness);
+std::unique_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness);
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+#endif // COMMON_AUDIO_VAD_INCLUDE_VAD_H_
diff --git a/webrtc/common_audio/vad/include/webrtc_vad.h b/webrtc/common_audio/vad/include/webrtc_vad.h
index 91308ee..f5bbadf 100644
--- a/webrtc/common_audio/vad/include/webrtc_vad.h
+++ b/webrtc/common_audio/vad/include/webrtc_vad.h
@@ -8,17 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
/*
- * This header file includes the VAD API calls. Specific function calls are given below.
+ * This header file includes the VAD API calls. Specific function calls are
+ * given below.
*/
-#ifndef WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
-#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_
+#ifndef COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
+#define COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_
#include <stddef.h>
-
-#include "webrtc/typedefs.h"
+#include <stdint.h>
typedef struct WebRtcVadInst VadInst;
@@ -27,7 +26,7 @@ extern "C" {
#endif
// Creates an instance to the VAD structure.
-VadInst* WebRtcVad_Create();
+VadInst* WebRtcVad_Create(void);
// Frees the dynamic memory of a specified VAD instance.
//
@@ -39,7 +38,7 @@ void WebRtcVad_Free(VadInst* handle);
// - handle [i/o] : Instance that should be initialized.
//
// returns : 0 - (OK),
-// -1 - (NULL pointer or Default mode could not be set).
+// -1 - (null pointer or Default mode could not be set).
int WebRtcVad_Init(VadInst* handle);
// Sets the VAD operating mode. A more aggressive (higher mode) VAD is more
@@ -51,7 +50,7 @@ int WebRtcVad_Init(VadInst* handle);
// - mode [i] : Aggressiveness mode (0, 1, 2, or 3).
//
// returns : 0 - (OK),
-// -1 - (NULL pointer, mode could not be set or the VAD instance
+// -1 - (null pointer, mode could not be set or the VAD instance
// has not been initialized).
int WebRtcVad_set_mode(VadInst* handle, int mode);
@@ -67,7 +66,9 @@ int WebRtcVad_set_mode(VadInst* handle, int mode);
// returns : 1 - (Active Voice),
// 0 - (Non-active Voice),
// -1 - (Error)
-int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame,
+int WebRtcVad_Process(VadInst* handle,
+ int fs,
+ const int16_t* audio_frame,
size_t frame_length);
// Checks for valid combinations of |rate| and |frame_length|. We support 10,
@@ -83,4 +84,4 @@ int WebRtcVad_ValidRateAndFrameLength(int rate, size_t frame_length);
}
#endif
-#endif // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
+#endif // COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
diff --git a/webrtc/common_audio/vad/vad.cc b/webrtc/common_audio/vad/vad.cc
index 95a162f..987ed52 100644
--- a/webrtc/common_audio/vad/vad.cc
+++ b/webrtc/common_audio/vad/vad.cc
@@ -8,9 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/vad/include/vad.h"
+#include "common_audio/vad/include/vad.h"
-#include "webrtc/base/checks.h"
+#include <memory>
+
+#include "common_audio/vad/include/webrtc_vad.h"
+#include "rtc_base/checks.h"
namespace webrtc {
@@ -35,7 +38,7 @@ class VadImpl final : public Vad {
case 1:
return kActive;
default:
- RTC_DCHECK(false) << "WebRtcVad_Process returned an error.";
+ RTC_NOTREACHED() << "WebRtcVad_Process returned an error.";
return kError;
}
}
@@ -56,8 +59,8 @@ class VadImpl final : public Vad {
} // namespace
-rtc::scoped_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness) {
- return rtc::scoped_ptr<Vad>(new VadImpl(aggressiveness));
+std::unique_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness) {
+ return std::unique_ptr<Vad>(new VadImpl(aggressiveness));
}
} // namespace webrtc
diff --git a/webrtc/common_audio/vad/vad_core.c b/webrtc/common_audio/vad/vad_core.c
index 51797ee..55927ce 100644
--- a/webrtc/common_audio/vad/vad_core.c
+++ b/webrtc/common_audio/vad/vad_core.c
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/vad/vad_core.h"
+#include "common_audio/vad/vad_core.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/vad/vad_filterbank.h"
-#include "webrtc/common_audio/vad/vad_gmm.h"
-#include "webrtc/common_audio/vad/vad_sp.h"
-#include "webrtc/typedefs.h"
+#include "rtc_base/sanitizer.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/vad/vad_filterbank.h"
+#include "common_audio/vad/vad_gmm.h"
+#include "common_audio/vad/vad_sp.h"
// Spectrum Weighting
static const int16_t kSpectrumWeight[kNumChannels] = { 6, 8, 10, 12, 14, 16 };
@@ -110,6 +110,15 @@ static int32_t WeightedAverage(int16_t* data, int16_t offset,
return weighted_average;
}
+// An s16 x s32 -> s32 multiplication that's allowed to overflow. (It's still
+// undefined behavior, so not a good idea; this just makes UBSan ignore the
+// violation, so that our old code can continue to do what it's always been
+// doing.)
+static inline int32_t RTC_NO_SANITIZE("signed-integer-overflow")
+ OverflowingMulS16ByS32ToS32(int16_t a, int32_t b) {
+ return a * b;
+}
+
// Calculates the probabilities for both speech and background noise using
// Gaussian Mixture Models (GMM). A hypothesis-test is performed to decide which
// type of signal is most probable.
@@ -231,7 +240,7 @@ static int16_t GmmProbability(VadInstT* self, int16_t* features,
(int32_t) (log_likelihood_ratio * kSpectrumWeight[channel]);
// Local VAD decision.
- if ((log_likelihood_ratio << 2) > individualTest) {
+ if ((log_likelihood_ratio * 4) > individualTest) {
vadflag = 1;
}
@@ -378,7 +387,7 @@ static int16_t GmmProbability(VadInstT* self, int16_t* features,
// (Q14 >> 2) * Q12 = Q24.
tmp_s16 = (ngprvec[gaussian] + 2) >> 2;
- tmp2_s32 = tmp_s16 * tmp1_s32;
+ tmp2_s32 = OverflowingMulS16ByS32ToS32(tmp_s16, tmp1_s32);
// Q20 * approx 0.001 (2^-10=0.0009766), hence,
// (Q24 >> 14) = (Q24 >> 4) / 2^10 = Q20.
tmp1_s32 = tmp2_s32 >> 14;
diff --git a/webrtc/common_audio/vad/vad_core.h b/webrtc/common_audio/vad/vad_core.h
index b38c515..e79696c 100644
--- a/webrtc/common_audio/vad/vad_core.h
+++ b/webrtc/common_audio/vad/vad_core.h
@@ -8,51 +8,46 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
/*
* This header file includes the descriptions of the core VAD calls.
*/
-#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
-#define WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
+#ifndef COMMON_AUDIO_VAD_VAD_CORE_H_
+#define COMMON_AUDIO_VAD_VAD_CORE_H_
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/typedefs.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
-enum { kNumChannels = 6 }; // Number of frequency bands (named channels).
+enum { kNumChannels = 6 }; // Number of frequency bands (named channels).
enum { kNumGaussians = 2 }; // Number of Gaussians per channel in the GMM.
enum { kTableSize = kNumChannels * kNumGaussians };
enum { kMinEnergy = 10 }; // Minimum energy required to trigger audio signal.
-typedef struct VadInstT_
-{
-
- int vad;
- int32_t downsampling_filter_states[4];
- WebRtcSpl_State48khzTo8khz state_48_to_8;
- int16_t noise_means[kTableSize];
- int16_t speech_means[kTableSize];
- int16_t noise_stds[kTableSize];
- int16_t speech_stds[kTableSize];
- // TODO(bjornv): Change to |frame_count|.
- int32_t frame_counter;
- int16_t over_hang; // Over Hang
- int16_t num_of_speech;
- // TODO(bjornv): Change to |age_vector|.
- int16_t index_vector[16 * kNumChannels];
- int16_t low_value_vector[16 * kNumChannels];
- // TODO(bjornv): Change to |median|.
- int16_t mean_value[kNumChannels];
- int16_t upper_state[5];
- int16_t lower_state[5];
- int16_t hp_filter_state[4];
- int16_t over_hang_max_1[3];
- int16_t over_hang_max_2[3];
- int16_t individual[3];
- int16_t total[3];
-
- int init_flag;
+typedef struct VadInstT_ {
+ int vad;
+ int32_t downsampling_filter_states[4];
+ WebRtcSpl_State48khzTo8khz state_48_to_8;
+ int16_t noise_means[kTableSize];
+ int16_t speech_means[kTableSize];
+ int16_t noise_stds[kTableSize];
+ int16_t speech_stds[kTableSize];
+ // TODO(bjornv): Change to |frame_count|.
+ int32_t frame_counter;
+ int16_t over_hang; // Over Hang
+ int16_t num_of_speech;
+ // TODO(bjornv): Change to |age_vector|.
+ int16_t index_vector[16 * kNumChannels];
+ int16_t low_value_vector[16 * kNumChannels];
+ // TODO(bjornv): Change to |median|.
+ int16_t mean_value[kNumChannels];
+ int16_t upper_state[5];
+ int16_t lower_state[5];
+ int16_t hp_filter_state[4];
+ int16_t over_hang_max_1[3];
+ int16_t over_hang_max_2[3];
+ int16_t individual[3];
+ int16_t total[3];
+ int init_flag;
} VadInstT;
// Initializes the core VAD component. The default aggressiveness mode is
@@ -60,7 +55,7 @@ typedef struct VadInstT_
//
// - self [i/o] : Instance that should be initialized
//
-// returns : 0 (OK), -1 (NULL pointer in or if the default mode can't be
+// returns : 0 (OK), -1 (null pointer in or if the default mode can't be
// set)
int WebRtcVad_InitCore(VadInstT* self);
@@ -103,13 +98,17 @@ int WebRtcVad_set_mode_core(VadInstT* self, int mode);
* 0 - No active speech
* 1-6 - Active speech
*/
-int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame,
+int WebRtcVad_CalcVad48khz(VadInstT* inst,
+ const int16_t* speech_frame,
size_t frame_length);
-int WebRtcVad_CalcVad32khz(VadInstT* inst, const int16_t* speech_frame,
+int WebRtcVad_CalcVad32khz(VadInstT* inst,
+ const int16_t* speech_frame,
size_t frame_length);
-int WebRtcVad_CalcVad16khz(VadInstT* inst, const int16_t* speech_frame,
+int WebRtcVad_CalcVad16khz(VadInstT* inst,
+ const int16_t* speech_frame,
size_t frame_length);
-int WebRtcVad_CalcVad8khz(VadInstT* inst, const int16_t* speech_frame,
+int WebRtcVad_CalcVad8khz(VadInstT* inst,
+ const int16_t* speech_frame,
size_t frame_length);
-#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
+#endif // COMMON_AUDIO_VAD_VAD_CORE_H_
diff --git a/webrtc/common_audio/vad/vad_filterbank.c b/webrtc/common_audio/vad/vad_filterbank.c
index 8b9df93..1513153 100644
--- a/webrtc/common_audio/vad/vad_filterbank.c
+++ b/webrtc/common_audio/vad/vad_filterbank.c
@@ -8,12 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/vad/vad_filterbank.h"
+#include "common_audio/vad/vad_filterbank.h"
-#include <assert.h>
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/typedefs.h"
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
// Constants used in LogOfEnergy().
static const int16_t kLogConst = 24660; // 160*log10(2) in Q9.
@@ -92,14 +90,14 @@ static void AllPassFilter(const int16_t* data_in, size_t data_length,
size_t i;
int16_t tmp16 = 0;
int32_t tmp32 = 0;
- int32_t state32 = ((int32_t) (*filter_state) << 16); // Q15
+ int32_t state32 = ((int32_t) (*filter_state) * (1 << 16)); // Q15
for (i = 0; i < data_length; i++) {
tmp32 = state32 + filter_coefficient * *data_in;
tmp16 = (int16_t) (tmp32 >> 16); // Q(-1)
*data_out++ = tmp16;
- state32 = (*data_in << 14) - filter_coefficient * tmp16; // Q14
- state32 <<= 1; // Q15.
+ state32 = (*data_in * (1 << 14)) - filter_coefficient * tmp16; // Q14
+ state32 *= 2; // Q15.
data_in += 2;
}
@@ -160,8 +158,8 @@ static void LogOfEnergy(const int16_t* data_in, size_t data_length,
// we eventually will mask out the fractional part.
uint32_t energy = 0;
- assert(data_in != NULL);
- assert(data_length > 0);
+ RTC_DCHECK(data_in);
+ RTC_DCHECK_GT(data_length, 0);
energy = (uint32_t) WebRtcSpl_Energy((int16_t*) data_in, data_length,
&tot_rshifts);
@@ -261,8 +259,8 @@ int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
int16_t* hp_out_ptr = hp_120; // [2000 - 4000] Hz.
int16_t* lp_out_ptr = lp_120; // [0 - 2000] Hz.
- assert(data_length <= 240);
- assert(4 < kNumChannels - 1); // Checking maximum |frequency_band|.
+ RTC_DCHECK_LE(data_length, 240);
+ RTC_DCHECK_LT(4, kNumChannels - 1); // Checking maximum |frequency_band|.
// Split at 2000 Hz and downsample.
SplitFilter(in_ptr, data_length, &self->upper_state[frequency_band],
diff --git a/webrtc/common_audio/vad/vad_filterbank.h b/webrtc/common_audio/vad/vad_filterbank.h
index 42bf3fc..53bbbe1 100644
--- a/webrtc/common_audio/vad/vad_filterbank.h
+++ b/webrtc/common_audio/vad/vad_filterbank.h
@@ -12,11 +12,10 @@
* This file includes feature calculating functionality used in vad_core.c.
*/
-#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
-#define WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
+#ifndef COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
+#define COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
-#include "webrtc/common_audio/vad/vad_core.h"
-#include "webrtc/typedefs.h"
+#include "common_audio/vad/vad_core.h"
// Takes |data_length| samples of |data_in| and calculates the logarithm of the
// energy of each of the |kNumChannels| = 6 frequency bands used by the VAD:
@@ -38,7 +37,9 @@
// - features [o] : 10 * log10(energy in each frequency band), Q4.
// - returns : Total energy of the signal (NOTE! This value is not
// exact. It is only used in a comparison.)
-int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
- size_t data_length, int16_t* features);
+int16_t WebRtcVad_CalculateFeatures(VadInstT* self,
+ const int16_t* data_in,
+ size_t data_length,
+ int16_t* features);
-#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
+#endif // COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
diff --git a/webrtc/common_audio/vad/vad_gmm.c b/webrtc/common_audio/vad/vad_gmm.c
index 4a01440..ddc87b6 100644
--- a/webrtc/common_audio/vad/vad_gmm.c
+++ b/webrtc/common_audio/vad/vad_gmm.c
@@ -8,10 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/vad/vad_gmm.h"
+#include "common_audio/vad/vad_gmm.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/typedefs.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
static const int32_t kCompVar = 22005;
static const int16_t kLog2Exp = 5909; // log2(exp(1)) in Q12.
diff --git a/webrtc/common_audio/vad/vad_gmm.h b/webrtc/common_audio/vad/vad_gmm.h
index 992a156..6b2d11b 100644
--- a/webrtc/common_audio/vad/vad_gmm.h
+++ b/webrtc/common_audio/vad/vad_gmm.h
@@ -10,10 +10,10 @@
// Gaussian probability calculations internally used in vad_core.c.
-#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
-#define WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
+#ifndef COMMON_AUDIO_VAD_VAD_GMM_H_
+#define COMMON_AUDIO_VAD_VAD_GMM_H_
-#include "webrtc/typedefs.h"
+#include <stdint.h>
// Calculates the probability for |input|, given that |input| comes from a
// normal distribution with mean and standard deviation (|mean|, |std|).
@@ -36,4 +36,4 @@ int32_t WebRtcVad_GaussianProbability(int16_t input,
int16_t std,
int16_t* delta);
-#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
+#endif // COMMON_AUDIO_VAD_VAD_GMM_H_
diff --git a/webrtc/common_audio/vad/vad_sp.c b/webrtc/common_audio/vad/vad_sp.c
index a54be17..d710a37 100644
--- a/webrtc/common_audio/vad/vad_sp.c
+++ b/webrtc/common_audio/vad/vad_sp.c
@@ -8,13 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/vad/vad_sp.h"
+#include "common_audio/vad/vad_sp.h"
-#include <assert.h>
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/vad/vad_core.h"
-#include "webrtc/typedefs.h"
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/vad/vad_core.h"
// Allpass filter coefficients, upper and lower, in Q13.
// Upper: 0.64, Lower: 0.17.
@@ -72,7 +70,7 @@ int16_t WebRtcVad_FindMinimum(VadInstT* self,
int16_t* age = &self->index_vector[offset];
int16_t* smallest_values = &self->low_value_vector[offset];
- assert(channel < kNumChannels);
+ RTC_DCHECK_LT(channel, kNumChannels);
// Each value in |smallest_values| is getting 1 loop older. Update |age|, and
// remove old values.
@@ -81,7 +79,7 @@ int16_t WebRtcVad_FindMinimum(VadInstT* self,
age[i]++;
} else {
// Too old value. Remove from memory and shift larger values downwards.
- for (j = i; j < 16; j++) {
+ for (j = i; j < 15; j++) {
smallest_values[j] = smallest_values[j + 1];
age[j] = age[j + 1];
}
diff --git a/webrtc/common_audio/vad/vad_sp.h b/webrtc/common_audio/vad/vad_sp.h
index 4d2b02a..ff36760 100644
--- a/webrtc/common_audio/vad/vad_sp.h
+++ b/webrtc/common_audio/vad/vad_sp.h
@@ -8,14 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
// This file includes specific signal processing tools used in vad_core.c.
-#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
-#define WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
+#ifndef COMMON_AUDIO_VAD_VAD_SP_H_
+#define COMMON_AUDIO_VAD_VAD_SP_H_
-#include "webrtc/common_audio/vad/vad_core.h"
-#include "webrtc/typedefs.h"
+#include "common_audio/vad/vad_core.h"
// Downsamples the signal by a factor 2, eg. 32->16 or 16->8.
//
@@ -53,4 +51,4 @@ int16_t WebRtcVad_FindMinimum(VadInstT* handle,
int16_t feature_value,
int channel);
-#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
+#endif // COMMON_AUDIO_VAD_VAD_SP_H_
diff --git a/webrtc/common_audio/vad/webrtc_vad.c b/webrtc/common_audio/vad/webrtc_vad.c
index 80c8f3c..49e7682 100644
--- a/webrtc/common_audio/vad/webrtc_vad.c
+++ b/webrtc/common_audio/vad/webrtc_vad.c
@@ -8,14 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/vad/include/webrtc_vad.h"
+#include "common_audio/vad/include/webrtc_vad.h"
#include <stdlib.h>
#include <string.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/vad/vad_core.h"
-#include "webrtc/typedefs.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/vad/vad_core.h"
static const int kInitCheck = 42;
static const int kValidRates[] = { 8000, 16000, 32000, 48000 };
@@ -25,7 +24,6 @@ static const int kMaxFrameLengthMs = 30;
VadInst* WebRtcVad_Create() {
VadInstT* self = (VadInstT*)malloc(sizeof(VadInstT));
- WebRtcSpl_Init();
self->init_flag = 0;
return (VadInst*)self;
diff --git a/webrtc/common_audio/wav_file.cc b/webrtc/common_audio/wav_file.cc
index b14b620..e49126f 100644
--- a/webrtc/common_audio/wav_file.cc
+++ b/webrtc/common_audio/wav_file.cc
@@ -8,175 +8,283 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_audio/wav_file.h"
+#include "common_audio/wav_file.h"
+
+#include <errno.h>
#include <algorithm>
+#include <array>
#include <cstdio>
-#include <limits>
+#include <type_traits>
+#include <utility>
-#include "webrtc/base/checks.h"
-#include "webrtc/base/safe_conversions.h"
-#include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/wav_header.h"
+#include "common_audio/include/audio_util.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/system/arch.h"
namespace webrtc {
+namespace {
+
+static_assert(std::is_trivially_destructible<WavFormat>::value, "");
-// We write 16-bit PCM WAV files.
-static const WavFormat kWavFormat = kWavFormatPcm;
-static const int kBytesPerSample = 2;
+// Checks whether the format is supported or not.
+bool FormatSupported(WavFormat format) {
+ // Only PCM and IEEE Float formats are supported.
+ return format == WavFormat::kWavFormatPcm ||
+ format == WavFormat::kWavFormatIeeeFloat;
+}
// Doesn't take ownership of the file handle and won't close it.
-class ReadableWavFile : public ReadableWav {
+class WavHeaderFileReader : public WavHeaderReader {
public:
- explicit ReadableWavFile(FILE* file) : file_(file) {}
- virtual size_t Read(void* buf, size_t num_bytes) {
- return fread(buf, 1, num_bytes, file_);
+ explicit WavHeaderFileReader(FileWrapper* file) : file_(file) {}
+
+ WavHeaderFileReader(const WavHeaderFileReader&) = delete;
+ WavHeaderFileReader& operator=(const WavHeaderFileReader&) = delete;
+
+ size_t Read(void* buf, size_t num_bytes) override {
+ size_t count = file_->Read(buf, num_bytes);
+ pos_ += count;
+ return count;
+ }
+ bool SeekForward(uint32_t num_bytes) override {
+ bool success = file_->SeekRelative(num_bytes);
+ if (success) {
+ pos_ += num_bytes;
+ }
+ return success;
}
+ int64_t GetPosition() override { return pos_; }
private:
- FILE* file_;
+ FileWrapper* file_;
+ int64_t pos_ = 0;
};
-std::string WavFile::FormatAsString() const {
- std::ostringstream s;
- s << "Sample rate: " << sample_rate() << " Hz, Channels: " << num_channels()
- << ", Duration: "
- << (1.f * num_samples()) / (num_channels() * sample_rate()) << " s";
- return s.str();
-}
+constexpr size_t kMaxChunksize = 4096;
+
+} // namespace
WavReader::WavReader(const std::string& filename)
- : file_handle_(fopen(filename.c_str(), "rb")) {
- RTC_CHECK(file_handle_) << "Could not open wav file for reading.";
-
- ReadableWavFile readable(file_handle_);
- WavFormat format;
- int bytes_per_sample;
- RTC_CHECK(ReadWavHeader(&readable, &num_channels_, &sample_rate_, &format,
- &bytes_per_sample, &num_samples_));
- num_samples_remaining_ = num_samples_;
- RTC_CHECK_EQ(kWavFormat, format);
- RTC_CHECK_EQ(kBytesPerSample, bytes_per_sample);
+ : WavReader(FileWrapper::OpenReadOnly(filename)) {}
+
+WavReader::WavReader(FileWrapper file) : file_(std::move(file)) {
+ RTC_CHECK(file_.is_open())
+ << "Invalid file. Could not create file handle for wav file.";
+
+ WavHeaderFileReader readable(&file_);
+ size_t bytes_per_sample;
+ RTC_CHECK(ReadWavHeader(&readable, &num_channels_, &sample_rate_, &format_,
+ &bytes_per_sample, &num_samples_in_file_,
+ &data_start_pos_));
+ num_unread_samples_ = num_samples_in_file_;
+ RTC_CHECK(FormatSupported(format_)) << "Non-implemented wav-format";
}
-WavReader::~WavReader() {
- Close();
+void WavReader::Reset() {
+ RTC_CHECK(file_.SeekTo(data_start_pos_))
+ << "Failed to set position in the file to WAV data start position";
+ num_unread_samples_ = num_samples_in_file_;
}
-size_t WavReader::ReadSamples(size_t num_samples, int16_t* samples) {
+size_t WavReader::ReadSamples(const size_t num_samples,
+ int16_t* const samples) {
#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
#error "Need to convert samples to big-endian when reading from WAV file"
#endif
- // There could be metadata after the audio; ensure we don't read it.
- num_samples = std::min(rtc::checked_cast<uint32_t>(num_samples),
- num_samples_remaining_);
- const size_t read =
- fread(samples, sizeof(*samples), num_samples, file_handle_);
- // If we didn't read what was requested, ensure we've reached the EOF.
- RTC_CHECK(read == num_samples || feof(file_handle_));
- RTC_CHECK_LE(read, num_samples_remaining_);
- num_samples_remaining_ -= rtc::checked_cast<uint32_t>(read);
- return read;
+
+ size_t num_samples_left_to_read = num_samples;
+ size_t next_chunk_start = 0;
+ while (num_samples_left_to_read > 0 && num_unread_samples_ > 0) {
+ const size_t chunk_size = std::min(
+ std::min(kMaxChunksize, num_samples_left_to_read), num_unread_samples_);
+ size_t num_bytes_read;
+ size_t num_samples_read;
+ if (format_ == WavFormat::kWavFormatIeeeFloat) {
+ std::array<float, kMaxChunksize> samples_to_convert;
+ num_bytes_read = file_.Read(samples_to_convert.data(),
+ chunk_size * sizeof(samples_to_convert[0]));
+ num_samples_read = num_bytes_read / sizeof(samples_to_convert[0]);
+
+ for (size_t j = 0; j < num_samples_read; ++j) {
+ samples[next_chunk_start + j] = FloatToS16(samples_to_convert[j]);
+ }
+ } else {
+ RTC_CHECK_EQ(format_, WavFormat::kWavFormatPcm);
+ num_bytes_read = file_.Read(&samples[next_chunk_start],
+ chunk_size * sizeof(samples[0]));
+ num_samples_read = num_bytes_read / sizeof(samples[0]);
+ }
+ RTC_CHECK(num_samples_read == 0 || (num_bytes_read % num_samples_read) == 0)
+ << "Corrupt file: file ended in the middle of a sample.";
+ RTC_CHECK(num_samples_read == chunk_size || file_.ReadEof())
+ << "Corrupt file: payload size does not match header.";
+
+ next_chunk_start += num_samples_read;
+ num_unread_samples_ -= num_samples_read;
+ num_samples_left_to_read -= num_samples_read;
+ }
+
+ return num_samples - num_samples_left_to_read;
}
-size_t WavReader::ReadSamples(size_t num_samples, float* samples) {
- static const size_t kChunksize = 4096 / sizeof(uint16_t);
- size_t read = 0;
- for (size_t i = 0; i < num_samples; i += kChunksize) {
- int16_t isamples[kChunksize];
- size_t chunk = std::min(kChunksize, num_samples - i);
- chunk = ReadSamples(chunk, isamples);
- for (size_t j = 0; j < chunk; ++j)
- samples[i + j] = isamples[j];
- read += chunk;
+size_t WavReader::ReadSamples(const size_t num_samples, float* const samples) {
+#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
+#error "Need to convert samples to big-endian when reading from WAV file"
+#endif
+
+ size_t num_samples_left_to_read = num_samples;
+ size_t next_chunk_start = 0;
+ while (num_samples_left_to_read > 0 && num_unread_samples_ > 0) {
+ const size_t chunk_size = std::min(
+ std::min(kMaxChunksize, num_samples_left_to_read), num_unread_samples_);
+ size_t num_bytes_read;
+ size_t num_samples_read;
+ if (format_ == WavFormat::kWavFormatPcm) {
+ std::array<int16_t, kMaxChunksize> samples_to_convert;
+ num_bytes_read = file_.Read(samples_to_convert.data(),
+ chunk_size * sizeof(samples_to_convert[0]));
+ num_samples_read = num_bytes_read / sizeof(samples_to_convert[0]);
+
+ for (size_t j = 0; j < num_samples_read; ++j) {
+ samples[next_chunk_start + j] =
+ static_cast<float>(samples_to_convert[j]);
+ }
+ } else {
+ RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat);
+ num_bytes_read = file_.Read(&samples[next_chunk_start],
+ chunk_size * sizeof(samples[0]));
+ num_samples_read = num_bytes_read / sizeof(samples[0]);
+
+ for (size_t j = 0; j < num_samples_read; ++j) {
+ samples[next_chunk_start + j] =
+ FloatToFloatS16(samples[next_chunk_start + j]);
+ }
+ }
+ RTC_CHECK(num_samples_read == 0 || (num_bytes_read % num_samples_read) == 0)
+ << "Corrupt file: file ended in the middle of a sample.";
+ RTC_CHECK(num_samples_read == chunk_size || file_.ReadEof())
+ << "Corrupt file: payload size does not match header.";
+
+ next_chunk_start += num_samples_read;
+ num_unread_samples_ -= num_samples_read;
+ num_samples_left_to_read -= num_samples_read;
}
- return read;
+
+ return num_samples - num_samples_left_to_read;
}
void WavReader::Close() {
- RTC_CHECK_EQ(0, fclose(file_handle_));
- file_handle_ = NULL;
+ file_.Close();
}
-WavWriter::WavWriter(const std::string& filename, int sample_rate,
- int num_channels)
+WavWriter::WavWriter(const std::string& filename,
+ int sample_rate,
+ size_t num_channels,
+ SampleFormat sample_format)
+ // Unlike plain fopen, OpenWriteOnly takes care of filename utf8 ->
+ // wchar conversion on windows.
+ : WavWriter(FileWrapper::OpenWriteOnly(filename),
+ sample_rate,
+ num_channels,
+ sample_format) {}
+
+WavWriter::WavWriter(FileWrapper file,
+ int sample_rate,
+ size_t num_channels,
+ SampleFormat sample_format)
: sample_rate_(sample_rate),
num_channels_(num_channels),
- num_samples_(0),
- file_handle_(fopen(filename.c_str(), "wb")) {
- RTC_CHECK(file_handle_) << "Could not open wav file for writing.";
- RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, kWavFormat,
- kBytesPerSample, num_samples_));
+ num_samples_written_(0),
+ format_(sample_format == SampleFormat::kInt16
+ ? WavFormat::kWavFormatPcm
+ : WavFormat::kWavFormatIeeeFloat),
+ file_(std::move(file)) {
+ // Handle errors from the OpenWriteOnly call in above constructor.
+ RTC_CHECK(file_.is_open()) << "Invalid file. Could not create wav file.";
+
+ RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, format_,
+ num_samples_written_));
// Write a blank placeholder header, since we need to know the total number
// of samples before we can fill in the real data.
- static const uint8_t blank_header[kWavHeaderSize] = {0};
- RTC_CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
-}
-
-WavWriter::~WavWriter() {
- Close();
+ static const uint8_t blank_header[MaxWavHeaderSize()] = {0};
+ RTC_CHECK(file_.Write(blank_header, WavHeaderSize(format_)));
}
void WavWriter::WriteSamples(const int16_t* samples, size_t num_samples) {
#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
#error "Need to convert samples to little-endian when writing to WAV file"
#endif
- const size_t written =
- fwrite(samples, sizeof(*samples), num_samples, file_handle_);
- RTC_CHECK_EQ(num_samples, written);
- num_samples_ += static_cast<uint32_t>(written);
- RTC_CHECK(written <= std::numeric_limits<uint32_t>::max() ||
- num_samples_ >= written); // detect uint32_t overflow
-}
-
-void WavWriter::WriteSamples(const float* samples, size_t num_samples) {
- static const size_t kChunksize = 4096 / sizeof(uint16_t);
- for (size_t i = 0; i < num_samples; i += kChunksize) {
- int16_t isamples[kChunksize];
- const size_t chunk = std::min(kChunksize, num_samples - i);
- FloatS16ToS16(samples + i, chunk, isamples);
- WriteSamples(isamples, chunk);
- }
-}
-void WavWriter::Close() {
- RTC_CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
- uint8_t header[kWavHeaderSize];
- WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
- kBytesPerSample, num_samples_);
- RTC_CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
- RTC_CHECK_EQ(0, fclose(file_handle_));
- file_handle_ = NULL;
-}
+ for (size_t i = 0; i < num_samples; i += kMaxChunksize) {
+ const size_t num_remaining_samples = num_samples - i;
+ const size_t num_samples_to_write =
+ std::min(kMaxChunksize, num_remaining_samples);
-} // namespace webrtc
+ if (format_ == WavFormat::kWavFormatPcm) {
+ RTC_CHECK(
+ file_.Write(&samples[i], num_samples_to_write * sizeof(samples[0])));
+ } else {
+ RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat);
+ std::array<float, kMaxChunksize> converted_samples;
+ for (size_t j = 0; j < num_samples_to_write; ++j) {
+ converted_samples[j] = S16ToFloat(samples[i + j]);
+ }
+ RTC_CHECK(
+ file_.Write(converted_samples.data(),
+ num_samples_to_write * sizeof(converted_samples[0])));
+ }
-rtc_WavWriter* rtc_WavOpen(const char* filename,
- int sample_rate,
- int num_channels) {
- return reinterpret_cast<rtc_WavWriter*>(
- new webrtc::WavWriter(filename, sample_rate, num_channels));
+ num_samples_written_ += num_samples_to_write;
+ RTC_CHECK_GE(num_samples_written_,
+ num_samples_to_write); // detect size_t overflow
+ }
}
-void rtc_WavClose(rtc_WavWriter* wf) {
- delete reinterpret_cast<webrtc::WavWriter*>(wf);
-}
+void WavWriter::WriteSamples(const float* samples, size_t num_samples) {
+#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
+#error "Need to convert samples to little-endian when writing to WAV file"
+#endif
-void rtc_WavWriteSamples(rtc_WavWriter* wf,
- const float* samples,
- size_t num_samples) {
- reinterpret_cast<webrtc::WavWriter*>(wf)->WriteSamples(samples, num_samples);
-}
+ for (size_t i = 0; i < num_samples; i += kMaxChunksize) {
+ const size_t num_remaining_samples = num_samples - i;
+ const size_t num_samples_to_write =
+ std::min(kMaxChunksize, num_remaining_samples);
-int rtc_WavSampleRate(const rtc_WavWriter* wf) {
- return reinterpret_cast<const webrtc::WavWriter*>(wf)->sample_rate();
-}
+ if (format_ == WavFormat::kWavFormatPcm) {
+ std::array<int16_t, kMaxChunksize> converted_samples;
+ for (size_t j = 0; j < num_samples_to_write; ++j) {
+ converted_samples[j] = FloatS16ToS16(samples[i + j]);
+ }
+ RTC_CHECK(
+ file_.Write(converted_samples.data(),
+ num_samples_to_write * sizeof(converted_samples[0])));
+ } else {
+ RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat);
+ std::array<float, kMaxChunksize> converted_samples;
+ for (size_t j = 0; j < num_samples_to_write; ++j) {
+ converted_samples[j] = FloatS16ToFloat(samples[i + j]);
+ }
+ RTC_CHECK(
+ file_.Write(converted_samples.data(),
+ num_samples_to_write * sizeof(converted_samples[0])));
+ }
-int rtc_WavNumChannels(const rtc_WavWriter* wf) {
- return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_channels();
+ num_samples_written_ += num_samples_to_write;
+ RTC_CHECK(num_samples_written_ >=
+ num_samples_to_write); // detect size_t overflow
+ }
}
-uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf) {
- return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_samples();
+void WavWriter::Close() {
+ RTC_CHECK(file_.Rewind());
+ std::array<uint8_t, MaxWavHeaderSize()> header;
+ size_t header_size;
+ WriteWavHeader(num_channels_, sample_rate_, format_, num_samples_written_,
+ header.data(), &header_size);
+ RTC_CHECK(file_.Write(header.data(), header_size));
+ RTC_CHECK(file_.Close());
}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/wav_file.h b/webrtc/common_audio/wav_file.h
index 42b0618..dda611b 100644
--- a/webrtc/common_audio/wav_file.h
+++ b/webrtc/common_audio/wav_file.h
@@ -8,60 +8,69 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_WAV_FILE_H_
-#define WEBRTC_COMMON_AUDIO_WAV_FILE_H_
-
-#ifdef __cplusplus
+#ifndef COMMON_AUDIO_WAV_FILE_H_
+#define COMMON_AUDIO_WAV_FILE_H_
#include <stdint.h>
+
#include <cstddef>
#include <string>
-#include "webrtc/base/constructormagic.h"
+#include "common_audio/wav_header.h"
+#include "rtc_base/system/file_wrapper.h"
namespace webrtc {
-// Interface to provide access to WAV file parameters.
+// Interface to provide access WAV file parameters.
class WavFile {
public:
+ enum class SampleFormat { kInt16, kFloat };
+
virtual ~WavFile() {}
virtual int sample_rate() const = 0;
- virtual int num_channels() const = 0;
- virtual uint32_t num_samples() const = 0;
-
- // Returns a human-readable string containing the audio format.
- std::string FormatAsString() const;
+ virtual size_t num_channels() const = 0;
+ virtual size_t num_samples() const = 0;
};
-// Simple C++ class for writing 16-bit PCM WAV files. All error handling is
-// by calls to RTC_CHECK(), making it unsuitable for anything but debug code.
+// Simple C++ class for writing 16-bit integer and 32 bit floating point PCM WAV
+// files. All error handling is by calls to RTC_CHECK(), making it unsuitable
+// for anything but debug code.
class WavWriter final : public WavFile {
public:
- // Open a new WAV file for writing.
- WavWriter(const std::string& filename, int sample_rate, int num_channels);
-
- // Close the WAV file, after writing its header.
- ~WavWriter();
+ // Opens a new WAV file for writing.
+ WavWriter(const std::string& filename,
+ int sample_rate,
+ size_t num_channels,
+ SampleFormat sample_format = SampleFormat::kInt16);
+ WavWriter(FileWrapper file,
+ int sample_rate,
+ size_t num_channels,
+ SampleFormat sample_format = SampleFormat::kInt16);
+
+ // Closes the WAV file, after writing its header.
+ ~WavWriter() { Close(); }
+
+ WavWriter(const WavWriter&) = delete;
+ WavWriter& operator=(const WavWriter&) = delete;
// Write additional samples to the file. Each sample is in the range
- // [-32768,32767], and there must be the previously specified number of
+ // [-32768.0,32767.0], and there must be the previously specified number of
// interleaved channels.
void WriteSamples(const float* samples, size_t num_samples);
void WriteSamples(const int16_t* samples, size_t num_samples);
int sample_rate() const override { return sample_rate_; }
- int num_channels() const override { return num_channels_; }
- uint32_t num_samples() const override { return num_samples_; }
+ size_t num_channels() const override { return num_channels_; }
+ size_t num_samples() const override { return num_samples_written_; }
private:
void Close();
const int sample_rate_;
- const int num_channels_;
- uint32_t num_samples_; // Total number of samples written to file.
- FILE* file_handle_; // Output file, owned by this class
-
- RTC_DISALLOW_COPY_AND_ASSIGN(WavWriter);
+ const size_t num_channels_;
+ size_t num_samples_written_;
+ WavFormat format_;
+ FileWrapper file_;
};
// Follows the conventions of WavWriter.
@@ -69,9 +78,16 @@ class WavReader final : public WavFile {
public:
// Opens an existing WAV file for reading.
explicit WavReader(const std::string& filename);
+ explicit WavReader(FileWrapper file);
// Close the WAV file.
- ~WavReader();
+ ~WavReader() { Close(); }
+
+ WavReader(const WavReader&) = delete;
+ WavReader& operator=(const WavReader&) = delete;
+
+ // Resets position to the beginning of the file.
+ void Reset();
// Returns the number of samples read. If this is less than requested,
// verifies that the end of the file was reached.
@@ -79,40 +95,21 @@ class WavReader final : public WavFile {
size_t ReadSamples(size_t num_samples, int16_t* samples);
int sample_rate() const override { return sample_rate_; }
- int num_channels() const override { return num_channels_; }
- uint32_t num_samples() const override { return num_samples_; }
+ size_t num_channels() const override { return num_channels_; }
+ size_t num_samples() const override { return num_samples_in_file_; }
private:
void Close();
int sample_rate_;
- int num_channels_;
- uint32_t num_samples_; // Total number of samples in the file.
- uint32_t num_samples_remaining_;
- FILE* file_handle_; // Input file, owned by this class.
-
- RTC_DISALLOW_COPY_AND_ASSIGN(WavReader);
+ size_t num_channels_;
+ WavFormat format_;
+ size_t num_samples_in_file_;
+ size_t num_unread_samples_;
+ FileWrapper file_;
+ int64_t
+ data_start_pos_; // Position in the file immediately after WAV header.
};
} // namespace webrtc
-extern "C" {
-#endif // __cplusplus
-
-// C wrappers for the WavWriter class.
-typedef struct rtc_WavWriter rtc_WavWriter;
-rtc_WavWriter* rtc_WavOpen(const char* filename,
- int sample_rate,
- int num_channels);
-void rtc_WavClose(rtc_WavWriter* wf);
-void rtc_WavWriteSamples(rtc_WavWriter* wf,
- const float* samples,
- size_t num_samples);
-int rtc_WavSampleRate(const rtc_WavWriter* wf);
-int rtc_WavNumChannels(const rtc_WavWriter* wf);
-uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // WEBRTC_COMMON_AUDIO_WAV_FILE_H_
+#endif // COMMON_AUDIO_WAV_FILE_H_
diff --git a/webrtc/common_audio/wav_header.cc b/webrtc/common_audio/wav_header.cc
index 61cfffe..d3dca90 100644
--- a/webrtc/common_audio/wav_header.cc
+++ b/webrtc/common_audio/wav_header.cc
@@ -12,28 +12,42 @@
// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ and
// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
-#include "webrtc/common_audio/wav_header.h"
+#include "common_audio/wav_header.h"
-#include <algorithm>
#include <cstring>
#include <limits>
#include <string>
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/include/audio_util.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/sanitizer.h"
+#include "rtc_base/system/arch.h"
namespace webrtc {
namespace {
+#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
+#error "Code not working properly for big endian platforms."
+#endif
+
+#pragma pack(2)
struct ChunkHeader {
uint32_t ID;
uint32_t Size;
};
static_assert(sizeof(ChunkHeader) == 8, "ChunkHeader size");
+#pragma pack(2)
+struct RiffHeader {
+ ChunkHeader header;
+ uint32_t Format;
+};
+static_assert(sizeof(RiffHeader) == sizeof(ChunkHeader) + 4, "RiffHeader size");
+
// We can't nest this definition in WavHeader, because VS2013 gives an error
// on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand".
-struct FmtSubchunk {
+#pragma pack(2)
+struct FmtPcmSubchunk {
ChunkHeader header;
uint16_t AudioFormat;
uint16_t NumChannels;
@@ -42,37 +56,247 @@ struct FmtSubchunk {
uint16_t BlockAlign;
uint16_t BitsPerSample;
};
-static_assert(sizeof(FmtSubchunk) == 24, "FmtSubchunk size");
-const uint32_t kFmtSubchunkSize = sizeof(FmtSubchunk) - sizeof(ChunkHeader);
+static_assert(sizeof(FmtPcmSubchunk) == 24, "FmtPcmSubchunk size");
+const uint32_t kFmtPcmSubchunkSize =
+ sizeof(FmtPcmSubchunk) - sizeof(ChunkHeader);
-struct WavHeader {
+// Pack struct to avoid additional padding bytes.
+#pragma pack(2)
+struct FmtIeeeFloatSubchunk {
+ ChunkHeader header;
+ uint16_t AudioFormat;
+ uint16_t NumChannels;
+ uint32_t SampleRate;
+ uint32_t ByteRate;
+ uint16_t BlockAlign;
+ uint16_t BitsPerSample;
+ uint16_t ExtensionSize;
+};
+static_assert(sizeof(FmtIeeeFloatSubchunk) == 26, "FmtIeeeFloatSubchunk size");
+const uint32_t kFmtIeeeFloatSubchunkSize =
+ sizeof(FmtIeeeFloatSubchunk) - sizeof(ChunkHeader);
+
+// Simple PCM wav header. It does not include chunks that are not essential to
+// read audio samples.
+#pragma pack(2)
+struct WavHeaderPcm {
+ WavHeaderPcm(const WavHeaderPcm&) = default;
+ WavHeaderPcm& operator=(const WavHeaderPcm&) = default;
+ RiffHeader riff;
+ FmtPcmSubchunk fmt;
+ struct {
+ ChunkHeader header;
+ } data;
+};
+static_assert(sizeof(WavHeaderPcm) == kPcmWavHeaderSize,
+ "no padding in header");
+
+// IEEE Float Wav header, includes extra chunks necessary for proper non-PCM
+// WAV implementation.
+#pragma pack(2)
+struct WavHeaderIeeeFloat {
+ WavHeaderIeeeFloat(const WavHeaderIeeeFloat&) = default;
+ WavHeaderIeeeFloat& operator=(const WavHeaderIeeeFloat&) = default;
+ RiffHeader riff;
+ FmtIeeeFloatSubchunk fmt;
struct {
ChunkHeader header;
- uint32_t Format;
- } riff;
- FmtSubchunk fmt;
+ uint32_t SampleLength;
+ } fact;
struct {
ChunkHeader header;
} data;
};
-static_assert(sizeof(WavHeader) == kWavHeaderSize, "no padding in header");
+static_assert(sizeof(WavHeaderIeeeFloat) == kIeeeFloatWavHeaderSize,
+ "no padding in header");
+
+uint32_t PackFourCC(char a, char b, char c, char d) {
+ uint32_t packed_value =
+ static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 |
+ static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24;
+ return packed_value;
+}
-} // namespace
+std::string ReadFourCC(uint32_t x) {
+ return std::string(reinterpret_cast<char*>(&x), 4);
+}
+
+uint16_t MapWavFormatToHeaderField(WavFormat format) {
+ switch (format) {
+ case WavFormat::kWavFormatPcm:
+ return 1;
+ case WavFormat::kWavFormatIeeeFloat:
+ return 3;
+ case WavFormat::kWavFormatALaw:
+ return 6;
+ case WavFormat::kWavFormatMuLaw:
+ return 7;
+ }
+ RTC_CHECK(false);
+}
+
+WavFormat MapHeaderFieldToWavFormat(uint16_t format_header_value) {
+ if (format_header_value == 1) {
+ return WavFormat::kWavFormatPcm;
+ }
+ if (format_header_value == 3) {
+ return WavFormat::kWavFormatIeeeFloat;
+ }
+
+ RTC_CHECK(false) << "Unsupported WAV format";
+}
+
+uint32_t RiffChunkSize(size_t bytes_in_payload, size_t header_size) {
+ return static_cast<uint32_t>(bytes_in_payload + header_size -
+ sizeof(ChunkHeader));
+}
+
+uint32_t ByteRate(size_t num_channels,
+ int sample_rate,
+ size_t bytes_per_sample) {
+ return static_cast<uint32_t>(num_channels * sample_rate * bytes_per_sample);
+}
+
+uint16_t BlockAlign(size_t num_channels, size_t bytes_per_sample) {
+ return static_cast<uint16_t>(num_channels * bytes_per_sample);
+}
+
+// Finds a chunk having the sought ID. If found, then |readable| points to the
+// first byte of the sought chunk data. If not found, the end of the file is
+// reached.
+bool FindWaveChunk(ChunkHeader* chunk_header,
+ WavHeaderReader* readable,
+ const std::string sought_chunk_id) {
+ RTC_DCHECK_EQ(sought_chunk_id.size(), 4);
+ while (true) {
+ if (readable->Read(chunk_header, sizeof(*chunk_header)) !=
+ sizeof(*chunk_header))
+ return false; // EOF.
+ if (ReadFourCC(chunk_header->ID) == sought_chunk_id)
+ return true; // Sought chunk found.
+ // Ignore current chunk by skipping its payload.
+ if (!readable->SeekForward(chunk_header->Size))
+ return false; // EOF or error.
+ }
+}
+
+bool ReadFmtChunkData(FmtPcmSubchunk* fmt_subchunk, WavHeaderReader* readable) {
+ // Reads "fmt " chunk payload.
+ if (readable->Read(&(fmt_subchunk->AudioFormat), kFmtPcmSubchunkSize) !=
+ kFmtPcmSubchunkSize)
+ return false;
+ const uint32_t fmt_size = fmt_subchunk->header.Size;
+ if (fmt_size != kFmtPcmSubchunkSize) {
+ // There is an optional two-byte extension field permitted to be present
+ // with PCM, but which must be zero.
+ int16_t ext_size;
+ if (kFmtPcmSubchunkSize + sizeof(ext_size) != fmt_size)
+ return false;
+ if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size))
+ return false;
+ if (ext_size != 0)
+ return false;
+ }
+ return true;
+}
+
+void WritePcmWavHeader(size_t num_channels,
+ int sample_rate,
+ size_t bytes_per_sample,
+ size_t num_samples,
+ uint8_t* buf,
+ size_t* header_size) {
+ RTC_CHECK(buf);
+ RTC_CHECK(header_size);
+ *header_size = kPcmWavHeaderSize;
+ auto header = rtc::MsanUninitialized<WavHeaderPcm>({});
+ const size_t bytes_in_payload = bytes_per_sample * num_samples;
+
+ header.riff.header.ID = PackFourCC('R', 'I', 'F', 'F');
+ header.riff.header.Size = RiffChunkSize(bytes_in_payload, *header_size);
+ header.riff.Format = PackFourCC('W', 'A', 'V', 'E');
+ header.fmt.header.ID = PackFourCC('f', 'm', 't', ' ');
+ header.fmt.header.Size = kFmtPcmSubchunkSize;
+ header.fmt.AudioFormat = MapWavFormatToHeaderField(WavFormat::kWavFormatPcm);
+ header.fmt.NumChannels = static_cast<uint16_t>(num_channels);
+ header.fmt.SampleRate = sample_rate;
+ header.fmt.ByteRate = ByteRate(num_channels, sample_rate, bytes_per_sample);
+ header.fmt.BlockAlign = BlockAlign(num_channels, bytes_per_sample);
+ header.fmt.BitsPerSample = static_cast<uint16_t>(8 * bytes_per_sample);
+ header.data.header.ID = PackFourCC('d', 'a', 't', 'a');
+ header.data.header.Size = static_cast<uint32_t>(bytes_in_payload);
+
+ // Do an extra copy rather than writing everything to buf directly, since buf
+ // might not be correctly aligned.
+ memcpy(buf, &header, *header_size);
+}
+
+void WriteIeeeFloatWavHeader(size_t num_channels,
+ int sample_rate,
+ size_t bytes_per_sample,
+ size_t num_samples,
+ uint8_t* buf,
+ size_t* header_size) {
+ RTC_CHECK(buf);
+ RTC_CHECK(header_size);
+ *header_size = kIeeeFloatWavHeaderSize;
+ auto header = rtc::MsanUninitialized<WavHeaderIeeeFloat>({});
+ const size_t bytes_in_payload = bytes_per_sample * num_samples;
+
+ header.riff.header.ID = PackFourCC('R', 'I', 'F', 'F');
+ header.riff.header.Size = RiffChunkSize(bytes_in_payload, *header_size);
+ header.riff.Format = PackFourCC('W', 'A', 'V', 'E');
+ header.fmt.header.ID = PackFourCC('f', 'm', 't', ' ');
+ header.fmt.header.Size = kFmtIeeeFloatSubchunkSize;
+ header.fmt.AudioFormat =
+ MapWavFormatToHeaderField(WavFormat::kWavFormatIeeeFloat);
+ header.fmt.NumChannels = static_cast<uint16_t>(num_channels);
+ header.fmt.SampleRate = sample_rate;
+ header.fmt.ByteRate = ByteRate(num_channels, sample_rate, bytes_per_sample);
+ header.fmt.BlockAlign = BlockAlign(num_channels, bytes_per_sample);
+ header.fmt.BitsPerSample = static_cast<uint16_t>(8 * bytes_per_sample);
+ header.fmt.ExtensionSize = 0;
+ header.fact.header.ID = PackFourCC('f', 'a', 'c', 't');
+ header.fact.header.Size = 4;
+ header.fact.SampleLength = static_cast<uint32_t>(num_channels * num_samples);
+ header.data.header.ID = PackFourCC('d', 'a', 't', 'a');
+ header.data.header.Size = static_cast<uint32_t>(bytes_in_payload);
+
+ // Do an extra copy rather than writing everything to buf directly, since buf
+ // might not be correctly aligned.
+ memcpy(buf, &header, *header_size);
+}
+
+// Returns the number of bytes per sample for the format.
+size_t GetFormatBytesPerSample(WavFormat format) {
+ switch (format) {
+ case WavFormat::kWavFormatPcm:
+ // Other values may be OK, but for now we're conservative.
+ return 2;
+ case WavFormat::kWavFormatALaw:
+ case WavFormat::kWavFormatMuLaw:
+ return 1;
+ case WavFormat::kWavFormatIeeeFloat:
+ return 4;
+ default:
+ RTC_CHECK(false);
+ return 2;
+ }
+}
-bool CheckWavParameters(int num_channels,
+bool CheckWavParameters(size_t num_channels,
int sample_rate,
WavFormat format,
- int bytes_per_sample,
- uint32_t num_samples) {
+ size_t bytes_per_sample,
+ size_t num_samples) {
// num_channels, sample_rate, and bytes_per_sample must be positive, must fit
// in their respective fields, and their product must fit in the 32-bit
// ByteRate field.
- if (num_channels <= 0 || sample_rate <= 0 || bytes_per_sample <= 0)
+ if (num_channels == 0 || sample_rate <= 0 || bytes_per_sample == 0)
return false;
if (static_cast<uint64_t>(sample_rate) > std::numeric_limits<uint32_t>::max())
return false;
- if (static_cast<uint64_t>(num_channels) >
- std::numeric_limits<uint16_t>::max())
+ if (num_channels > std::numeric_limits<uint16_t>::max())
return false;
if (static_cast<uint64_t>(bytes_per_sample) * 8 >
std::numeric_limits<uint16_t>::max())
@@ -83,26 +307,29 @@ bool CheckWavParameters(int num_channels,
// format and bytes_per_sample must agree.
switch (format) {
- case kWavFormatPcm:
+ case WavFormat::kWavFormatPcm:
// Other values may be OK, but for now we're conservative:
if (bytes_per_sample != 1 && bytes_per_sample != 2)
return false;
break;
- case kWavFormatALaw:
- case kWavFormatMuLaw:
+ case WavFormat::kWavFormatALaw:
+ case WavFormat::kWavFormatMuLaw:
if (bytes_per_sample != 1)
return false;
break;
+ case WavFormat::kWavFormatIeeeFloat:
+ if (bytes_per_sample != 4)
+ return false;
+ break;
default:
return false;
}
// The number of bytes in the file, not counting the first ChunkHeader, must
// be less than 2^32; otherwise, the ChunkSize field overflows.
- const uint32_t max_samples =
- (std::numeric_limits<uint32_t>::max()
- - (kWavHeaderSize - sizeof(ChunkHeader))) /
- bytes_per_sample;
+ const size_t header_size = kPcmWavHeaderSize - sizeof(ChunkHeader);
+ const size_t max_samples =
+ (std::numeric_limits<uint32_t>::max() - header_size) / bytes_per_sample;
if (num_samples > max_samples)
return false;
@@ -113,130 +340,102 @@ bool CheckWavParameters(int num_channels,
return true;
}
-#ifdef WEBRTC_ARCH_LITTLE_ENDIAN
-static inline void WriteLE16(uint16_t* f, uint16_t x) { *f = x; }
-static inline void WriteLE32(uint32_t* f, uint32_t x) { *f = x; }
-static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
- *f = static_cast<uint32_t>(a)
- | static_cast<uint32_t>(b) << 8
- | static_cast<uint32_t>(c) << 16
- | static_cast<uint32_t>(d) << 24;
-}
-
-static inline uint16_t ReadLE16(uint16_t x) { return x; }
-static inline uint32_t ReadLE32(uint32_t x) { return x; }
-static inline std::string ReadFourCC(uint32_t x) {
- return std::string(reinterpret_cast<char*>(&x), 4);
-}
-#else
-#error "Write be-to-le conversion functions"
-#endif
-
-static inline uint32_t RiffChunkSize(uint32_t bytes_in_payload) {
- return bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader);
-}
-
-static inline uint32_t ByteRate(int num_channels, int sample_rate,
- int bytes_per_sample) {
- return static_cast<uint32_t>(num_channels) * sample_rate * bytes_per_sample;
-}
+} // namespace
-static inline uint16_t BlockAlign(int num_channels, int bytes_per_sample) {
- return num_channels * bytes_per_sample;
+bool CheckWavParameters(size_t num_channels,
+ int sample_rate,
+ WavFormat format,
+ size_t num_samples) {
+ return CheckWavParameters(num_channels, sample_rate, format,
+ GetFormatBytesPerSample(format), num_samples);
}
-void WriteWavHeader(uint8_t* buf,
- int num_channels,
+void WriteWavHeader(size_t num_channels,
int sample_rate,
WavFormat format,
- int bytes_per_sample,
- uint32_t num_samples) {
+ size_t num_samples,
+ uint8_t* buf,
+ size_t* header_size) {
+ RTC_CHECK(buf);
+ RTC_CHECK(header_size);
+
+ const size_t bytes_per_sample = GetFormatBytesPerSample(format);
RTC_CHECK(CheckWavParameters(num_channels, sample_rate, format,
bytes_per_sample, num_samples));
-
- WavHeader header;
- const uint32_t bytes_in_payload = bytes_per_sample * num_samples;
-
- WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F');
- WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload));
- WriteFourCC(&header.riff.Format, 'W', 'A', 'V', 'E');
-
- WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' ');
- WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize);
- WriteLE16(&header.fmt.AudioFormat, format);
- WriteLE16(&header.fmt.NumChannels, num_channels);
- WriteLE32(&header.fmt.SampleRate, sample_rate);
- WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate,
- bytes_per_sample));
- WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample));
- WriteLE16(&header.fmt.BitsPerSample, 8 * bytes_per_sample);
-
- WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a');
- WriteLE32(&header.data.header.Size, bytes_in_payload);
-
- // Do an extra copy rather than writing everything to buf directly, since buf
- // might not be correctly aligned.
- memcpy(buf, &header, kWavHeaderSize);
+ if (format == WavFormat::kWavFormatPcm) {
+ WritePcmWavHeader(num_channels, sample_rate, bytes_per_sample, num_samples,
+ buf, header_size);
+ } else {
+ RTC_CHECK_EQ(format, WavFormat::kWavFormatIeeeFloat);
+ WriteIeeeFloatWavHeader(num_channels, sample_rate, bytes_per_sample,
+ num_samples, buf, header_size);
+ }
}
-bool ReadWavHeader(ReadableWav* readable,
- int* num_channels,
+bool ReadWavHeader(WavHeaderReader* readable,
+ size_t* num_channels,
int* sample_rate,
WavFormat* format,
- int* bytes_per_sample,
- uint32_t* num_samples) {
- WavHeader header;
- if (readable->Read(&header, kWavHeaderSize - sizeof(header.data)) !=
- kWavHeaderSize - sizeof(header.data))
+ size_t* bytes_per_sample,
+ size_t* num_samples,
+ int64_t* data_start_pos) {
+ // Read using the PCM header, even though it might be float Wav file
+ auto header = rtc::MsanUninitialized<WavHeaderPcm>({});
+
+ // Read RIFF chunk.
+ if (readable->Read(&header.riff, sizeof(header.riff)) != sizeof(header.riff))
+ return false;
+ if (ReadFourCC(header.riff.header.ID) != "RIFF")
+ return false;
+ if (ReadFourCC(header.riff.Format) != "WAVE")
return false;
- const uint32_t fmt_size = ReadLE32(header.fmt.header.Size);
- if (fmt_size != kFmtSubchunkSize) {
- // There is an optional two-byte extension field permitted to be present
- // with PCM, but which must be zero.
- int16_t ext_size;
- if (kFmtSubchunkSize + sizeof(ext_size) != fmt_size)
- return false;
- if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size))
- return false;
- if (ext_size != 0)
- return false;
+ // Find "fmt " and "data" chunks. While the official Wave file specification
+ // does not put requirements on the chunks order, it is uncommon to find the
+ // "data" chunk before the "fmt " one. The code below fails if this is not the
+ // case.
+ if (!FindWaveChunk(&header.fmt.header, readable, "fmt ")) {
+ RTC_LOG(LS_ERROR) << "Cannot find 'fmt ' chunk.";
+ return false;
}
- if (readable->Read(&header.data, sizeof(header.data)) != sizeof(header.data))
+ if (!ReadFmtChunkData(&header.fmt, readable)) {
+ RTC_LOG(LS_ERROR) << "Cannot read 'fmt ' chunk.";
return false;
+ }
+ if (!FindWaveChunk(&header.data.header, readable, "data")) {
+ RTC_LOG(LS_ERROR) << "Cannot find 'data' chunk.";
+ return false;
+ }
// Parse needed fields.
- *format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat));
- *num_channels = ReadLE16(header.fmt.NumChannels);
- *sample_rate = ReadLE32(header.fmt.SampleRate);
- *bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8;
- const uint32_t bytes_in_payload = ReadLE32(header.data.header.Size);
- if (*bytes_per_sample <= 0)
+ *format = MapHeaderFieldToWavFormat(header.fmt.AudioFormat);
+ *num_channels = header.fmt.NumChannels;
+ *sample_rate = header.fmt.SampleRate;
+ *bytes_per_sample = header.fmt.BitsPerSample / 8;
+ const size_t bytes_in_payload = header.data.header.Size;
+ if (*bytes_per_sample == 0)
return false;
*num_samples = bytes_in_payload / *bytes_per_sample;
- // Sanity check remaining fields.
- if (ReadFourCC(header.riff.header.ID) != "RIFF")
- return false;
- if (ReadFourCC(header.riff.Format) != "WAVE")
- return false;
- if (ReadFourCC(header.fmt.header.ID) != "fmt ")
- return false;
- if (ReadFourCC(header.data.header.ID) != "data")
- return false;
+ const size_t header_size = *format == WavFormat::kWavFormatPcm
+ ? kPcmWavHeaderSize
+ : kIeeeFloatWavHeaderSize;
- if (ReadLE32(header.riff.header.Size) < RiffChunkSize(bytes_in_payload))
+ if (header.riff.header.Size < RiffChunkSize(bytes_in_payload, header_size))
return false;
- if (ReadLE32(header.fmt.ByteRate) !=
+ if (header.fmt.ByteRate !=
ByteRate(*num_channels, *sample_rate, *bytes_per_sample))
return false;
- if (ReadLE16(header.fmt.BlockAlign) !=
- BlockAlign(*num_channels, *bytes_per_sample))
+ if (header.fmt.BlockAlign != BlockAlign(*num_channels, *bytes_per_sample))
return false;
- return CheckWavParameters(*num_channels, *sample_rate, *format,
- *bytes_per_sample, *num_samples);
-}
+ if (!CheckWavParameters(*num_channels, *sample_rate, *format,
+ *bytes_per_sample, *num_samples)) {
+ return false;
+ }
+ *data_start_pos = readable->GetPosition();
+ return true;
+}
} // namespace webrtc
diff --git a/webrtc/common_audio/wav_header.h b/webrtc/common_audio/wav_header.h
index 1a0fd7c..2cccd7d 100644
--- a/webrtc/common_audio/wav_header.h
+++ b/webrtc/common_audio/wav_header.h
@@ -8,57 +8,83 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
-#define WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
+#ifndef COMMON_AUDIO_WAV_HEADER_H_
+#define COMMON_AUDIO_WAV_HEADER_H_
#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
-namespace webrtc {
+#include "rtc_base/checks.h"
-static const size_t kWavHeaderSize = 44;
+namespace webrtc {
-class ReadableWav {
+// Interface providing header reading functionality.
+class WavHeaderReader {
public:
// Returns the number of bytes read.
- size_t virtual Read(void* buf, size_t num_bytes) = 0;
- virtual ~ReadableWav() {}
+ virtual size_t Read(void* buf, size_t num_bytes) = 0;
+ virtual bool SeekForward(uint32_t num_bytes) = 0;
+ virtual ~WavHeaderReader() = default;
+ virtual int64_t GetPosition() = 0;
};
-enum WavFormat {
- kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample
- kWavFormatALaw = 6, // 8-bit ITU-T G.711 A-law
- kWavFormatMuLaw = 7, // 8-bit ITU-T G.711 mu-law
+// Possible WAV formats.
+enum class WavFormat {
+ kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample.
+ kWavFormatIeeeFloat = 3, // IEEE float.
+ kWavFormatALaw = 6, // 8-bit ITU-T G.711 A-law.
+ kWavFormatMuLaw = 7, // 8-bit ITU-T G.711 mu-law.
};
+// Header sizes for supported WAV formats.
+constexpr size_t kPcmWavHeaderSize = 44;
+constexpr size_t kIeeeFloatWavHeaderSize = 58;
+
+// Returns the size of the WAV header for the specified format.
+constexpr size_t WavHeaderSize(WavFormat format) {
+ if (format == WavFormat::kWavFormatPcm) {
+ return kPcmWavHeaderSize;
+ }
+ RTC_CHECK_EQ(format, WavFormat::kWavFormatIeeeFloat);
+ return kIeeeFloatWavHeaderSize;
+}
+
+// Returns the maximum size of the supported WAV formats.
+constexpr size_t MaxWavHeaderSize() {
+ return std::max(WavHeaderSize(WavFormat::kWavFormatPcm),
+ WavHeaderSize(WavFormat::kWavFormatIeeeFloat));
+}
+
// Return true if the given parameters will make a well-formed WAV header.
-bool CheckWavParameters(int num_channels,
+bool CheckWavParameters(size_t num_channels,
int sample_rate,
WavFormat format,
- int bytes_per_sample,
- uint32_t num_samples);
+ size_t num_samples);
// Write a kWavHeaderSize bytes long WAV header to buf. The payload that
// follows the header is supposed to have the specified number of interleaved
// channels and contain the specified total number of samples of the specified
-// type. CHECKs the input parameters for validity.
-void WriteWavHeader(uint8_t* buf,
- int num_channels,
+// type. The size of the header is returned in header_size. CHECKs the input
+// parameters for validity.
+void WriteWavHeader(size_t num_channels,
int sample_rate,
WavFormat format,
- int bytes_per_sample,
- uint32_t num_samples);
+ size_t num_samples,
+ uint8_t* buf,
+ size_t* header_size);
-// Read a WAV header from an implemented ReadableWav and parse the values into
-// the provided output parameters. ReadableWav is used because the header can
-// be variably sized. Returns false if the header is invalid.
-bool ReadWavHeader(ReadableWav* readable,
- int* num_channels,
+// Read a WAV header from an implemented WavHeaderReader and parse the values
+// into the provided output parameters. WavHeaderReader is used because the
+// header can be variably sized. Returns false if the header is invalid.
+bool ReadWavHeader(WavHeaderReader* readable,
+ size_t* num_channels,
int* sample_rate,
WavFormat* format,
- int* bytes_per_sample,
- uint32_t* num_samples);
+ size_t* bytes_per_sample,
+ size_t* num_samples,
+ int64_t* data_start_pos);
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
+#endif // COMMON_AUDIO_WAV_HEADER_H_
diff --git a/webrtc/common_audio/window_generator.cc b/webrtc/common_audio/window_generator.cc
index ab983b7..da5603d 100644
--- a/webrtc/common_audio/window_generator.cc
+++ b/webrtc/common_audio/window_generator.cc
@@ -10,12 +10,12 @@
#define _USE_MATH_DEFINES
-#include "webrtc/common_audio/window_generator.h"
+#include "common_audio/window_generator.h"
#include <cmath>
#include <complex>
-#include "webrtc/base/checks.h"
+#include "rtc_base/checks.h"
using std::complex;
@@ -25,12 +25,11 @@ namespace {
complex<float> I0(complex<float> x) {
complex<float> y = x / 3.75f;
y *= y;
- return 1.0f + y * (
- 3.5156229f + y * (
- 3.0899424f + y * (
- 1.2067492f + y * (
- 0.2659732f + y * (
- 0.360768e-1f + y * 0.45813e-2f)))));
+ return 1.0f + y * (3.5156229f +
+ y * (3.0899424f +
+ y * (1.2067492f +
+ y * (0.2659732f +
+ y * (0.360768e-1f + y * 0.45813e-2f)))));
}
} // namespace
@@ -41,12 +40,13 @@ void WindowGenerator::Hanning(int length, float* window) {
RTC_CHECK_GT(length, 1);
RTC_CHECK(window != nullptr);
for (int i = 0; i < length; ++i) {
- window[i] = 0.5f * (1 - cosf(2 * static_cast<float>(M_PI) * i /
- (length - 1)));
+ window[i] =
+ 0.5f * (1 - cosf(2 * static_cast<float>(M_PI) * i / (length - 1)));
}
}
-void WindowGenerator::KaiserBesselDerived(float alpha, size_t length,
+void WindowGenerator::KaiserBesselDerived(float alpha,
+ size_t length,
float* window) {
RTC_CHECK_GT(length, 1U);
RTC_CHECK(window != nullptr);
@@ -69,4 +69,3 @@ void WindowGenerator::KaiserBesselDerived(float alpha, size_t length,
}
} // namespace webrtc
-
diff --git a/webrtc/common_audio/window_generator.h b/webrtc/common_audio/window_generator.h
index 25dd233..c0a89c4 100644
--- a/webrtc/common_audio/window_generator.h
+++ b/webrtc/common_audio/window_generator.h
@@ -8,26 +8,24 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_AUDIO_WINDOW_GENERATOR_H_
-#define WEBRTC_COMMON_AUDIO_WINDOW_GENERATOR_H_
+#ifndef COMMON_AUDIO_WINDOW_GENERATOR_H_
+#define COMMON_AUDIO_WINDOW_GENERATOR_H_
#include <stddef.h>
-#include "webrtc/base/constructormagic.h"
-
namespace webrtc {
// Helper class with generators for various signal transform windows.
class WindowGenerator {
public:
+ WindowGenerator() = delete;
+ WindowGenerator(const WindowGenerator&) = delete;
+ WindowGenerator& operator=(const WindowGenerator&) = delete;
+
static void Hanning(int length, float* window);
static void KaiserBesselDerived(float alpha, size_t length, float* window);
-
- private:
- RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WindowGenerator);
};
} // namespace webrtc
-#endif // WEBRTC_COMMON_AUDIO_WINDOW_GENERATOR_H_
-
+#endif // COMMON_AUDIO_WINDOW_GENERATOR_H_
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
deleted file mode 100644
index 048485f..0000000
--- a/webrtc/common_types.h
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_COMMON_TYPES_H_
-#define WEBRTC_COMMON_TYPES_H_
-
-#include <stddef.h>
-#include <string.h>
-
-#include <string>
-#include <vector>
-
-#include "webrtc/typedefs.h"
-
-#if defined(_MSC_VER)
-// Disable "new behavior: elements of array will be default initialized"
-// warning. Affects OverUseDetectorOptions.
-#pragma warning(disable:4351)
-#endif
-
-#ifdef WEBRTC_EXPORT
-#define WEBRTC_DLLEXPORT _declspec(dllexport)
-#elif WEBRTC_DLL
-#define WEBRTC_DLLEXPORT _declspec(dllimport)
-#else
-#define WEBRTC_DLLEXPORT
-#endif
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#define RTP_PAYLOAD_NAME_SIZE 32
-
-#if defined(WEBRTC_WIN) || defined(WIN32)
-// Compares two strings without regard to case.
-#define STR_CASE_CMP(s1, s2) ::_stricmp(s1, s2)
-// Compares characters of two strings without regard to case.
-#define STR_NCASE_CMP(s1, s2, n) ::_strnicmp(s1, s2, n)
-#else
-#define STR_CASE_CMP(s1, s2) ::strcasecmp(s1, s2)
-#define STR_NCASE_CMP(s1, s2, n) ::strncasecmp(s1, s2, n)
-#endif
-
-namespace webrtc {
-
-class Config;
-
-class InStream
-{
-public:
- // Reads |length| bytes from file to |buf|. Returns the number of bytes read
- // or -1 on error.
- virtual int Read(void *buf, size_t len) = 0;
- virtual int Rewind();
- virtual ~InStream() {}
-protected:
- InStream() {}
-};
-
-class OutStream
-{
-public:
- // Writes |length| bytes from |buf| to file. The actual writing may happen
- // some time later. Call Flush() to force a write.
- virtual bool Write(const void *buf, size_t len) = 0;
- virtual int Rewind();
- virtual ~OutStream() {}
-protected:
- OutStream() {}
-};
-
-enum TraceModule
-{
- kTraceUndefined = 0,
- // not a module, triggered from the engine code
- kTraceVoice = 0x0001,
- // not a module, triggered from the engine code
- kTraceVideo = 0x0002,
- // not a module, triggered from the utility code
- kTraceUtility = 0x0003,
- kTraceRtpRtcp = 0x0004,
- kTraceTransport = 0x0005,
- kTraceSrtp = 0x0006,
- kTraceAudioCoding = 0x0007,
- kTraceAudioMixerServer = 0x0008,
- kTraceAudioMixerClient = 0x0009,
- kTraceFile = 0x000a,
- kTraceAudioProcessing = 0x000b,
- kTraceVideoCoding = 0x0010,
- kTraceVideoMixer = 0x0011,
- kTraceAudioDevice = 0x0012,
- kTraceVideoRenderer = 0x0014,
- kTraceVideoCapture = 0x0015,
- kTraceRemoteBitrateEstimator = 0x0017,
-};
-
-enum TraceLevel
-{
- kTraceNone = 0x0000, // no trace
- kTraceStateInfo = 0x0001,
- kTraceWarning = 0x0002,
- kTraceError = 0x0004,
- kTraceCritical = 0x0008,
- kTraceApiCall = 0x0010,
- kTraceDefault = 0x00ff,
-
- kTraceModuleCall = 0x0020,
- kTraceMemory = 0x0100, // memory info
- kTraceTimer = 0x0200, // timing info
- kTraceStream = 0x0400, // "continuous" stream of data
-
- // used for debug purposes
- kTraceDebug = 0x0800, // debug
- kTraceInfo = 0x1000, // debug info
-
- // Non-verbose level used by LS_INFO of logging.h. Do not use directly.
- kTraceTerseInfo = 0x2000,
-
- kTraceAll = 0xffff
-};
-
-// External Trace API
-class TraceCallback {
- public:
- virtual void Print(TraceLevel level, const char* message, int length) = 0;
-
- protected:
- virtual ~TraceCallback() {}
- TraceCallback() {}
-};
-
-enum FileFormats
-{
- kFileFormatWavFile = 1,
- kFileFormatCompressedFile = 2,
- kFileFormatPreencodedFile = 4,
- kFileFormatPcm16kHzFile = 7,
- kFileFormatPcm8kHzFile = 8,
- kFileFormatPcm32kHzFile = 9
-};
-
-enum ProcessingTypes
-{
- kPlaybackPerChannel = 0,
- kPlaybackAllChannelsMixed,
- kRecordingPerChannel,
- kRecordingAllChannelsMixed,
- kRecordingPreprocessing
-};
-
-enum FrameType {
- kEmptyFrame = 0,
- kAudioFrameSpeech = 1,
- kAudioFrameCN = 2,
- kVideoFrameKey = 3,
- kVideoFrameDelta = 4,
-};
-
-// Statistics for an RTCP channel
-struct RtcpStatistics {
- RtcpStatistics()
- : fraction_lost(0),
- cumulative_lost(0),
- extended_max_sequence_number(0),
- jitter(0) {}
-
- uint8_t fraction_lost;
- uint32_t cumulative_lost;
- uint32_t extended_max_sequence_number;
- uint32_t jitter;
-};
-
-class RtcpStatisticsCallback {
- public:
- virtual ~RtcpStatisticsCallback() {}
-
- virtual void StatisticsUpdated(const RtcpStatistics& statistics,
- uint32_t ssrc) = 0;
- virtual void CNameChanged(const char* cname, uint32_t ssrc) = 0;
-};
-
-// Statistics for RTCP packet types.
-struct RtcpPacketTypeCounter {
- RtcpPacketTypeCounter()
- : first_packet_time_ms(-1),
- nack_packets(0),
- fir_packets(0),
- pli_packets(0),
- nack_requests(0),
- unique_nack_requests(0) {}
-
- void Add(const RtcpPacketTypeCounter& other) {
- nack_packets += other.nack_packets;
- fir_packets += other.fir_packets;
- pli_packets += other.pli_packets;
- nack_requests += other.nack_requests;
- unique_nack_requests += other.unique_nack_requests;
- if (other.first_packet_time_ms != -1 &&
- (other.first_packet_time_ms < first_packet_time_ms ||
- first_packet_time_ms == -1)) {
- // Use oldest time.
- first_packet_time_ms = other.first_packet_time_ms;
- }
- }
-
- int64_t TimeSinceFirstPacketInMs(int64_t now_ms) const {
- return (first_packet_time_ms == -1) ? -1 : (now_ms - first_packet_time_ms);
- }
-
- int UniqueNackRequestsInPercent() const {
- if (nack_requests == 0) {
- return 0;
- }
- return static_cast<int>(
- (unique_nack_requests * 100.0f / nack_requests) + 0.5f);
- }
-
- int64_t first_packet_time_ms; // Time when first packet is sent/received.
- uint32_t nack_packets; // Number of RTCP NACK packets.
- uint32_t fir_packets; // Number of RTCP FIR packets.
- uint32_t pli_packets; // Number of RTCP PLI packets.
- uint32_t nack_requests; // Number of NACKed RTP packets.
- uint32_t unique_nack_requests; // Number of unique NACKed RTP packets.
-};
-
-class RtcpPacketTypeCounterObserver {
- public:
- virtual ~RtcpPacketTypeCounterObserver() {}
- virtual void RtcpPacketTypesCounterUpdated(
- uint32_t ssrc,
- const RtcpPacketTypeCounter& packet_counter) = 0;
-};
-
-// Rate statistics for a stream.
-struct BitrateStatistics {
- BitrateStatistics() : bitrate_bps(0), packet_rate(0), timestamp_ms(0) {}
-
- uint32_t bitrate_bps; // Bitrate in bits per second.
- uint32_t packet_rate; // Packet rate in packets per second.
- uint64_t timestamp_ms; // Ntp timestamp in ms at time of rate estimation.
-};
-
-// Callback, used to notify an observer whenever new rates have been estimated.
-class BitrateStatisticsObserver {
- public:
- virtual ~BitrateStatisticsObserver() {}
-
- virtual void Notify(const BitrateStatistics& total_stats,
- const BitrateStatistics& retransmit_stats,
- uint32_t ssrc) = 0;
-};
-
-struct FrameCounts {
- FrameCounts() : key_frames(0), delta_frames(0) {}
- int key_frames;
- int delta_frames;
-};
-
-// Callback, used to notify an observer whenever frame counts have been updated.
-class FrameCountObserver {
- public:
- virtual ~FrameCountObserver() {}
- virtual void FrameCountUpdated(const FrameCounts& frame_counts,
- uint32_t ssrc) = 0;
-};
-
-// Callback, used to notify an observer whenever the send-side delay is updated.
-class SendSideDelayObserver {
- public:
- virtual ~SendSideDelayObserver() {}
- virtual void SendSideDelayUpdated(int avg_delay_ms,
- int max_delay_ms,
- uint32_t ssrc) = 0;
-};
-
-// ==================================================================
-// Voice specific types
-// ==================================================================
-
-// Each codec supported can be described by this structure.
-struct CodecInst {
- int pltype;
- char plname[RTP_PAYLOAD_NAME_SIZE];
- int plfreq;
- int pacsize;
- int channels;
- int rate; // bits/sec unlike {start,min,max}Bitrate elsewhere in this file!
-
- bool operator==(const CodecInst& other) const {
- return pltype == other.pltype &&
- (STR_CASE_CMP(plname, other.plname) == 0) &&
- plfreq == other.plfreq &&
- pacsize == other.pacsize &&
- channels == other.channels &&
- rate == other.rate;
- }
-
- bool operator!=(const CodecInst& other) const {
- return !(*this == other);
- }
-};
-
-// RTP
-enum {kRtpCsrcSize = 15}; // RFC 3550 page 13
-
-enum RTPDirections
-{
- kRtpIncoming = 0,
- kRtpOutgoing
-};
-
-enum PayloadFrequencies
-{
- kFreq8000Hz = 8000,
- kFreq16000Hz = 16000,
- kFreq32000Hz = 32000
-};
-
-enum VadModes // degree of bandwidth reduction
-{
- kVadConventional = 0, // lowest reduction
- kVadAggressiveLow,
- kVadAggressiveMid,
- kVadAggressiveHigh // highest reduction
-};
-
-struct NetworkStatistics // NETEQ statistics
-{
- // current jitter buffer size in ms
- uint16_t currentBufferSize;
- // preferred (optimal) buffer size in ms
- uint16_t preferredBufferSize;
- // adding extra delay due to "peaky jitter"
- bool jitterPeaksFound;
- // Loss rate (network + late); fraction between 0 and 1, scaled to Q14.
- uint16_t currentPacketLossRate;
- // Late loss rate; fraction between 0 and 1, scaled to Q14.
- uint16_t currentDiscardRate;
- // fraction (of original stream) of synthesized audio inserted through
- // expansion (in Q14)
- uint16_t currentExpandRate;
- // fraction (of original stream) of synthesized speech inserted through
- // expansion (in Q14)
- uint16_t currentSpeechExpandRate;
- // fraction of synthesized speech inserted through pre-emptive expansion
- // (in Q14)
- uint16_t currentPreemptiveRate;
- // fraction of data removed through acceleration (in Q14)
- uint16_t currentAccelerateRate;
- // fraction of data coming from secondary decoding (in Q14)
- uint16_t currentSecondaryDecodedRate;
- // clock-drift in parts-per-million (negative or positive)
- int32_t clockDriftPPM;
- // average packet waiting time in the jitter buffer (ms)
- int meanWaitingTimeMs;
- // median packet waiting time in the jitter buffer (ms)
- int medianWaitingTimeMs;
- // min packet waiting time in the jitter buffer (ms)
- int minWaitingTimeMs;
- // max packet waiting time in the jitter buffer (ms)
- int maxWaitingTimeMs;
- // added samples in off mode due to packet loss
- size_t addedSamples;
-};
-
-// Statistics for calls to AudioCodingModule::PlayoutData10Ms().
-struct AudioDecodingCallStats {
- AudioDecodingCallStats()
- : calls_to_silence_generator(0),
- calls_to_neteq(0),
- decoded_normal(0),
- decoded_plc(0),
- decoded_cng(0),
- decoded_plc_cng(0) {}
-
- int calls_to_silence_generator; // Number of calls where silence generated,
- // and NetEq was disengaged from decoding.
- int calls_to_neteq; // Number of calls to NetEq.
- int decoded_normal; // Number of calls where audio RTP packet decoded.
- int decoded_plc; // Number of calls resulted in PLC.
- int decoded_cng; // Number of calls where comfort noise generated due to DTX.
- int decoded_plc_cng; // Number of calls resulted where PLC faded to CNG.
-};
-
-typedef struct
-{
- int min; // minumum
- int max; // maximum
- int average; // average
-} StatVal;
-
-typedef struct // All levels are reported in dBm0
-{
- StatVal speech_rx; // long-term speech levels on receiving side
- StatVal speech_tx; // long-term speech levels on transmitting side
- StatVal noise_rx; // long-term noise/silence levels on receiving side
- StatVal noise_tx; // long-term noise/silence levels on transmitting side
-} LevelStatistics;
-
-typedef struct // All levels are reported in dB
-{
- StatVal erl; // Echo Return Loss
- StatVal erle; // Echo Return Loss Enhancement
- StatVal rerl; // RERL = ERL + ERLE
- // Echo suppression inside EC at the point just before its NLP
- StatVal a_nlp;
-} EchoStatistics;
-
-enum NsModes // type of Noise Suppression
-{
- kNsUnchanged = 0, // previously set mode
- kNsDefault, // platform default
- kNsConference, // conferencing default
- kNsLowSuppression, // lowest suppression
- kNsModerateSuppression,
- kNsHighSuppression,
- kNsVeryHighSuppression, // highest suppression
-};
-
-enum AgcModes // type of Automatic Gain Control
-{
- kAgcUnchanged = 0, // previously set mode
- kAgcDefault, // platform default
- // adaptive mode for use when analog volume control exists (e.g. for
- // PC softphone)
- kAgcAdaptiveAnalog,
- // scaling takes place in the digital domain (e.g. for conference servers
- // and embedded devices)
- kAgcAdaptiveDigital,
- // can be used on embedded devices where the capture signal level
- // is predictable
- kAgcFixedDigital
-};
-
-// EC modes
-enum EcModes // type of Echo Control
-{
- kEcUnchanged = 0, // previously set mode
- kEcDefault, // platform default
- kEcConference, // conferencing default (aggressive AEC)
- kEcAec, // Acoustic Echo Cancellation
- kEcAecm, // AEC mobile
-};
-
-// AECM modes
-enum AecmModes // mode of AECM
-{
- kAecmQuietEarpieceOrHeadset = 0,
- // Quiet earpiece or headset use
- kAecmEarpiece, // most earpiece use
- kAecmLoudEarpiece, // Loud earpiece or quiet speakerphone use
- kAecmSpeakerphone, // most speakerphone use (default)
- kAecmLoudSpeakerphone // Loud speakerphone
-};
-
-// AGC configuration
-typedef struct
-{
- unsigned short targetLeveldBOv;
- unsigned short digitalCompressionGaindB;
- bool limiterEnable;
-} AgcConfig; // AGC configuration parameters
-
-enum StereoChannel
-{
- kStereoLeft = 0,
- kStereoRight,
- kStereoBoth
-};
-
-// Audio device layers
-enum AudioLayers
-{
- kAudioPlatformDefault = 0,
- kAudioWindowsWave = 1,
- kAudioWindowsCore = 2,
- kAudioLinuxAlsa = 3,
- kAudioLinuxPulse = 4
-};
-
-// TODO(henrika): to be removed.
-enum NetEqModes // NetEQ playout configurations
-{
- // Optimized trade-off between low delay and jitter robustness for two-way
- // communication.
- kNetEqDefault = 0,
- // Improved jitter robustness at the cost of increased delay. Can be
- // used in one-way communication.
- kNetEqStreaming = 1,
- // Optimzed for decodability of fax signals rather than for perceived audio
- // quality.
- kNetEqFax = 2,
- // Minimal buffer management. Inserts zeros for lost packets and during
- // buffer increases.
- kNetEqOff = 3,
-};
-
-// TODO(henrika): to be removed.
-enum OnHoldModes // On Hold direction
-{
- kHoldSendAndPlay = 0, // Put both sending and playing in on-hold state.
- kHoldSendOnly, // Put only sending in on-hold state.
- kHoldPlayOnly // Put only playing in on-hold state.
-};
-
-// TODO(henrika): to be removed.
-enum AmrMode
-{
- kRfc3267BwEfficient = 0,
- kRfc3267OctetAligned = 1,
- kRfc3267FileStorage = 2,
-};
-
-// ==================================================================
-// Video specific types
-// ==================================================================
-
-// Raw video types
-enum RawVideoType
-{
- kVideoI420 = 0,
- kVideoYV12 = 1,
- kVideoYUY2 = 2,
- kVideoUYVY = 3,
- kVideoIYUV = 4,
- kVideoARGB = 5,
- kVideoRGB24 = 6,
- kVideoRGB565 = 7,
- kVideoARGB4444 = 8,
- kVideoARGB1555 = 9,
- kVideoMJPEG = 10,
- kVideoNV12 = 11,
- kVideoNV21 = 12,
- kVideoBGRA = 13,
- kVideoUnknown = 99
-};
-
-// Video codec
-enum { kConfigParameterSize = 128};
-enum { kPayloadNameSize = 32};
-enum { kMaxSimulcastStreams = 4};
-enum { kMaxSpatialLayers = 5 };
-enum { kMaxTemporalStreams = 4};
-
-enum VideoCodecComplexity
-{
- kComplexityNormal = 0,
- kComplexityHigh = 1,
- kComplexityHigher = 2,
- kComplexityMax = 3
-};
-
-enum VideoCodecProfile
-{
- kProfileBase = 0x00,
- kProfileMain = 0x01
-};
-
-enum VP8ResilienceMode {
- kResilienceOff, // The stream produced by the encoder requires a
- // recovery frame (typically a key frame) to be
- // decodable after a packet loss.
- kResilientStream, // A stream produced by the encoder is resilient to
- // packet losses, but packets within a frame subsequent
- // to a loss can't be decoded.
- kResilientFrames // Same as kResilientStream but with added resilience
- // within a frame.
-};
-
-// VP8 specific
-struct VideoCodecVP8 {
- bool pictureLossIndicationOn;
- bool feedbackModeOn;
- VideoCodecComplexity complexity;
- VP8ResilienceMode resilience;
- unsigned char numberOfTemporalLayers;
- bool denoisingOn;
- bool errorConcealmentOn;
- bool automaticResizeOn;
- bool frameDroppingOn;
- int keyFrameInterval;
-
- bool operator==(const VideoCodecVP8& other) const {
- return pictureLossIndicationOn == other.pictureLossIndicationOn &&
- feedbackModeOn == other.feedbackModeOn &&
- complexity == other.complexity &&
- resilience == other.resilience &&
- numberOfTemporalLayers == other.numberOfTemporalLayers &&
- denoisingOn == other.denoisingOn &&
- errorConcealmentOn == other.errorConcealmentOn &&
- automaticResizeOn == other.automaticResizeOn &&
- frameDroppingOn == other.frameDroppingOn &&
- keyFrameInterval == other.keyFrameInterval;
- }
-
- bool operator!=(const VideoCodecVP8& other) const {
- return !(*this == other);
- }
-};
-
-// VP9 specific.
-struct VideoCodecVP9 {
- VideoCodecComplexity complexity;
- int resilience;
- unsigned char numberOfTemporalLayers;
- bool denoisingOn;
- bool frameDroppingOn;
- int keyFrameInterval;
- bool adaptiveQpMode;
- bool automaticResizeOn;
- unsigned char numberOfSpatialLayers;
- bool flexibleMode;
-};
-
-// H264 specific.
-struct VideoCodecH264 {
- VideoCodecProfile profile;
- bool frameDroppingOn;
- int keyFrameInterval;
- // These are NULL/0 if not externally negotiated.
- const uint8_t* spsData;
- size_t spsLen;
- const uint8_t* ppsData;
- size_t ppsLen;
-};
-
-// Video codec types
-enum VideoCodecType {
- kVideoCodecVP8,
- kVideoCodecVP9,
- kVideoCodecH264,
- kVideoCodecI420,
- kVideoCodecRED,
- kVideoCodecULPFEC,
- kVideoCodecGeneric,
- kVideoCodecUnknown
-};
-
-union VideoCodecUnion {
- VideoCodecVP8 VP8;
- VideoCodecVP9 VP9;
- VideoCodecH264 H264;
-};
-
-
-// Simulcast is when the same stream is encoded multiple times with different
-// settings such as resolution.
-struct SimulcastStream {
- unsigned short width;
- unsigned short height;
- unsigned char numberOfTemporalLayers;
- unsigned int maxBitrate; // kilobits/sec.
- unsigned int targetBitrate; // kilobits/sec.
- unsigned int minBitrate; // kilobits/sec.
- unsigned int qpMax; // minimum quality
-
- bool operator==(const SimulcastStream& other) const {
- return width == other.width &&
- height == other.height &&
- numberOfTemporalLayers == other.numberOfTemporalLayers &&
- maxBitrate == other.maxBitrate &&
- targetBitrate == other.targetBitrate &&
- minBitrate == other.minBitrate &&
- qpMax == other.qpMax;
- }
-
- bool operator!=(const SimulcastStream& other) const {
- return !(*this == other);
- }
-};
-
-struct SpatialLayer {
- int scaling_factor_num;
- int scaling_factor_den;
- int target_bitrate_bps;
- // TODO(ivica): Add max_quantizer and min_quantizer?
-};
-
-enum VideoCodecMode {
- kRealtimeVideo,
- kScreensharing
-};
-
-// Common video codec properties
-struct VideoCodec {
- VideoCodecType codecType;
- char plName[kPayloadNameSize];
- unsigned char plType;
-
- unsigned short width;
- unsigned short height;
-
- unsigned int startBitrate; // kilobits/sec.
- unsigned int maxBitrate; // kilobits/sec.
- unsigned int minBitrate; // kilobits/sec.
- unsigned int targetBitrate; // kilobits/sec.
-
- unsigned char maxFramerate;
-
- VideoCodecUnion codecSpecific;
-
- unsigned int qpMax;
- unsigned char numberOfSimulcastStreams;
- SimulcastStream simulcastStream[kMaxSimulcastStreams];
- SpatialLayer spatialLayers[kMaxSpatialLayers];
-
- VideoCodecMode mode;
-
- // When using an external encoder/decoder this allows to pass
- // extra options without requiring webrtc to be aware of them.
- Config* extra_options;
-
- bool operator==(const VideoCodec& other) const {
- bool ret = codecType == other.codecType &&
- (STR_CASE_CMP(plName, other.plName) == 0) &&
- plType == other.plType &&
- width == other.width &&
- height == other.height &&
- startBitrate == other.startBitrate &&
- maxBitrate == other.maxBitrate &&
- minBitrate == other.minBitrate &&
- targetBitrate == other.targetBitrate &&
- maxFramerate == other.maxFramerate &&
- qpMax == other.qpMax &&
- numberOfSimulcastStreams == other.numberOfSimulcastStreams &&
- mode == other.mode;
- if (ret && codecType == kVideoCodecVP8) {
- ret &= (codecSpecific.VP8 == other.codecSpecific.VP8);
- }
-
- for (unsigned char i = 0; i < other.numberOfSimulcastStreams && ret; ++i) {
- ret &= (simulcastStream[i] == other.simulcastStream[i]);
- }
- return ret;
- }
-
- bool operator!=(const VideoCodec& other) const {
- return !(*this == other);
- }
-};
-
-// Bandwidth over-use detector options. These are used to drive
-// experimentation with bandwidth estimation parameters.
-// See modules/remote_bitrate_estimator/overuse_detector.h
-struct OverUseDetectorOptions {
- OverUseDetectorOptions()
- : initial_slope(8.0/512.0),
- initial_offset(0),
- initial_e(),
- initial_process_noise(),
- initial_avg_noise(0.0),
- initial_var_noise(50) {
- initial_e[0][0] = 100;
- initial_e[1][1] = 1e-1;
- initial_e[0][1] = initial_e[1][0] = 0;
- initial_process_noise[0] = 1e-13;
- initial_process_noise[1] = 1e-2;
- }
- double initial_slope;
- double initial_offset;
- double initial_e[2][2];
- double initial_process_noise[2];
- double initial_avg_noise;
- double initial_var_noise;
-};
-
-// This structure will have the information about when packet is actually
-// received by socket.
-struct PacketTime {
- PacketTime() : timestamp(-1), not_before(-1) {}
- PacketTime(int64_t timestamp, int64_t not_before)
- : timestamp(timestamp), not_before(not_before) {
- }
-
- int64_t timestamp; // Receive time after socket delivers the data.
- int64_t not_before; // Earliest possible time the data could have arrived,
- // indicating the potential error in the |timestamp|
- // value,in case the system is busy.
- // For example, the time of the last select() call.
- // If unknown, this value will be set to zero.
-};
-
-struct RTPHeaderExtension {
- RTPHeaderExtension();
-
- bool hasTransmissionTimeOffset;
- int32_t transmissionTimeOffset;
- bool hasAbsoluteSendTime;
- uint32_t absoluteSendTime;
- bool hasTransportSequenceNumber;
- uint16_t transportSequenceNumber;
-
- // Audio Level includes both level in dBov and voiced/unvoiced bit. See:
- // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
- bool hasAudioLevel;
- bool voiceActivity;
- uint8_t audioLevel;
-
- // For Coordination of Video Orientation. See
- // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/
- // ts_126114v120700p.pdf
- bool hasVideoRotation;
- uint8_t videoRotation;
-};
-
-struct RTPHeader {
- RTPHeader();
-
- bool markerBit;
- uint8_t payloadType;
- uint16_t sequenceNumber;
- uint32_t timestamp;
- uint32_t ssrc;
- uint8_t numCSRCs;
- uint32_t arrOfCSRCs[kRtpCsrcSize];
- size_t paddingLength;
- size_t headerLength;
- int payload_type_frequency;
- RTPHeaderExtension extension;
-};
-
-struct RtpPacketCounter {
- RtpPacketCounter()
- : header_bytes(0),
- payload_bytes(0),
- padding_bytes(0),
- packets(0) {}
-
- void Add(const RtpPacketCounter& other) {
- header_bytes += other.header_bytes;
- payload_bytes += other.payload_bytes;
- padding_bytes += other.padding_bytes;
- packets += other.packets;
- }
-
- void AddPacket(size_t packet_length, const RTPHeader& header) {
- ++packets;
- header_bytes += header.headerLength;
- padding_bytes += header.paddingLength;
- payload_bytes +=
- packet_length - (header.headerLength + header.paddingLength);
- }
-
- size_t TotalBytes() const {
- return header_bytes + payload_bytes + padding_bytes;
- }
-
- size_t header_bytes; // Number of bytes used by RTP headers.
- size_t payload_bytes; // Payload bytes, excluding RTP headers and padding.
- size_t padding_bytes; // Number of padding bytes.
- uint32_t packets; // Number of packets.
-};
-
-// Data usage statistics for a (rtp) stream.
-struct StreamDataCounters {
- StreamDataCounters();
-
- void Add(const StreamDataCounters& other) {
- transmitted.Add(other.transmitted);
- retransmitted.Add(other.retransmitted);
- fec.Add(other.fec);
- if (other.first_packet_time_ms != -1 &&
- (other.first_packet_time_ms < first_packet_time_ms ||
- first_packet_time_ms == -1)) {
- // Use oldest time.
- first_packet_time_ms = other.first_packet_time_ms;
- }
- }
-
- int64_t TimeSinceFirstPacketInMs(int64_t now_ms) const {
- return (first_packet_time_ms == -1) ? -1 : (now_ms - first_packet_time_ms);
- }
-
- // Returns the number of bytes corresponding to the actual media payload (i.e.
- // RTP headers, padding, retransmissions and fec packets are excluded).
- // Note this function does not have meaning for an RTX stream.
- size_t MediaPayloadBytes() const {
- return transmitted.payload_bytes - retransmitted.payload_bytes -
- fec.payload_bytes;
- }
-
- int64_t first_packet_time_ms; // Time when first packet is sent/received.
- RtpPacketCounter transmitted; // Number of transmitted packets/bytes.
- RtpPacketCounter retransmitted; // Number of retransmitted packets/bytes.
- RtpPacketCounter fec; // Number of redundancy packets/bytes.
-};
-
-// Callback, called whenever byte/packet counts have been updated.
-class StreamDataCountersCallback {
- public:
- virtual ~StreamDataCountersCallback() {}
-
- virtual void DataCountersUpdated(const StreamDataCounters& counters,
- uint32_t ssrc) = 0;
-};
-
-// RTCP mode to use. Compound mode is described by RFC 4585 and reduced-size
-// RTCP mode is described by RFC 5506.
-enum class RtcpMode { kOff, kCompound, kReducedSize };
-
-} // namespace webrtc
-
-#endif // WEBRTC_COMMON_TYPES_H_
diff --git a/webrtc/meson.build b/webrtc/meson.build
index c166f9b..e7a2dfb 100644
--- a/webrtc/meson.build
+++ b/webrtc/meson.build
@@ -1,31 +1,11 @@
-webrtc_sources = [
- 'common_types.cc'
-]
+webrtc_inc = include_directories('.')
-webrtc_headers = [
- 'common.h',
- 'common_types.h',
- 'typedefs.h',
-]
-
-install_headers(webrtc_headers,
- subdir: 'webrtc_audio_processing/webrtc'
-)
-
-libwebrtc = static_library('webrtc',
- webrtc_sources,
- dependencies: common_deps,
- include_directories: webrtc_inc,
- c_args: common_cflags,
- cpp_args: common_cxxflags
-)
-
-webrtc_dep = declare_dependency(
- link_with: libwebrtc
-)
-
-subdir('base')
-subdir('common_audio')
+subdir('rtc_base')
+subdir('api')
subdir('system_wrappers')
+subdir('common_audio')
+
+subdir('third_party/pffft')
+subdir('third_party/rnnoise')
subdir('modules')
diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn
new file mode 100644
index 0000000..bb6b7cc
--- /dev/null
+++ b/webrtc/modules/BUILD.gn
@@ -0,0 +1,247 @@
+# 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.
+
+import("../webrtc.gni")
+import("audio_coding/audio_coding.gni")
+
+group("modules") {
+ deps = [
+ "audio_coding",
+ "audio_device",
+ "audio_mixer",
+ "audio_processing",
+ "congestion_controller",
+ "pacing",
+ "remote_bitrate_estimator",
+ "rtp_rtcp",
+ "utility",
+ "video_coding",
+ "video_processing",
+ ]
+
+ if (rtc_desktop_capture_supported) {
+ deps += [ "desktop_capture" ]
+ }
+}
+
+rtc_source_set("module_api_public") {
+ sources = [ "include/module_common_types_public.h" ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_source_set("module_api") {
+ visibility = [ "*" ]
+ sources = [
+ "include/module.h",
+ "include/module_common_types.h",
+ ]
+}
+
+rtc_source_set("module_fec_api") {
+ visibility = [ "*" ]
+ sources = [ "include/module_fec_types.h" ]
+}
+
+if (rtc_include_tests) {
+ modules_tests_resources = [
+ "../resources/audio_coding/testfile16kHz.pcm",
+ "../resources/audio_coding/testfile32kHz.pcm",
+ "../resources/audio_coding/teststereo32kHz.pcm",
+ "../resources/foreman_cif.yuv",
+ ]
+
+ if (is_ios) {
+ bundle_data("modules_tests_bundle_data") {
+ testonly = true
+ sources = modules_tests_resources
+ outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
+ }
+ }
+
+ rtc_test("modules_tests") {
+ testonly = true
+
+ deps = [
+ "../test:test_main",
+ "../test:video_test_common",
+ "audio_coding:audio_coding_modules_tests",
+ "rtp_rtcp:rtp_rtcp_modules_tests",
+ "video_coding:video_coding_modules_tests",
+ "//testing/gtest",
+ ]
+
+ if (rtc_desktop_capture_supported) {
+ deps += [ "desktop_capture:desktop_capture_modules_tests" ]
+ }
+
+ data = modules_tests_resources
+
+ if (is_android) {
+ deps += [
+ # NOTE(brandtr): Including Java classes seems only to be possible from
+ # rtc_test targets. Therefore we include this target here, instead of
+ # in video_coding_modules_tests, where it is actually used.
+ "../sdk/android:libjingle_peerconnection_java",
+ "//testing/android/native_test:native_test_native_code",
+ ]
+ shard_timeout = 900
+ }
+
+ if (is_ios) {
+ deps += [ ":modules_tests_bundle_data" ]
+ }
+ }
+
+ modules_unittests_resources = [
+ "../resources/audio_coding/neteq_opus.rtp",
+ "../resources/audio_coding/neteq_opus_dtx.rtp",
+ "../resources/audio_coding/neteq_universal_new.rtp",
+ "../resources/audio_coding/speech_4_channels_48k_one_second.wav",
+ "../resources/audio_coding/speech_mono_16kHz.pcm",
+ "../resources/audio_coding/speech_mono_32_48kHz.pcm",
+ "../resources/audio_coding/testfile16kHz.pcm",
+ "../resources/audio_coding/testfile32kHz.pcm",
+ "../resources/audio_coding/testfile_fake_stereo_32kHz.pcm",
+ "../resources/audio_coding/teststereo32kHz.pcm",
+ "../resources/audio_device/audio_short16.pcm",
+ "../resources/audio_device/audio_short44.pcm",
+ "../resources/audio_device/audio_short48.pcm",
+ "../resources/audio_processing/agc/agc_audio.pcm",
+ "../resources/audio_processing/agc/agc_no_circular_buffer.dat",
+ "../resources/audio_processing/agc/agc_pitch_gain.dat",
+ "../resources/audio_processing/agc/agc_pitch_lag.dat",
+ "../resources/audio_processing/agc/agc_spectral_peak.dat",
+ "../resources/audio_processing/agc/agc_vad.dat",
+ "../resources/audio_processing/agc/agc_voicing_prob.dat",
+ "../resources/audio_processing/agc/agc_with_circular_buffer.dat",
+ "../resources/audio_processing/output_data_fixed.pb",
+ "../resources/audio_processing/output_data_float.pb",
+ "../resources/audio_processing/output_data_float_avx2.pb",
+ "../resources/audio_processing/output_data_mac.pb",
+ "../resources/audio_processing/transient/ajm-macbook-1-spke16m.pcm",
+ "../resources/audio_processing/transient/audio16kHz.pcm",
+ "../resources/audio_processing/transient/audio32kHz.pcm",
+ "../resources/audio_processing/transient/audio48kHz.pcm",
+ "../resources/audio_processing/transient/audio8kHz.pcm",
+ "../resources/audio_processing/transient/detect16kHz.dat",
+ "../resources/audio_processing/transient/detect32kHz.dat",
+ "../resources/audio_processing/transient/detect48kHz.dat",
+ "../resources/audio_processing/transient/detect8kHz.dat",
+ "../resources/audio_processing/transient/double-utils.dat",
+ "../resources/audio_processing/transient/float-utils.dat",
+ "../resources/audio_processing/transient/suppressed16kHz.pcm",
+ "../resources/audio_processing/transient/suppressed32kHz.pcm",
+ "../resources/audio_processing/transient/suppressed8kHz.pcm",
+ "../resources/audio_processing/transient/wpd0.dat",
+ "../resources/audio_processing/transient/wpd1.dat",
+ "../resources/audio_processing/transient/wpd2.dat",
+ "../resources/audio_processing/transient/wpd3.dat",
+ "../resources/audio_processing/transient/wpd4.dat",
+ "../resources/audio_processing/transient/wpd5.dat",
+ "../resources/audio_processing/transient/wpd6.dat",
+ "../resources/audio_processing/transient/wpd7.dat",
+ "../resources/deflicker_before_cif_short.yuv",
+ "../resources/far16_stereo.pcm",
+ "../resources/far32_stereo.pcm",
+ "../resources/far44_stereo.pcm",
+ "../resources/far48_stereo.pcm",
+ "../resources/far8_stereo.pcm",
+ "../resources/foremanColorEnhanced_cif_short.yuv",
+ "../resources/foreman_cif.yuv",
+ "../resources/foreman_cif_short.yuv",
+ "../resources/near16_stereo.pcm",
+ "../resources/near32_stereo.pcm",
+ "../resources/near44_stereo.pcm",
+ "../resources/near48_stereo.pcm",
+ "../resources/near8_stereo.pcm",
+ "../resources/ref03.aecdump",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_0_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_0_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_1_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_1_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_0_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_0_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_1_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_1_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingDelay1_0_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingDelay1_0_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingLoss1_0_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingLoss1_0_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_Multi1_1_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_Multi1_1_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_0_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_0_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_1_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_1_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyDelay_0_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyDelay_0_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyLoss_0_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyLoss_0_TOF.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_UnlimitedSpeed_0_AST.bin",
+ "../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_UnlimitedSpeed_0_TOF.bin",
+ "../resources/short_mixed_mono_48.dat",
+ "../resources/short_mixed_mono_48.pcm",
+ "../resources/short_mixed_mono_48_arm.dat",
+ "../resources/short_mixed_stereo_48.dat",
+ "../resources/short_mixed_stereo_48.pcm",
+ "../resources/voice_engine/audio_tiny48.wav",
+ ]
+ if (is_ios) {
+ bundle_data("modules_unittests_bundle_data") {
+ testonly = true
+ sources = modules_unittests_resources
+ outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
+ }
+ }
+
+ rtc_test("modules_unittests") {
+ testonly = true
+ defines = []
+ sources = [ "module_common_types_unittest.cc" ]
+
+ deps = [
+ ":module_api",
+ ":module_api_public",
+ "../test:test_main",
+ "../test:test_support",
+ "audio_coding:audio_coding_unittests",
+ "audio_device:audio_device_unittests",
+ "audio_mixer:audio_mixer_unittests",
+ "audio_processing:audio_processing_unittests",
+ "audio_processing/aec3:aec3_unittests",
+ "audio_processing/ns:ns_unittests",
+ "congestion_controller:congestion_controller_unittests",
+ "pacing:pacing_unittests",
+ "remote_bitrate_estimator:remote_bitrate_estimator_unittests",
+ "rtp_rtcp:rtp_rtcp_unittests",
+ "utility:utility_unittests",
+ "video_coding:video_coding_unittests",
+ "video_processing:video_processing_unittests",
+ ]
+
+ if (rtc_desktop_capture_supported) {
+ deps += [ "desktop_capture:desktop_capture_unittests" ]
+ }
+
+ data = modules_unittests_resources
+
+ if (is_android) {
+ deps += [
+ "../sdk/android:libjingle_peerconnection_java",
+ "//testing/android/native_test:native_test_support",
+ ]
+ shard_timeout = 900
+ }
+ if (is_ios) {
+ info_plist = "../test/ios/Info.plist"
+ deps += [ ":modules_unittests_bundle_data" ]
+ configs += [ "..:common_objc" ]
+ ldflags = [ "-ObjC" ]
+ }
+ }
+}
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index 839a143..cdf7821 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -6,287 +6,223 @@
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
-import("//build/config/arm.gni")
-import("../../build/webrtc.gni")
-
-source_set("rent_a_codec") {
- sources = [
- "main/acm2/acm_codec_database.cc",
- "main/acm2/acm_codec_database.h",
- "main/acm2/rent_a_codec.cc",
- "main/acm2/rent_a_codec.h",
- ]
- configs += [ "../..:common_config" ]
- public_configs = [ "../..:common_inherited_config" ]
- deps = [
- "../..:webrtc_common",
- ]
-
- defines = []
- if (rtc_include_opus) {
- defines += [ "WEBRTC_CODEC_OPUS" ]
- }
- if (!build_with_mozilla) {
- if (current_cpu == "arm") {
- defines += [ "WEBRTC_CODEC_ISACFX" ]
- } else {
- defines += [ "WEBRTC_CODEC_ISAC" ]
- }
- defines += [ "WEBRTC_CODEC_G722" ]
- }
- if (!build_with_mozilla && !build_with_chromium) {
- defines += [
- "WEBRTC_CODEC_ILBC",
- "WEBRTC_CODEC_RED",
- ]
- }
+import("../../webrtc.gni")
+import("audio_coding.gni")
+if (rtc_enable_protobuf) {
+ import("//third_party/protobuf/proto_library.gni")
}
-config("audio_coding_config") {
- include_dirs = [
- "main/include",
- "../interface",
- ]
+visibility = [ ":*" ]
+
+rtc_source_set("audio_coding_module_typedefs") {
+ visibility += [ "*" ]
+ sources = [ "include/audio_coding_module_typedefs.h" ]
+ deps = [ "../../rtc_base:deprecation" ]
}
-source_set("audio_coding") {
+rtc_library("audio_coding") {
+ visibility += [ "*" ]
sources = [
- "main/acm2/acm_common_defs.h",
- "main/acm2/acm_receiver.cc",
- "main/acm2/acm_receiver.h",
- "main/acm2/acm_resampler.cc",
- "main/acm2/acm_resampler.h",
- "main/acm2/audio_coding_module.cc",
- "main/acm2/audio_coding_module_impl.cc",
- "main/acm2/audio_coding_module_impl.h",
- "main/acm2/call_statistics.cc",
- "main/acm2/call_statistics.h",
- "main/acm2/codec_manager.cc",
- "main/acm2/codec_manager.h",
- "main/acm2/codec_owner.cc",
- "main/acm2/codec_owner.h",
- "main/acm2/initial_delay_manager.cc",
- "main/acm2/initial_delay_manager.h",
- "main/include/audio_coding_module.h",
- "main/include/audio_coding_module_typedefs.h",
+ "acm2/acm_receiver.cc",
+ "acm2/acm_receiver.h",
+ "acm2/acm_remixing.cc",
+ "acm2/acm_remixing.h",
+ "acm2/acm_resampler.cc",
+ "acm2/acm_resampler.h",
+ "acm2/audio_coding_module.cc",
+ "acm2/call_statistics.cc",
+ "acm2/call_statistics.h",
+ "include/audio_coding_module.h",
]
defines = []
- configs += [ "../..:common_config" ]
-
- public_configs = [
- "../..:common_inherited_config",
- ":audio_coding_config",
- ]
-
- if (is_win) {
- cflags = [
- # TODO(kjellander): Bug 261: fix this warning.
- "/wd4373", # virtual function override.
- ]
- }
-
- if (is_clang) {
- # Suppress warnings from Chrome's Clang plugins.
- # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
- configs -= [ "//build/config/clang:find_bad_constructs" ]
- }
-
deps = [
- ":cng",
- ":g711",
+ ":audio_coding_module_typedefs",
+ ":default_neteq_factory",
":neteq",
- ":pcm16b",
- ":rent_a_codec",
- "../..:rtc_event_log",
- "../..:webrtc_common",
+ "..:module_api",
+ "..:module_api_public",
+ "../../api:array_view",
+ "../../api:function_view",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/neteq:neteq_api",
"../../common_audio",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:audio_format_to_string",
+ "../../rtc_base:checks",
+ "../../rtc_base:deprecation",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base/synchronization:mutex",
"../../system_wrappers",
+ "../../system_wrappers:metrics",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
]
-
- if (rtc_include_opus) {
- defines += [ "WEBRTC_CODEC_OPUS" ]
- deps += [ ":webrtc_opus" ]
- }
- if (!build_with_mozilla) {
- if (current_cpu == "arm") {
- defines += [ "WEBRTC_CODEC_ISACFX" ]
- deps += [ ":isac_fix" ]
- } else {
- defines += [ "WEBRTC_CODEC_ISAC" ]
- deps += [ ":isac" ]
- }
- defines += [ "WEBRTC_CODEC_G722" ]
- deps += [ ":g722" ]
- }
- if (!build_with_mozilla && !build_with_chromium) {
- defines += [
- "WEBRTC_CODEC_ILBC",
- "WEBRTC_CODEC_RED",
- ]
- deps += [
- ":ilbc",
- ":red",
- ]
- }
}
-source_set("audio_decoder_interface") {
+rtc_library("legacy_encoded_audio_frame") {
sources = [
- "codecs/audio_decoder.cc",
- "codecs/audio_decoder.h",
+ "codecs/legacy_encoded_audio_frame.cc",
+ "codecs/legacy_encoded_audio_frame.h",
]
- configs += [ "../..:common_config" ]
- public_configs = [ "../..:common_inherited_config" ]
deps = [
- "../..:webrtc_common",
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
-source_set("audio_encoder_interface") {
+rtc_library("webrtc_cng") {
+ visibility += webrtc_default_visibility
sources = [
- "codecs/audio_encoder.cc",
- "codecs/audio_encoder.h",
+ "codecs/cng/webrtc_cng.cc",
+ "codecs/cng/webrtc_cng.h",
]
- configs += [ "../..:common_config" ]
- public_configs = [ "../..:common_inherited_config" ]
- deps = [
- "../..:webrtc_common",
- ]
-}
-config("cng_config") {
- include_dirs = [
- "../../..",
- "codecs/cng/include",
+ deps = [
+ "../../api:array_view",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:safe_conversions",
]
}
-source_set("cng") {
+rtc_library("audio_encoder_cng") {
+ visibility += [ "*" ]
sources = [
"codecs/cng/audio_encoder_cng.cc",
- "codecs/cng/cng_helpfuns.c",
- "codecs/cng/cng_helpfuns.h",
- "codecs/cng/include/audio_encoder_cng.h",
- "codecs/cng/include/webrtc_cng.h",
- "codecs/cng/webrtc_cng.c",
- ]
-
- configs += [ "../..:common_config" ]
-
- public_configs = [
- "../..:common_inherited_config",
- ":cng_config",
+ "codecs/cng/audio_encoder_cng.h",
]
deps = [
+ ":webrtc_cng",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/units:time_delta",
"../../common_audio",
- ":audio_encoder_interface",
+ "../../rtc_base:checks",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
-config("red_config") {
- include_dirs = [ "codecs/red" ]
-}
-
-source_set("red") {
+rtc_library("red") {
+ visibility += [ "*" ]
sources = [
"codecs/red/audio_encoder_copy_red.cc",
"codecs/red/audio_encoder_copy_red.h",
]
- configs += [ "../..:common_config" ]
-
- public_configs = [
- "../..:common_inherited_config",
- ":red_config",
- ]
-
deps = [
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/units:time_delta",
"../../common_audio",
- ":audio_encoder_interface",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
-config("g711_config") {
- include_dirs = [
- "../../..",
- "codecs/g711/include",
- ]
-}
-
-source_set("g711") {
+rtc_library("g711") {
+ visibility += [ "*" ]
+ poisonous = [ "audio_codecs" ]
sources = [
"codecs/g711/audio_decoder_pcm.cc",
+ "codecs/g711/audio_decoder_pcm.h",
"codecs/g711/audio_encoder_pcm.cc",
- "codecs/g711/g711.c",
- "codecs/g711/g711.h",
- "codecs/g711/g711_interface.c",
- "codecs/g711/include/audio_decoder_pcm.h",
- "codecs/g711/include/audio_encoder_pcm.h",
- "codecs/g711/include/g711_interface.h",
- ]
-
- configs += [ "../..:common_config" ]
-
- public_configs = [
- "../..:common_inherited_config",
- ":g711_config",
+ "codecs/g711/audio_encoder_pcm.h",
]
deps = [
- ":audio_encoder_interface",
+ ":legacy_encoded_audio_frame",
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/units:time_delta",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ public_deps = [ ":g711_c" ] # no-presubmit-check TODO(webrtc:8603)
}
-config("g722_config") {
- include_dirs = [
- "../../..",
- "codecs/g722/include",
+rtc_library("g711_c") {
+ poisonous = [ "audio_codecs" ]
+ sources = [
+ "codecs/g711/g711_interface.c",
+ "codecs/g711/g711_interface.h",
]
+ deps = [ "../third_party/g711:g711_3p" ]
}
-source_set("g722") {
+rtc_library("g722") {
+ visibility += [ "*" ]
+ poisonous = [ "audio_codecs" ]
sources = [
"codecs/g722/audio_decoder_g722.cc",
+ "codecs/g722/audio_decoder_g722.h",
"codecs/g722/audio_encoder_g722.cc",
- "codecs/g722/g722_decode.c",
- "codecs/g722/g722_enc_dec.h",
- "codecs/g722/g722_encode.c",
- "codecs/g722/g722_interface.c",
- "codecs/g722/include/audio_decoder_g722.h",
- "codecs/g722/include/audio_encoder_g722.h",
- "codecs/g722/include/g722_interface.h",
+ "codecs/g722/audio_encoder_g722.h",
]
- configs += [ "../..:common_config" ]
-
- public_configs = [
- "../..:common_inherited_config",
- ":g722_config",
+ deps = [
+ ":legacy_encoded_audio_frame",
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs/g722:audio_encoder_g722_config",
+ "../../api/units:time_delta",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ public_deps = [ ":g722_c" ] # no-presubmit-check TODO(webrtc:8603)
+}
- deps = [
- ":audio_encoder_interface",
+rtc_library("g722_c") {
+ poisonous = [ "audio_codecs" ]
+ sources = [
+ "codecs/g722/g722_interface.c",
+ "codecs/g722/g722_interface.h",
]
+ deps = [ "../third_party/g722:g722_3p" ]
}
-config("ilbc_config") {
- include_dirs = [
- "../../..",
- "codecs/ilbc/include",
+rtc_library("ilbc") {
+ visibility += webrtc_default_visibility
+ poisonous = [ "audio_codecs" ]
+ sources = [
+ "codecs/ilbc/audio_decoder_ilbc.cc",
+ "codecs/ilbc/audio_decoder_ilbc.h",
+ "codecs/ilbc/audio_encoder_ilbc.cc",
+ "codecs/ilbc/audio_encoder_ilbc.h",
+ ]
+
+ deps = [
+ ":legacy_encoded_audio_frame",
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs/ilbc:audio_encoder_ilbc_config",
+ "../../api/units:time_delta",
+ "../../common_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ public_deps = [ ":ilbc_c" ] # no-presubmit-check TODO(webrtc:8603)
}
-source_set("ilbc") {
+rtc_library("ilbc_c") {
+ poisonous = [ "audio_codecs" ]
sources = [
"codecs/ilbc/abs_quant.c",
"codecs/ilbc/abs_quant.h",
"codecs/ilbc/abs_quant_loop.c",
"codecs/ilbc/abs_quant_loop.h",
- "codecs/ilbc/audio_decoder_ilbc.cc",
- "codecs/ilbc/audio_encoder_ilbc.cc",
"codecs/ilbc/augmented_cb_corr.c",
"codecs/ilbc/augmented_cb_corr.h",
"codecs/ilbc/bw_expand.c",
@@ -351,9 +287,7 @@ source_set("ilbc") {
"codecs/ilbc/hp_output.c",
"codecs/ilbc/hp_output.h",
"codecs/ilbc/ilbc.c",
- "codecs/ilbc/include/audio_decoder_ilbc.h",
- "codecs/ilbc/include/audio_encoder_ilbc.h",
- "codecs/ilbc/include/ilbc.h",
+ "codecs/ilbc/ilbc.h",
"codecs/ilbc/index_conv_dec.c",
"codecs/ilbc/index_conv_dec.h",
"codecs/ilbc/index_conv_enc.c",
@@ -426,47 +360,93 @@ source_set("ilbc") {
"codecs/ilbc/xcorr_coef.h",
]
- configs += [ "../..:common_config" ]
-
- public_configs = [
- "../..:common_inherited_config",
- ":ilbc_config",
- ]
-
deps = [
+ "../../api/audio_codecs:audio_codecs_api",
"../../common_audio",
- ":audio_encoder_interface",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:sanitizer",
+ "../../rtc_base/system:arch",
+ "../../rtc_base/system:unused",
]
}
-source_set("isac_common") {
+rtc_source_set("isac_common") {
+ poisonous = [ "audio_codecs" ]
sources = [
+ "codecs/isac/audio_decoder_isac_t.h",
+ "codecs/isac/audio_decoder_isac_t_impl.h",
"codecs/isac/audio_encoder_isac_t.h",
"codecs/isac/audio_encoder_isac_t_impl.h",
- "codecs/isac/locked_bandwidth_info.cc",
- "codecs/isac/locked_bandwidth_info.h",
]
- public_configs = [ "../..:common_inherited_config" ]
-}
-
-config("isac_config") {
- include_dirs = [
- "../../..",
- "codecs/isac/main/include",
+ deps = [
+ ":isac_bwinfo",
+ "../../api:scoped_refptr",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/units:time_delta",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:safe_minmax",
+ "../../system_wrappers:field_trial",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
-source_set("isac") {
+rtc_library("isac") {
+ visibility += [ "*" ]
+ poisonous = [ "audio_codecs" ]
sources = [
"codecs/isac/main/include/audio_decoder_isac.h",
"codecs/isac/main/include/audio_encoder_isac.h",
+ "codecs/isac/main/source/audio_decoder_isac.cc",
+ "codecs/isac/main/source/audio_encoder_isac.cc",
+ ]
+
+ deps = [
+ ":isac_common",
+ "../../api/audio_codecs:audio_codecs_api",
+ ]
+ public_deps = [ ":isac_c" ] # no-presubmit-check TODO(webrtc:8603)
+}
+
+rtc_source_set("isac_bwinfo") {
+ sources = [ "codecs/isac/bandwidth_info.h" ]
+ deps = []
+}
+
+rtc_library("isac_vad") {
+ visibility += webrtc_default_visibility
+ sources = [
+ "codecs/isac/main/source/filter_functions.c",
+ "codecs/isac/main/source/filter_functions.h",
+ "codecs/isac/main/source/isac_vad.c",
+ "codecs/isac/main/source/isac_vad.h",
+ "codecs/isac/main/source/os_specific_inline.h",
+ "codecs/isac/main/source/pitch_estimator.c",
+ "codecs/isac/main/source/pitch_estimator.h",
+ "codecs/isac/main/source/pitch_filter.c",
+ "codecs/isac/main/source/pitch_filter.h",
+ "codecs/isac/main/source/settings.h",
+ "codecs/isac/main/source/structs.h",
+ ]
+ deps = [
+ ":isac_bwinfo",
+ "../../rtc_base:compile_assert_c",
+ "../../rtc_base/system:arch",
+ "../../rtc_base/system:ignore_warnings",
+ "../third_party/fft",
+ ]
+}
+
+rtc_library("isac_c") {
+ poisonous = [ "audio_codecs" ]
+ sources = [
"codecs/isac/main/include/isac.h",
"codecs/isac/main/source/arith_routines.c",
"codecs/isac/main/source/arith_routines.h",
"codecs/isac/main/source/arith_routines_hist.c",
"codecs/isac/main/source/arith_routines_logist.c",
- "codecs/isac/main/source/audio_decoder_isac.cc",
- "codecs/isac/main/source/audio_encoder_isac.cc",
"codecs/isac/main/source/bandwidth_estimator.c",
"codecs/isac/main/source/bandwidth_estimator.h",
"codecs/isac/main/source/codec.h",
@@ -479,11 +459,6 @@ source_set("isac") {
"codecs/isac/main/source/encode_lpc_swb.h",
"codecs/isac/main/source/entropy_coding.c",
"codecs/isac/main/source/entropy_coding.h",
- "codecs/isac/main/source/fft.c",
- "codecs/isac/main/source/fft.h",
- "codecs/isac/main/source/filter_functions.c",
- "codecs/isac/main/source/filterbank_tables.c",
- "codecs/isac/main/source/filterbank_tables.h",
"codecs/isac/main/source/filterbanks.c",
"codecs/isac/main/source/intialize.c",
"codecs/isac/main/source/isac.c",
@@ -499,48 +474,89 @@ source_set("isac") {
"codecs/isac/main/source/lpc_shape_swb16_tables.h",
"codecs/isac/main/source/lpc_tables.c",
"codecs/isac/main/source/lpc_tables.h",
- "codecs/isac/main/source/os_specific_inline.h",
- "codecs/isac/main/source/pitch_estimator.c",
- "codecs/isac/main/source/pitch_estimator.h",
- "codecs/isac/main/source/pitch_filter.c",
"codecs/isac/main/source/pitch_gain_tables.c",
"codecs/isac/main/source/pitch_gain_tables.h",
"codecs/isac/main/source/pitch_lag_tables.c",
"codecs/isac/main/source/pitch_lag_tables.h",
- "codecs/isac/main/source/settings.h",
"codecs/isac/main/source/spectrum_ar_model_tables.c",
"codecs/isac/main/source/spectrum_ar_model_tables.h",
- "codecs/isac/main/source/structs.h",
"codecs/isac/main/source/transform.c",
]
- if (is_linux) {
+ if (is_linux || is_chromeos) {
libs = [ "m" ]
}
- configs += [ "../..:common_config" ]
+ deps = [
+ ":isac_bwinfo",
+ ":isac_vad",
+ "../../common_audio",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:checks",
+ "../../rtc_base:compile_assert_c",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base/system:arch",
+ "../third_party/fft",
+ ]
+}
- public_configs = [
- "../..:common_inherited_config",
- ":isac_config",
+rtc_library("isac_fix") {
+ visibility += [ "*" ]
+ poisonous = [ "audio_codecs" ]
+ sources = [
+ "codecs/isac/fix/source/audio_decoder_isacfix.cc",
+ "codecs/isac/fix/source/audio_encoder_isacfix.cc",
]
deps = [
- ":audio_decoder_interface",
- ":audio_encoder_interface",
":isac_common",
+ "../../api/audio_codecs:audio_codecs_api",
"../../common_audio",
+ "../../system_wrappers",
]
+ public_deps = [ ":isac_fix_c" ] # no-presubmit-check TODO(webrtc:8603)
+
+ if (rtc_build_with_neon) {
+ deps += [ ":isac_neon" ]
+ }
}
-config("isac_fix_config") {
- include_dirs = [
- "../../..",
- "codecs/isac/fix/include",
+rtc_library("isac_fix_common") {
+ poisonous = [ "audio_codecs" ]
+ sources = [
+ "codecs/isac/fix/source/codec.h",
+ "codecs/isac/fix/source/entropy_coding.h",
+ "codecs/isac/fix/source/fft.c",
+ "codecs/isac/fix/source/fft.h",
+ "codecs/isac/fix/source/filterbank_internal.h",
+ "codecs/isac/fix/source/settings.h",
+ "codecs/isac/fix/source/structs.h",
+ "codecs/isac/fix/source/transform_tables.c",
+ ]
+ deps = [
+ ":isac_bwinfo",
+ "../../common_audio",
+ "../../common_audio:common_audio_c",
]
}
-source_set("isac_fix") {
+rtc_source_set("isac_fix_c_arm_asm") {
+ poisonous = [ "audio_codecs" ]
+ sources = []
+ if (current_cpu == "arm" && arm_version >= 7) {
+ sources += [
+ "codecs/isac/fix/source/lattice_armv7.S",
+ "codecs/isac/fix/source/pitch_filter_armv6.S",
+ ]
+ deps = [
+ ":isac_fix_common",
+ "../../rtc_base/system:asm_defines",
+ ]
+ }
+}
+
+rtc_library("isac_fix_c") {
+ poisonous = [ "audio_codecs" ]
sources = [
"codecs/isac/fix/include/audio_decoder_isacfix.h",
"codecs/isac/fix/include/audio_encoder_isacfix.h",
@@ -549,19 +565,13 @@ source_set("isac_fix") {
"codecs/isac/fix/source/arith_routines_hist.c",
"codecs/isac/fix/source/arith_routines_logist.c",
"codecs/isac/fix/source/arith_routins.h",
- "codecs/isac/fix/source/audio_decoder_isacfix.cc",
- "codecs/isac/fix/source/audio_encoder_isacfix.cc",
"codecs/isac/fix/source/bandwidth_estimator.c",
"codecs/isac/fix/source/bandwidth_estimator.h",
- "codecs/isac/fix/source/codec.h",
"codecs/isac/fix/source/decode.c",
"codecs/isac/fix/source/decode_bwe.c",
"codecs/isac/fix/source/decode_plc.c",
"codecs/isac/fix/source/encode.c",
"codecs/isac/fix/source/entropy_coding.c",
- "codecs/isac/fix/source/entropy_coding.h",
- "codecs/isac/fix/source/fft.c",
- "codecs/isac/fix/source/fft.h",
"codecs/isac/fix/source/filterbank_tables.c",
"codecs/isac/fix/source/filterbank_tables.h",
"codecs/isac/fix/source/filterbanks.c",
@@ -584,45 +594,44 @@ source_set("isac_fix") {
"codecs/isac/fix/source/pitch_gain_tables.h",
"codecs/isac/fix/source/pitch_lag_tables.c",
"codecs/isac/fix/source/pitch_lag_tables.h",
- "codecs/isac/fix/source/settings.h",
"codecs/isac/fix/source/spectrum_ar_model_tables.c",
"codecs/isac/fix/source/spectrum_ar_model_tables.h",
- "codecs/isac/fix/source/structs.h",
"codecs/isac/fix/source/transform.c",
- "codecs/isac/fix/source/transform_tables.c",
- ]
-
- if (!is_win) {
- defines = [ "WEBRTC_LINUX" ]
- }
-
- configs += [ "../..:common_config" ]
-
- public_configs = [
- "../..:common_inherited_config",
- ":isac_fix_config",
]
deps = [
- ":audio_encoder_interface",
+ ":isac_bwinfo",
":isac_common",
+ "../../api/audio_codecs:audio_codecs_api",
"../../common_audio",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:checks",
+ "../../rtc_base:compile_assert_c",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:sanitizer",
"../../system_wrappers",
+ "../third_party/fft",
]
+ public_deps = [ ":isac_fix_common" ] # no-presubmit-check TODO(webrtc:8603)
+
if (rtc_build_with_neon) {
deps += [ ":isac_neon" ]
+
+ # TODO(bugs.webrtc.org/9579): Consider moving the usage of NEON from
+ # pitch_estimator_c.c into the "isac_neon" target and delete this flag:
+ if (current_cpu != "arm64") {
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags = [ "-mfpu=neon" ]
+ }
}
if (current_cpu == "arm" && arm_version >= 7) {
- sources += [
- "codecs/isac/fix/source/lattice_armv7.S",
- "codecs/isac/fix/source/pitch_filter_armv6.S",
- ]
sources -= [
"codecs/isac/fix/source/lattice_c.c",
"codecs/isac/fix/source/pitch_filter_c.c",
]
+ deps += [ ":isac_fix_c_arm_asm" ]
}
if (current_cpu == "mipsel") {
@@ -651,7 +660,8 @@ source_set("isac_fix") {
}
if (rtc_build_with_neon) {
- source_set("isac_neon") {
+ rtc_library("isac_neon") {
+ poisonous = [ "audio_codecs" ]
sources = [
"codecs/isac/fix/source/entropy_coding_neon.c",
"codecs/isac/fix/source/filterbanks_neon.c",
@@ -661,108 +671,259 @@ if (rtc_build_with_neon) {
]
if (current_cpu != "arm64") {
- # Enable compilation for the NEON instruction set. This is needed
- # since //build/config/arm.gni only enables NEON for iOS, not Android.
- # This provides the same functionality as webrtc/build/arm_neon.gypi.
- configs -= [ "//build/config/compiler:compiler_arm_fpu" ]
+ # Enable compilation for the NEON instruction set.
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
cflags = [ "-mfpu=neon" ]
}
- # Disable LTO on NEON targets due to compiler bug.
- # TODO(fdegans): Enable this. See crbug.com/408997.
- if (rtc_use_lto) {
- cflags -= [
- "-flto",
- "-ffat-lto-objects",
- ]
- }
-
- configs += [ "../..:common_config" ]
- public_configs = [ "../..:common_inherited_config" ]
-
deps = [
+ ":isac_fix_common",
"../../common_audio",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
]
}
}
-config("pcm16b_config") {
- include_dirs = [
- "../../..",
- "codecs/pcm16b/include",
- ]
-}
-
-source_set("pcm16b") {
+rtc_library("pcm16b") {
+ visibility += [ "*" ]
+ poisonous = [ "audio_codecs" ]
sources = [
"codecs/pcm16b/audio_decoder_pcm16b.cc",
+ "codecs/pcm16b/audio_decoder_pcm16b.h",
"codecs/pcm16b/audio_encoder_pcm16b.cc",
- "codecs/pcm16b/include/audio_decoder_pcm16b.h",
- "codecs/pcm16b/include/audio_encoder_pcm16b.h",
- "codecs/pcm16b/include/pcm16b.h",
- "codecs/pcm16b/pcm16b.c",
+ "codecs/pcm16b/audio_encoder_pcm16b.h",
+ "codecs/pcm16b/pcm16b_common.cc",
+ "codecs/pcm16b/pcm16b_common.h",
]
deps = [
- ":audio_encoder_interface",
":g711",
+ ":legacy_encoded_audio_frame",
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
]
+ public_deps = [ ":pcm16b_c" ] # no-presubmit-check TODO(webrtc:8603)
+}
- configs += [ "../..:common_config" ]
-
- public_configs = [
- "../..:common_inherited_config",
- ":pcm16b_config",
+rtc_library("pcm16b_c") {
+ poisonous = [ "audio_codecs" ]
+ sources = [
+ "codecs/pcm16b/pcm16b.c",
+ "codecs/pcm16b/pcm16b.h",
]
}
-config("opus_config") {
- include_dirs = [ "../../.." ]
+rtc_library("audio_coding_opus_common") {
+ sources = [
+ "codecs/opus/audio_coder_opus_common.cc",
+ "codecs/opus/audio_coder_opus_common.h",
+ ]
+
+ deps = [
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../rtc_base:checks",
+ "../../rtc_base:stringutils",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
}
-source_set("webrtc_opus") {
+rtc_library("webrtc_opus") {
+ visibility += webrtc_default_visibility
+ poisonous = [ "audio_codecs" ]
sources = [
"codecs/opus/audio_decoder_opus.cc",
+ "codecs/opus/audio_decoder_opus.h",
"codecs/opus/audio_encoder_opus.cc",
- "codecs/opus/include/audio_decoder_opus.h",
- "codecs/opus/include/audio_encoder_opus.h",
- "codecs/opus/include/opus_interface.h",
- "codecs/opus/opus_inst.h",
- "codecs/opus/opus_interface.c",
+ "codecs/opus/audio_encoder_opus.h",
]
deps = [
- ":audio_encoder_interface",
+ ":audio_coding_opus_common",
+ ":audio_network_adaptor",
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs/opus:audio_encoder_opus_config",
+ "../../common_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:protobuf_utils",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:rtc_numerics",
+ "../../rtc_base:safe_minmax",
+ "../../system_wrappers:field_trial",
]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ public_deps = # no-presubmit-check TODO(webrtc:8603)
+ [ ":webrtc_opus_wrapper" ]
+
+ defines = audio_codec_defines
if (rtc_build_opus) {
- configs += [ "../..:common_config" ]
- public_configs = [ "../..:common_inherited_config" ]
+ public_deps += [ rtc_opus_dir ] # no-presubmit-check TODO(webrtc:8603)
+ } else if (build_with_mozilla) {
+ include_dirs = [ "/media/libopus/include" ]
+ }
+}
- public_deps = [
- rtc_opus_dir,
- ]
+rtc_library("webrtc_multiopus") {
+ visibility += webrtc_default_visibility
+ poisonous = [ "audio_codecs" ]
+ sources = [
+ "codecs/opus/audio_decoder_multi_channel_opus_impl.cc",
+ "codecs/opus/audio_decoder_multi_channel_opus_impl.h",
+ "codecs/opus/audio_encoder_multi_channel_opus_impl.cc",
+ "codecs/opus/audio_encoder_multi_channel_opus_impl.h",
+ ]
+
+ deps = [
+ ":audio_coding_opus_common",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs/opus:audio_decoder_opus_config",
+ "../../api/audio_codecs/opus:audio_encoder_opus_config",
+ "../../api/units:time_delta",
+ "../../rtc_base:checks",
+ "../../rtc_base:logging",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:safe_minmax",
+ "../../rtc_base:stringutils",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ public_deps = # no-presubmit-check TODO(webrtc:8603)
+ [ ":webrtc_opus_wrapper" ]
+
+ defines = audio_codec_defines
+
+ if (rtc_build_opus) {
+ public_deps += [ rtc_opus_dir ]
+ } else if (build_with_mozilla) {
+ include_dirs = [ "/media/libopus/include" ]
+ }
+}
+
+rtc_library("webrtc_opus_wrapper") {
+ poisonous = [ "audio_codecs" ]
+ sources = [
+ "codecs/opus/opus_inst.h",
+ "codecs/opus/opus_interface.cc",
+ "codecs/opus/opus_interface.h",
+ ]
+
+ defines = audio_coding_defines
+
+ if (rtc_build_opus) {
+ public_deps = [ rtc_opus_dir ] # no-presubmit-check TODO(webrtc:8603)
} else if (build_with_mozilla) {
include_dirs = [ getenv("DIST") + "/include/opus" ]
}
+
+ deps = [
+ "../../rtc_base:checks",
+ "../../rtc_base:ignore_wundef",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers:field_trial",
+ ]
+}
+
+if (rtc_enable_protobuf) {
+ proto_library("ana_debug_dump_proto") {
+ visibility += webrtc_default_visibility
+ sources = [ "audio_network_adaptor/debug_dump.proto" ]
+ link_deps = [ ":ana_config_proto" ]
+ proto_out_dir = "modules/audio_coding/audio_network_adaptor"
+ }
+ proto_library("ana_config_proto") {
+ visibility += [ "*" ]
+ sources = [ "audio_network_adaptor/config.proto" ]
+ proto_out_dir = "modules/audio_coding/audio_network_adaptor"
+ }
+}
+
+rtc_library("audio_network_adaptor_config") {
+ visibility += webrtc_default_visibility
+ sources = [
+ "audio_network_adaptor/audio_network_adaptor_config.cc",
+ "audio_network_adaptor/include/audio_network_adaptor_config.h",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
-config("neteq_config") {
- include_dirs = [
- # Need Opus header files for the audio classifier.
- "//third_party/opus/src/celt",
- "//third_party/opus/src/src",
+rtc_library("audio_network_adaptor") {
+ visibility += webrtc_default_visibility
+ sources = [
+ "audio_network_adaptor/audio_network_adaptor_impl.cc",
+ "audio_network_adaptor/audio_network_adaptor_impl.h",
+ "audio_network_adaptor/bitrate_controller.cc",
+ "audio_network_adaptor/bitrate_controller.h",
+ "audio_network_adaptor/channel_controller.cc",
+ "audio_network_adaptor/channel_controller.h",
+ "audio_network_adaptor/controller.cc",
+ "audio_network_adaptor/controller.h",
+ "audio_network_adaptor/controller_manager.cc",
+ "audio_network_adaptor/controller_manager.h",
+ "audio_network_adaptor/debug_dump_writer.cc",
+ "audio_network_adaptor/debug_dump_writer.h",
+ "audio_network_adaptor/dtx_controller.cc",
+ "audio_network_adaptor/dtx_controller.h",
+ "audio_network_adaptor/event_log_writer.cc",
+ "audio_network_adaptor/event_log_writer.h",
+ "audio_network_adaptor/fec_controller_plr_based.cc",
+ "audio_network_adaptor/fec_controller_plr_based.h",
+ "audio_network_adaptor/frame_length_controller.cc",
+ "audio_network_adaptor/frame_length_controller.h",
+ "audio_network_adaptor/frame_length_controller_v2.cc",
+ "audio_network_adaptor/frame_length_controller_v2.h",
+ "audio_network_adaptor/include/audio_network_adaptor.h",
+ "audio_network_adaptor/util/threshold_curve.h",
+ ]
+
+ public_deps = # no-presubmit-check TODO(webrtc:8603)
+ [ ":audio_network_adaptor_config" ]
+
+ deps = [
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/rtc_event_log",
+ "../../common_audio",
+ "../../logging:rtc_event_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:ignore_wundef",
+ "../../rtc_base:protobuf_utils",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base/system:file_wrapper",
+ "../../system_wrappers",
+ "../../system_wrappers:field_trial",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/algorithm:container",
+ "//third_party/abseil-cpp/absl/types:optional",
]
+
+ if (rtc_enable_protobuf) {
+ deps += [
+ ":ana_config_proto",
+ ":ana_debug_dump_proto",
+ ]
+ }
}
-source_set("neteq") {
+rtc_library("neteq") {
+ visibility += webrtc_default_visibility
sources = [
"neteq/accelerate.cc",
"neteq/accelerate.h",
- "neteq/audio_classifier.cc",
- "neteq/audio_classifier.h",
- "neteq/audio_decoder_impl.cc",
- "neteq/audio_decoder_impl.h",
"neteq/audio_multi_vector.cc",
"neteq/audio_multi_vector.h",
"neteq/audio_vector.cc",
@@ -773,19 +934,14 @@ source_set("neteq") {
"neteq/buffer_level_filter.h",
"neteq/comfort_noise.cc",
"neteq/comfort_noise.h",
+ "neteq/cross_correlation.cc",
+ "neteq/cross_correlation.h",
"neteq/decision_logic.cc",
"neteq/decision_logic.h",
- "neteq/decision_logic_fax.cc",
- "neteq/decision_logic_fax.h",
- "neteq/decision_logic_normal.cc",
- "neteq/decision_logic_normal.h",
"neteq/decoder_database.cc",
"neteq/decoder_database.h",
- "neteq/defines.h",
"neteq/delay_manager.cc",
"neteq/delay_manager.h",
- "neteq/delay_peak_detector.cc",
- "neteq/delay_peak_detector.h",
"neteq/dsp_helper.cc",
"neteq/dsp_helper.h",
"neteq/dtmf_buffer.cc",
@@ -794,28 +950,30 @@ source_set("neteq") {
"neteq/dtmf_tone_generator.h",
"neteq/expand.cc",
"neteq/expand.h",
- "neteq/include/neteq.h",
+ "neteq/expand_uma_logger.cc",
+ "neteq/expand_uma_logger.h",
+ "neteq/histogram.cc",
+ "neteq/histogram.h",
"neteq/merge.cc",
"neteq/merge.h",
- "neteq/nack.cc",
- "neteq/nack.h",
- "neteq/neteq.cc",
+ "neteq/nack_tracker.cc",
+ "neteq/nack_tracker.h",
"neteq/neteq_impl.cc",
"neteq/neteq_impl.h",
"neteq/normal.cc",
"neteq/normal.h",
+ "neteq/packet.cc",
+ "neteq/packet.h",
"neteq/packet_buffer.cc",
"neteq/packet_buffer.h",
- "neteq/payload_splitter.cc",
- "neteq/payload_splitter.h",
"neteq/post_decode_vad.cc",
"neteq/post_decode_vad.h",
"neteq/preemptive_expand.cc",
"neteq/preemptive_expand.h",
"neteq/random_vector.cc",
"neteq/random_vector.h",
- "neteq/rtcp.cc",
- "neteq/rtcp.h",
+ "neteq/red_payload_splitter.cc",
+ "neteq/red_payload_splitter.h",
"neteq/statistics_calculator.cc",
"neteq/statistics_calculator.h",
"neteq/sync_buffer.cc",
@@ -826,42 +984,1132 @@ source_set("neteq") {
"neteq/timestamp_scaler.h",
]
- configs += [ "../..:common_config" ]
+ deps = [
+ ":audio_coding_module_typedefs",
+ ":webrtc_cng",
+ "..:module_api",
+ "..:module_api_public",
+ "../../api:array_view",
+ "../../api:rtp_headers",
+ "../../api:rtp_packet_info",
+ "../../api:scoped_refptr",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/neteq:neteq_api",
+ "../../api/neteq:neteq_controller_api",
+ "../../api/neteq:tick_timer",
+ "../../common_audio",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:audio_format_to_string",
+ "../../rtc_base:checks",
+ "../../rtc_base:gtest_prod",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:safe_minmax",
+ "../../rtc_base:sanitizer",
+ "../../rtc_base/experiments:field_trial_parser",
+ "../../rtc_base/synchronization:mutex",
+ "../../system_wrappers",
+ "../../system_wrappers:field_trial",
+ "../../system_wrappers:metrics",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
- public_configs = [
- "../..:common_inherited_config",
- ":neteq_config",
+rtc_source_set("default_neteq_factory") {
+ visibility += webrtc_default_visibility
+ sources = [
+ "neteq/default_neteq_factory.cc",
+ "neteq/default_neteq_factory.h",
+ ]
+ deps = [
+ ":neteq",
+ "../../api:scoped_refptr",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/neteq:default_neteq_controller_factory",
+ "../../api/neteq:neteq_api",
+ "../../system_wrappers:system_wrappers",
+ ]
+}
+
+# Although providing only test support, this target must be outside of the
+# rtc_include_tests conditional. The reason is that it supports fuzzer tests
+# that ultimately are built and run as a part of the Chromium ecosystem, which
+# does not set the rtc_include_tests flag.
+rtc_library("neteq_tools_minimal") {
+ visibility += webrtc_default_visibility
+ sources = [
+ "neteq/tools/audio_sink.cc",
+ "neteq/tools/audio_sink.h",
+ "neteq/tools/encode_neteq_input.cc",
+ "neteq/tools/encode_neteq_input.h",
+ "neteq/tools/neteq_input.cc",
+ "neteq/tools/neteq_input.h",
+ "neteq/tools/neteq_test.cc",
+ "neteq/tools/neteq_test.h",
+ "neteq/tools/packet.cc",
+ "neteq/tools/packet.h",
+ "neteq/tools/packet_source.cc",
+ "neteq/tools/packet_source.h",
+ ]
+
+ deps = [
+ ":default_neteq_factory",
+ ":neteq",
+ "../../api:neteq_simulator_api",
+ "../../api:rtp_headers",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/neteq:custom_neteq_factory",
+ "../../api/neteq:default_neteq_controller_factory",
+ "../../api/neteq:neteq_api",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers",
+ "../rtp_rtcp",
+ "../rtp_rtcp:rtp_rtcp_format",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ defines = audio_codec_defines
+}
+
+rtc_library("neteq_test_tools") {
+ visibility += webrtc_default_visibility
+ testonly = true
+ sources = [
+ "neteq/tools/audio_checksum.h",
+ "neteq/tools/audio_loop.cc",
+ "neteq/tools/audio_loop.h",
+ "neteq/tools/constant_pcm_packet_source.cc",
+ "neteq/tools/constant_pcm_packet_source.h",
+ "neteq/tools/initial_packet_inserter_neteq_input.cc",
+ "neteq/tools/initial_packet_inserter_neteq_input.h",
+ "neteq/tools/neteq_packet_source_input.cc",
+ "neteq/tools/neteq_packet_source_input.h",
+ "neteq/tools/output_audio_file.h",
+ "neteq/tools/output_wav_file.h",
+ "neteq/tools/rtp_file_source.cc",
+ "neteq/tools/rtp_file_source.h",
+ "neteq/tools/rtp_generator.cc",
+ "neteq/tools/rtp_generator.h",
]
deps = [
- ":audio_decoder_interface",
- ":cng",
- ":g711",
":pcm16b",
- "../..:webrtc_common",
+ "../../api:array_view",
+ "../../api:rtp_headers",
+ "../../common_audio",
+ "../../rtc_base",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base/system:arch",
+ "../../test:rtp_test_utils",
+ "../rtp_rtcp",
+ "../rtp_rtcp:rtp_rtcp_format",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+
+ public_deps = [
+ ":neteq_tools",
+ ":neteq_tools_minimal",
+ ]
+
+ if (rtc_enable_protobuf) {
+ sources += [
+ "neteq/tools/neteq_event_log_input.cc",
+ "neteq/tools/neteq_event_log_input.h",
+ ]
+ deps += [ ":rtc_event_log_source" ]
+ }
+}
+
+rtc_library("neteq_tools") {
+ visibility += webrtc_default_visibility
+ sources = [
+ "neteq/tools/fake_decode_from_file.cc",
+ "neteq/tools/fake_decode_from_file.h",
+ "neteq/tools/neteq_delay_analyzer.cc",
+ "neteq/tools/neteq_delay_analyzer.h",
+ "neteq/tools/neteq_replacement_input.cc",
+ "neteq/tools/neteq_replacement_input.h",
+ "neteq/tools/neteq_stats_getter.cc",
+ "neteq/tools/neteq_stats_getter.h",
+ "neteq/tools/neteq_stats_plotter.cc",
+ "neteq/tools/neteq_stats_plotter.h",
+ ]
+
+ deps = [
+ "..:module_api_public",
+ "../../api:array_view",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../rtp_rtcp",
+ "../rtp_rtcp:rtp_rtcp_format",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+
+ public_deps = [
+ ":neteq_input_audio_tools",
+ ":neteq_tools_minimal",
+ ]
+}
+
+rtc_library("neteq_input_audio_tools") {
+ visibility += webrtc_default_visibility
+ sources = [
+ "neteq/tools/input_audio_file.cc",
+ "neteq/tools/input_audio_file.h",
+ "neteq/tools/resample_input_audio_file.cc",
+ "neteq/tools/resample_input_audio_file.h",
+ ]
+
+ deps = [
"../../common_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ ]
+}
+
+if (rtc_enable_protobuf) {
+ rtc_library("rtc_event_log_source") {
+ testonly = true
+
+ sources = [
+ "neteq/tools/rtc_event_log_source.cc",
+ "neteq/tools/rtc_event_log_source.h",
+ ]
+
+ deps = [
+ ":neteq_tools_minimal",
+ "../../logging:rtc_event_log_parser",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../rtp_rtcp",
+ "../rtp_rtcp:rtp_rtcp_format",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ public_deps = # no-presubmit-check TODO(webrtc:8603)
+ [ "../../logging:rtc_event_log_proto" ]
+ }
+
+ # Only used for test purpose. Since we want to use it from chromium
+ # (see audio_coding_modules_tests_shared below), we cannot guard it
+ # under rtc_include_tests.
+ proto_library("neteq_unittest_proto") {
+ testonly = true
+ sources = [ "neteq/neteq_unittest.proto" ]
+ proto_out_dir = "modules/audio_coding/neteq"
+ }
+}
+
+# Allow to re-use some test classes from chromium.
+rtc_library("audio_coding_modules_tests_shared") {
+ testonly = true
+ visibility = []
+ visibility = [ "*" ]
+
+ sources = [
+ "neteq/test/neteq_decoding_test.cc",
+ "neteq/test/neteq_decoding_test.h",
+ "neteq/test/result_sink.cc",
+ "neteq/test/result_sink.h",
+ "test/PCMFile.cc",
+ "test/PCMFile.h",
+ "test/TestStereo.cc",
+ "test/TestStereo.h",
+ "test/opus_test.cc",
+ "test/opus_test.h",
+ ]
+
+ deps = [
+ ":audio_coding",
+ ":audio_coding_module_typedefs",
+ ":default_neteq_factory",
+ ":neteq_test_tools",
+ ":neteq_tools_minimal",
+ ":webrtc_opus_wrapper",
+ "..:module_api",
+ "../../api:rtp_headers",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
+ "../../api/audio_codecs:builtin_audio_encoder_factory",
+ "../../api/neteq:neteq_api",
+ "../../rtc_base",
+ "../../rtc_base:checks",
+ "../../rtc_base:ignore_wundef",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:stringutils",
"../../system_wrappers",
+ "../../test:fileutils",
+ "../../test:test_support",
+ "../rtp_rtcp:rtp_rtcp_format",
+ "//testing/gtest",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
]
+ defines = audio_coding_defines
- defines = []
+ if (rtc_enable_protobuf) {
+ defines += [ "WEBRTC_NETEQ_UNITTEST_BITEXACT" ]
+ deps += [ ":neteq_unittest_proto" ]
+ }
+}
+if (rtc_include_tests) {
+ audio_coding_deps = [
+ ":audio_encoder_cng",
+ ":g711",
+ ":g722",
+ ":pcm16b",
+ "../../common_audio",
+ "../../system_wrappers",
+ ]
+ if (rtc_include_ilbc) {
+ audio_coding_deps += [ ":ilbc" ]
+ }
if (rtc_include_opus) {
- defines += [ "WEBRTC_CODEC_OPUS" ]
- deps += [ ":webrtc_opus" ]
- }
- if (!build_with_mozilla) {
- if (current_cpu == "arm") {
- defines += [ "WEBRTC_CODEC_ISACFX" ]
- deps += [ ":isac_fix" ]
- } else {
- defines += [ "WEBRTC_CODEC_ISAC" ]
- deps += [ ":isac" ]
- }
- defines += [ "WEBRTC_CODEC_G722" ]
- deps += [ ":g722" ]
+ audio_coding_deps += [ ":webrtc_opus" ]
+ }
+ if (current_cpu == "arm") {
+ audio_coding_deps += [ ":isac_fix" ]
+ } else {
+ audio_coding_deps += [ ":isac" ]
}
if (!build_with_mozilla && !build_with_chromium) {
- defines += [ "WEBRTC_CODEC_ILBC" ]
- deps += [ ":ilbc" ]
+ audio_coding_deps += [ ":red" ]
+ }
+
+ rtc_source_set("mocks") {
+ testonly = true
+ sources = [
+ "audio_network_adaptor/mock/mock_audio_network_adaptor.h",
+ "audio_network_adaptor/mock/mock_controller.h",
+ "audio_network_adaptor/mock/mock_controller_manager.h",
+ "audio_network_adaptor/mock/mock_debug_dump_writer.h",
+ ]
+ deps = [
+ ":audio_network_adaptor",
+ "../../test:test_support",
+ ]
+ }
+
+ group("audio_coding_tests") {
+ visibility += webrtc_default_visibility
+ testonly = true
+ public_deps = [
+ ":acm_receive_test",
+ ":acm_send_test",
+ ":audio_codec_speed_tests",
+ ":audio_decoder_unittests",
+ ":audio_decoder_unittests",
+ ":g711_test",
+ ":g722_test",
+ ":ilbc_test",
+ ":isac_api_test",
+ ":isac_fix_test",
+ ":isac_switch_samprate_test",
+ ":isac_test",
+ ":neteq_ilbc_quality_test",
+ ":neteq_isac_quality_test",
+ ":neteq_opus_quality_test",
+ ":neteq_pcm16b_quality_test",
+ ":neteq_pcmu_quality_test",
+ ":neteq_speed_test",
+ ":rtp_analyze",
+ ":rtp_encode",
+ ":rtp_jitter",
+ ":rtpcat",
+ ":webrtc_opus_fec_test",
+ ]
+ if (rtc_enable_protobuf) {
+ public_deps += [ ":neteq_rtpplay" ]
+ }
+ }
+
+ rtc_library("audio_coding_modules_tests") {
+ testonly = true
+ visibility += webrtc_default_visibility
+
+ sources = [
+ "test/Channel.cc",
+ "test/Channel.h",
+ "test/EncodeDecodeTest.cc",
+ "test/EncodeDecodeTest.h",
+ "test/PacketLossTest.cc",
+ "test/PacketLossTest.h",
+ "test/RTPFile.cc",
+ "test/RTPFile.h",
+ "test/TestAllCodecs.cc",
+ "test/TestAllCodecs.h",
+ "test/TestRedFec.cc",
+ "test/TestRedFec.h",
+ "test/TestVADDTX.cc",
+ "test/TestVADDTX.h",
+ "test/Tester.cc",
+ "test/TwoWayCommunication.cc",
+ "test/TwoWayCommunication.h",
+ "test/iSACTest.cc",
+ "test/iSACTest.h",
+ "test/target_delay_unittest.cc",
+ ]
+ deps = [
+ ":audio_coding",
+ ":audio_coding_module_typedefs",
+ ":audio_coding_modules_tests_shared",
+ ":audio_encoder_cng",
+ ":pcm16b_c",
+ ":red",
+ ":webrtc_opus_wrapper",
+ "..:module_api",
+ "../../api:rtp_headers",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
+ "../../api/audio_codecs:builtin_audio_encoder_factory",
+ "../../api/audio_codecs/L16:audio_decoder_L16",
+ "../../api/audio_codecs/L16:audio_encoder_L16",
+ "../../api/audio_codecs/g711:audio_decoder_g711",
+ "../../api/audio_codecs/g711:audio_encoder_g711",
+ "../../api/audio_codecs/g722:audio_decoder_g722",
+ "../../api/audio_codecs/g722:audio_encoder_g722",
+ "../../api/audio_codecs/ilbc:audio_decoder_ilbc",
+ "../../api/audio_codecs/ilbc:audio_encoder_ilbc",
+ "../../api/audio_codecs/isac:audio_decoder_isac_float",
+ "../../api/audio_codecs/isac:audio_encoder_isac_float",
+ "../../api/audio_codecs/opus:audio_decoder_opus",
+ "../../api/audio_codecs/opus:audio_encoder_opus",
+ "../../common_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base/synchronization:mutex",
+ "../../rtc_base/synchronization:rw_lock_wrapper",
+ "../../system_wrappers",
+ "../../test:fileutils",
+ "../../test:test_support",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ defines = audio_coding_defines
+ }
+
+ rtc_library("audio_coding_perf_tests") {
+ testonly = true
+ visibility += webrtc_default_visibility
+
+ sources = [
+ "codecs/opus/opus_complexity_unittest.cc",
+ "neteq/test/neteq_performance_unittest.cc",
+ ]
+ deps = [
+ ":neteq_test_support",
+ ":neteq_test_tools",
+ "../../api/audio_codecs/opus:audio_encoder_opus",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers",
+ "../../system_wrappers:field_trial",
+ "../../test:fileutils",
+ "../../test:perf_test",
+ "../../test:test_support",
+ ]
+ }
+
+ rtc_library("acm_receive_test") {
+ testonly = true
+ sources = [
+ "acm2/acm_receive_test.cc",
+ "acm2/acm_receive_test.h",
+ ]
+
+ defines = audio_coding_defines
+
+ deps = audio_coding_deps + [
+ "../../api:scoped_refptr",
+ "..:module_api",
+ ":audio_coding",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
+ ":neteq_tools",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:test_support",
+ "//testing/gtest",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+ }
+
+ rtc_library("acm_send_test") {
+ testonly = true
+ sources = [
+ "acm2/acm_send_test.cc",
+ "acm2/acm_send_test.h",
+ ]
+
+ defines = audio_coding_defines
+
+ deps = audio_coding_deps + [
+ "//third_party/abseil-cpp/absl/strings",
+ "../../api/audio:audio_frame_api",
+ "../../rtc_base:checks",
+ ":audio_coding",
+ ":neteq_tools",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
+ "../../api/audio_codecs:builtin_audio_encoder_factory",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+
+ audio_decoder_unittests_resources =
+ [ "../../resources/audio_coding/testfile32kHz.pcm" ]
+
+ if (is_ios) {
+ bundle_data("audio_decoder_unittests_bundle_data") {
+ testonly = true
+ sources = audio_decoder_unittests_resources
+ outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
+ }
+ }
+
+ rtc_test("audio_decoder_unittests") {
+ testonly = true
+ sources = [ "neteq/audio_decoder_unittest.cc" ]
+
+ defines = neteq_defines
+
+ deps = [
+ ":ilbc",
+ ":isac",
+ ":isac_fix",
+ ":neteq",
+ ":neteq_tools",
+ "../../test:fileutils",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs/opus:audio_encoder_opus",
+ "../../common_audio",
+ "../../rtc_base/system:arch",
+ "../../test:test_main",
+ "//testing/gtest",
+ "../../test:test_support",
+ ] + audio_coding_deps
+
+ data = audio_decoder_unittests_resources
+
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_native_code" ]
+ shard_timeout = 900
+ }
+ if (is_ios) {
+ deps += [ ":audio_decoder_unittests_bundle_data" ]
+ }
}
+
+ if (rtc_enable_protobuf) {
+ rtc_library("neteq_test_factory") {
+ testonly = true
+ visibility += webrtc_default_visibility
+ defines = audio_codec_defines
+ deps = [
+ "../../rtc_base:checks",
+ "../../test:fileutils",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ sources = [
+ "neteq/tools/neteq_test_factory.cc",
+ "neteq/tools/neteq_test_factory.h",
+ ]
+
+ deps += [
+ ":neteq",
+ ":neteq_test_tools",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
+ "../../api/neteq:neteq_api",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:audio_codec_mocks",
+ "../../test:field_trial",
+ "../../test:test_support",
+ ]
+ }
+
+ rtc_executable("neteq_rtpplay") {
+ testonly = true
+ visibility += [ "*" ]
+ defines = []
+ deps = [
+ ":neteq_test_factory",
+ ":neteq_test_tools",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:stringutils",
+ "../../system_wrappers:field_trial",
+ "../../test:field_trial",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ sources = [ "neteq/tools/neteq_rtpplay.cc" ]
+ }
+ }
+
+ audio_codec_speed_tests_resources = [
+ "//resources/audio_coding/music_stereo_48kHz.pcm",
+ "//resources/audio_coding/speech_mono_16kHz.pcm",
+ "//resources/audio_coding/speech_mono_32_48kHz.pcm",
+ ]
+
+ if (is_ios) {
+ bundle_data("audio_codec_speed_tests_data") {
+ testonly = true
+ sources = audio_codec_speed_tests_resources
+ outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
+ }
+ }
+
+ rtc_test("audio_codec_speed_tests") {
+ testonly = true
+ defines = []
+ deps = [ "../../test:fileutils" ]
+ sources = [
+ "codecs/isac/fix/test/isac_speed_test.cc",
+ "codecs/opus/opus_speed_test.cc",
+ "codecs/tools/audio_codec_speed_test.cc",
+ "codecs/tools/audio_codec_speed_test.h",
+ ]
+
+ data = audio_codec_speed_tests_resources
+
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_native_code" ]
+ shard_timeout = 900
+ }
+
+ if (is_ios) {
+ deps += [ ":audio_codec_speed_tests_data" ]
+ }
+
+ deps += [
+ ":isac_fix",
+ ":webrtc_opus",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:test_main",
+ "../../test:test_support",
+ "../audio_processing",
+ "//testing/gtest",
+ ]
+ }
+
+ rtc_library("neteq_test_support") {
+ testonly = true
+ sources = [
+ "neteq/tools/neteq_performance_test.cc",
+ "neteq/tools/neteq_performance_test.h",
+ ]
+
+ deps = [
+ ":default_neteq_factory",
+ ":neteq",
+ ":neteq_test_tools",
+ ":pcm16b",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
+ "../../api/neteq:neteq_api",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers",
+ "../../test:fileutils",
+ "../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+
+ rtc_library("neteq_quality_test_support") {
+ testonly = true
+ sources = [
+ "neteq/tools/neteq_quality_test.cc",
+ "neteq/tools/neteq_quality_test.h",
+ ]
+
+ deps = [
+ ":default_neteq_factory",
+ ":neteq",
+ ":neteq_test_tools",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
+ "../../api/neteq:neteq_api",
+ "../../rtc_base:checks",
+ "../../system_wrappers",
+ "../../test:fileutils",
+ "../../test:test_support",
+ "//testing/gtest",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/flags:flag" ]
+ }
+
+ rtc_executable("rtp_encode") {
+ testonly = true
+
+ deps = audio_coding_deps + [
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ ":audio_coding",
+ ":audio_encoder_cng",
+ ":neteq_input_audio_tools",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio_codecs/g711:audio_encoder_g711",
+ "../../api/audio_codecs/L16:audio_encoder_L16",
+ "../../api/audio_codecs/g722:audio_encoder_g722",
+ "../../api/audio_codecs/ilbc:audio_encoder_ilbc",
+ "../../api/audio_codecs/isac:audio_encoder_isac",
+ "../../api/audio_codecs/opus:audio_encoder_opus",
+ "../../rtc_base:safe_conversions",
+ "//third_party/abseil-cpp/absl/memory",
+ ]
+
+ sources = [ "neteq/tools/rtp_encode.cc" ]
+
+ defines = audio_coding_defines
+ }
+
+ rtc_executable("rtp_jitter") {
+ testonly = true
+
+ deps = audio_coding_deps + [
+ "../rtp_rtcp:rtp_rtcp_format",
+ "../../api:array_view",
+ "../../rtc_base:rtc_base_approved",
+ ]
+
+ sources = [ "neteq/tools/rtp_jitter.cc" ]
+
+ defines = audio_coding_defines
+ }
+
+ rtc_executable("rtpcat") {
+ testonly = true
+
+ sources = [ "neteq/tools/rtpcat.cc" ]
+
+ deps = [
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:rtp_test_utils",
+ "//testing/gtest",
+ ]
+ }
+
+ rtc_executable("rtp_analyze") {
+ testonly = true
+
+ sources = [ "neteq/tools/rtp_analyze.cc" ]
+
+ deps = [
+ ":neteq",
+ ":neteq_test_tools",
+ ":pcm16b",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ ]
+ }
+
+ rtc_executable("neteq_opus_quality_test") {
+ testonly = true
+
+ sources = [ "neteq/test/neteq_opus_quality_test.cc" ]
+
+ deps = [
+ ":neteq",
+ ":neteq_quality_test_support",
+ ":neteq_tools",
+ ":webrtc_opus",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:test_main",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ ]
+ }
+
+ rtc_executable("neteq_speed_test") {
+ testonly = true
+
+ sources = [ "neteq/test/neteq_speed_test.cc" ]
+
+ deps = [
+ ":neteq",
+ ":neteq_test_support",
+ "../../rtc_base:checks",
+ "../../test:test_support",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ ]
+ }
+
+ rtc_executable("neteq_ilbc_quality_test") {
+ testonly = true
+
+ sources = [ "neteq/test/neteq_ilbc_quality_test.cc" ]
+
+ deps = [
+ ":ilbc",
+ ":neteq",
+ ":neteq_quality_test_support",
+ ":neteq_tools",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:fileutils",
+ "../../test:test_main",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ ]
+ }
+
+ rtc_executable("neteq_isac_quality_test") {
+ testonly = true
+
+ sources = [ "neteq/test/neteq_isac_quality_test.cc" ]
+
+ deps = [
+ ":isac_fix",
+ ":neteq",
+ ":neteq_quality_test_support",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:test_main",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ ]
+ }
+
+ rtc_executable("neteq_pcmu_quality_test") {
+ testonly = true
+
+ sources = [ "neteq/test/neteq_pcmu_quality_test.cc" ]
+
+ deps = [
+ ":g711",
+ ":neteq",
+ ":neteq_quality_test_support",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:fileutils",
+ "../../test:test_main",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ ]
+ }
+
+ rtc_executable("neteq_pcm16b_quality_test") {
+ testonly = true
+
+ sources = [ "neteq/test/neteq_pcm16b_quality_test.cc" ]
+
+ deps = [
+ ":neteq",
+ ":neteq_quality_test_support",
+ ":pcm16b",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:fileutils",
+ "../../test:test_main",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ ]
+ }
+
+ rtc_executable("isac_fix_test") {
+ testonly = true
+
+ sources = [ "codecs/isac/fix/test/kenny.cc" ]
+
+ deps = [
+ ":isac_fix",
+ "../../test:perf_test",
+ "../../test:test_support",
+ ]
+
+ data = [ "../../resources/speech_and_misc_wb.pcm" ]
+ }
+
+ rtc_library("isac_test_util") {
+ testonly = true
+ sources = [
+ "codecs/isac/main/util/utility.c",
+ "codecs/isac/main/util/utility.h",
+ ]
+ }
+
+ rtc_executable("isac_test") {
+ testonly = true
+
+ sources = [ "codecs/isac/main/test/simpleKenny.c" ]
+
+ deps = [
+ ":isac",
+ ":isac_test_util",
+ "../../rtc_base:rtc_base_approved",
+ ]
+ }
+
+ rtc_executable("g711_test") {
+ testonly = true
+
+ sources = [ "codecs/g711/test/testG711.cc" ]
+
+ deps = [ ":g711" ]
+ }
+
+ rtc_executable("g722_test") {
+ testonly = true
+
+ sources = [ "codecs/g722/test/testG722.cc" ]
+
+ deps = [ ":g722" ]
+ }
+
+ rtc_executable("isac_api_test") {
+ testonly = true
+
+ sources = [ "codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc" ]
+
+ deps = [
+ ":isac",
+ ":isac_test_util",
+ "../../rtc_base:rtc_base_approved",
+ ]
+ }
+
+ rtc_executable("isac_switch_samprate_test") {
+ testonly = true
+
+ sources = [ "codecs/isac/main/test/SwitchingSampRate/SwitchingSampRate.cc" ]
+
+ deps = [
+ ":isac",
+ ":isac_test_util",
+ "../../common_audio",
+ "../../common_audio:common_audio_c",
+ ]
+ }
+
+ rtc_executable("ilbc_test") {
+ testonly = true
+
+ sources = [ "codecs/ilbc/test/iLBC_test.c" ]
+
+ deps = [ ":ilbc" ]
+ }
+
+ rtc_executable("webrtc_opus_fec_test") {
+ testonly = true
+
+ sources = [ "codecs/opus/opus_fec_test.cc" ]
+
+ deps = [
+ ":webrtc_opus",
+ "../../common_audio",
+ "../../rtc_base:rtc_base_approved",
+ "../../test:fileutils",
+ "../../test:test_main",
+ "../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+
+ rtc_library("audio_coding_unittests") {
+ testonly = true
+ visibility += webrtc_default_visibility
+
+ sources = [
+ "acm2/acm_receiver_unittest.cc",
+ "acm2/acm_remixing_unittest.cc",
+ "acm2/audio_coding_module_unittest.cc",
+ "acm2/call_statistics_unittest.cc",
+ "audio_network_adaptor/audio_network_adaptor_impl_unittest.cc",
+ "audio_network_adaptor/bitrate_controller_unittest.cc",
+ "audio_network_adaptor/channel_controller_unittest.cc",
+ "audio_network_adaptor/controller_manager_unittest.cc",
+ "audio_network_adaptor/dtx_controller_unittest.cc",
+ "audio_network_adaptor/event_log_writer_unittest.cc",
+ "audio_network_adaptor/fec_controller_plr_based_unittest.cc",
+ "audio_network_adaptor/frame_length_controller_unittest.cc",
+ "audio_network_adaptor/frame_length_controller_v2_unittest.cc",
+ "audio_network_adaptor/util/threshold_curve_unittest.cc",
+ "codecs/builtin_audio_decoder_factory_unittest.cc",
+ "codecs/builtin_audio_encoder_factory_unittest.cc",
+ "codecs/cng/audio_encoder_cng_unittest.cc",
+ "codecs/cng/cng_unittest.cc",
+ "codecs/ilbc/ilbc_unittest.cc",
+ "codecs/isac/fix/source/filterbanks_unittest.cc",
+ "codecs/isac/fix/source/filters_unittest.cc",
+ "codecs/isac/fix/source/lpc_masking_model_unittest.cc",
+ "codecs/isac/fix/source/transform_unittest.cc",
+ "codecs/isac/isac_webrtc_api_test.cc",
+ "codecs/isac/main/source/audio_encoder_isac_unittest.cc",
+ "codecs/isac/main/source/isac_unittest.cc",
+ "codecs/legacy_encoded_audio_frame_unittest.cc",
+ "codecs/opus/audio_decoder_multi_channel_opus_unittest.cc",
+ "codecs/opus/audio_encoder_multi_channel_opus_unittest.cc",
+ "codecs/opus/audio_encoder_opus_unittest.cc",
+ "codecs/opus/opus_bandwidth_unittest.cc",
+ "codecs/opus/opus_unittest.cc",
+ "codecs/red/audio_encoder_copy_red_unittest.cc",
+ "neteq/audio_multi_vector_unittest.cc",
+ "neteq/audio_vector_unittest.cc",
+ "neteq/background_noise_unittest.cc",
+ "neteq/buffer_level_filter_unittest.cc",
+ "neteq/comfort_noise_unittest.cc",
+ "neteq/decision_logic_unittest.cc",
+ "neteq/decoder_database_unittest.cc",
+ "neteq/delay_manager_unittest.cc",
+ "neteq/dsp_helper_unittest.cc",
+ "neteq/dtmf_buffer_unittest.cc",
+ "neteq/dtmf_tone_generator_unittest.cc",
+ "neteq/expand_unittest.cc",
+ "neteq/histogram_unittest.cc",
+ "neteq/merge_unittest.cc",
+ "neteq/mock/mock_decoder_database.h",
+ "neteq/mock/mock_dtmf_buffer.h",
+ "neteq/mock/mock_dtmf_tone_generator.h",
+ "neteq/mock/mock_expand.h",
+ "neteq/mock/mock_histogram.h",
+ "neteq/mock/mock_neteq_controller.h",
+ "neteq/mock/mock_packet_buffer.h",
+ "neteq/mock/mock_red_payload_splitter.h",
+ "neteq/mock/mock_statistics_calculator.h",
+ "neteq/nack_tracker_unittest.cc",
+ "neteq/neteq_decoder_plc_unittest.cc",
+ "neteq/neteq_impl_unittest.cc",
+ "neteq/neteq_network_stats_unittest.cc",
+ "neteq/neteq_stereo_unittest.cc",
+ "neteq/neteq_unittest.cc",
+ "neteq/normal_unittest.cc",
+ "neteq/packet_buffer_unittest.cc",
+ "neteq/post_decode_vad_unittest.cc",
+ "neteq/random_vector_unittest.cc",
+ "neteq/red_payload_splitter_unittest.cc",
+ "neteq/statistics_calculator_unittest.cc",
+ "neteq/sync_buffer_unittest.cc",
+ "neteq/time_stretch_unittest.cc",
+ "neteq/timestamp_scaler_unittest.cc",
+ "neteq/tools/input_audio_file_unittest.cc",
+ "neteq/tools/packet_unittest.cc",
+ ]
+
+ deps = [
+ ":acm_receive_test",
+ ":acm_send_test",
+ ":audio_coding",
+ ":audio_coding_module_typedefs",
+ ":audio_coding_modules_tests_shared",
+ ":audio_coding_opus_common",
+ ":audio_encoder_cng",
+ ":audio_network_adaptor",
+ ":default_neteq_factory",
+ ":g711",
+ ":ilbc",
+ ":isac",
+ ":isac_c",
+ ":isac_common",
+ ":isac_fix",
+ ":legacy_encoded_audio_frame",
+ ":mocks",
+ ":neteq",
+ ":neteq_test_support",
+ ":neteq_test_tools",
+ ":pcm16b",
+ ":red",
+ ":webrtc_cng",
+ ":webrtc_opus",
+ "..:module_api",
+ "..:module_api_public",
+ "../../api:array_view",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio_codecs:audio_codecs_api",
+ "../../api/audio_codecs:builtin_audio_decoder_factory",
+ "../../api/audio_codecs:builtin_audio_encoder_factory",
+ "../../api/audio_codecs/isac:audio_decoder_isac_fix",
+ "../../api/audio_codecs/isac:audio_decoder_isac_float",
+ "../../api/audio_codecs/isac:audio_encoder_isac_fix",
+ "../../api/audio_codecs/isac:audio_encoder_isac_float",
+ "../../api/audio_codecs/opus:audio_decoder_multiopus",
+ "../../api/audio_codecs/opus:audio_decoder_opus",
+ "../../api/audio_codecs/opus:audio_encoder_multiopus",
+ "../../api/audio_codecs/opus:audio_encoder_opus",
+ "../../api/neteq:default_neteq_controller_factory",
+ "../../api/neteq:neteq_api",
+ "../../api/neteq:neteq_controller_api",
+ "../../api/neteq:tick_timer",
+ "../../api/neteq:tick_timer_unittest",
+ "../../api/rtc_event_log",
+ "../../common_audio",
+ "../../common_audio:common_audio_c",
+ "../../common_audio:mock_common_audio",
+ "../../logging:mocks",
+ "../../logging:rtc_event_audio",
+ "../../modules/rtp_rtcp:rtp_rtcp_format",
+ "../../rtc_base",
+ "../../rtc_base:checks",
+ "../../rtc_base:ignore_wundef",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:rtc_base_tests_utils",
+ "../../rtc_base:sanitizer",
+ "../../rtc_base:timeutils",
+ "../../rtc_base/synchronization:mutex",
+ "../../rtc_base/system:arch",
+ "../../system_wrappers",
+ "../../test:audio_codec_mocks",
+ "../../test:field_trial",
+ "../../test:fileutils",
+ "../../test:rtc_expect_death",
+ "../../test:rtp_test_utils",
+ "../../test:test_common",
+ "../../test:test_support",
+ "codecs/opus/test",
+ "codecs/opus/test:test_unittest",
+ "//testing/gtest",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+
+ defines = audio_coding_defines
+
+ if (rtc_enable_protobuf) {
+ defines += [ "WEBRTC_NETEQ_UNITTEST_BITEXACT" ]
+ deps += [
+ ":ana_config_proto",
+ ":neteq_unittest_proto",
+ ]
+ }
+ }
+}
+
+# For backwards compatibility only! Use
+# webrtc/api/audio_codecs:audio_codecs_api instead.
+# TODO(kwiberg): Remove this.
+rtc_source_set("audio_decoder_interface") {
+ visibility += [ "*" ]
+ sources = [ "codecs/audio_decoder.h" ]
+ deps = [ "../../api/audio_codecs:audio_codecs_api" ]
+}
+
+# For backwards compatibility only! Use
+# webrtc/api/audio_codecs:audio_codecs_api instead.
+# TODO(ossu): Remove this.
+rtc_source_set("audio_encoder_interface") {
+ visibility += [ "*" ]
+ sources = [ "codecs/audio_encoder.h" ]
+ deps = [ "../../api/audio_codecs:audio_codecs_api" ]
}
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.cc b/webrtc/modules/audio_coding/codecs/audio_decoder.cc
deleted file mode 100644
index 08d101c..0000000
--- a/webrtc/modules/audio_coding/codecs/audio_decoder.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
-
-#include <assert.h>
-
-#include "webrtc/base/checks.h"
-
-namespace webrtc {
-
-int AudioDecoder::Decode(const uint8_t* encoded, size_t encoded_len,
- int sample_rate_hz, size_t max_decoded_bytes,
- int16_t* decoded, SpeechType* speech_type) {
- int duration = PacketDuration(encoded, encoded_len);
- if (duration >= 0 &&
- duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
- return -1;
- }
- return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
- speech_type);
-}
-
-int AudioDecoder::DecodeRedundant(const uint8_t* encoded, size_t encoded_len,
- int sample_rate_hz, size_t max_decoded_bytes,
- int16_t* decoded, SpeechType* speech_type) {
- int duration = PacketDurationRedundant(encoded, encoded_len);
- if (duration >= 0 &&
- duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
- return -1;
- }
- return DecodeRedundantInternal(encoded, encoded_len, sample_rate_hz, decoded,
- speech_type);
-}
-
-int AudioDecoder::DecodeInternal(const uint8_t* encoded, size_t encoded_len,
- int sample_rate_hz, int16_t* decoded,
- SpeechType* speech_type) {
- return kNotImplemented;
-}
-
-int AudioDecoder::DecodeRedundantInternal(const uint8_t* encoded,
- size_t encoded_len,
- int sample_rate_hz, int16_t* decoded,
- SpeechType* speech_type) {
- return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
- speech_type);
-}
-
-bool AudioDecoder::HasDecodePlc() const { return false; }
-
-size_t AudioDecoder::DecodePlc(size_t num_frames, int16_t* decoded) {
- return 0;
-}
-
-int AudioDecoder::IncomingPacket(const uint8_t* payload,
- size_t payload_len,
- uint16_t rtp_sequence_number,
- uint32_t rtp_timestamp,
- uint32_t arrival_timestamp) {
- return 0;
-}
-
-int AudioDecoder::ErrorCode() { return 0; }
-
-int AudioDecoder::PacketDuration(const uint8_t* encoded,
- size_t encoded_len) const {
- return kNotImplemented;
-}
-
-int AudioDecoder::PacketDurationRedundant(const uint8_t* encoded,
- size_t encoded_len) const {
- return kNotImplemented;
-}
-
-bool AudioDecoder::PacketHasFec(const uint8_t* encoded,
- size_t encoded_len) const {
- return false;
-}
-
-CNG_dec_inst* AudioDecoder::CngDecoderInstance() {
- FATAL() << "Not a CNG decoder";
- return NULL;
-}
-
-AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) {
- switch (type) {
- case 0: // TODO(hlundin): Both iSAC and Opus return 0 for speech.
- case 1:
- return kSpeech;
- case 2:
- return kComfortNoise;
- default:
- assert(false);
- return kSpeech;
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.h b/webrtc/modules/audio_coding/codecs/audio_decoder.h
index 6189be0..b7b15cd 100644
--- a/webrtc/modules/audio_coding/codecs/audio_decoder.h
+++ b/webrtc/modules/audio_coding/codecs/audio_decoder.h
@@ -8,116 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_NETEQ_INCLUDE_AUDIO_DECODER_H_
-#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_INCLUDE_AUDIO_DECODER_H_
+// This file is for backwards compatibility only! Use
+// webrtc/api/audio_codecs/audio_decoder.h instead!
+// TODO(kwiberg): Remove it.
-#include <stdlib.h> // NULL
+#ifndef MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_
+#define MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h"
-#include "webrtc/typedefs.h"
+#include "api/audio_codecs/audio_decoder.h"
-namespace webrtc {
-
-// This is the interface class for decoders in NetEQ. Each codec type will have
-// and implementation of this class.
-class AudioDecoder {
- public:
- enum SpeechType {
- kSpeech = 1,
- kComfortNoise = 2
- };
-
- // Used by PacketDuration below. Save the value -1 for errors.
- enum { kNotImplemented = -2 };
-
- AudioDecoder() = default;
- virtual ~AudioDecoder() = default;
-
- // Decodes |encode_len| bytes from |encoded| and writes the result in
- // |decoded|. The maximum bytes allowed to be written into |decoded| is
- // |max_decoded_bytes|. Returns the total number of samples across all
- // channels. If the decoder produced comfort noise, |speech_type|
- // is set to kComfortNoise, otherwise it is kSpeech. The desired output
- // sample rate is provided in |sample_rate_hz|, which must be valid for the
- // codec at hand.
- virtual int Decode(const uint8_t* encoded,
- size_t encoded_len,
- int sample_rate_hz,
- size_t max_decoded_bytes,
- int16_t* decoded,
- SpeechType* speech_type);
-
- // Same as Decode(), but interfaces to the decoders redundant decode function.
- // The default implementation simply calls the regular Decode() method.
- virtual int DecodeRedundant(const uint8_t* encoded,
- size_t encoded_len,
- int sample_rate_hz,
- size_t max_decoded_bytes,
- int16_t* decoded,
- SpeechType* speech_type);
-
- // Indicates if the decoder implements the DecodePlc method.
- virtual bool HasDecodePlc() const;
-
- // Calls the packet-loss concealment of the decoder to update the state after
- // one or several lost packets. The caller has to make sure that the
- // memory allocated in |decoded| should accommodate |num_frames| frames.
- virtual size_t DecodePlc(size_t num_frames, int16_t* decoded);
-
- // Resets the decoder state (empty buffers etc.).
- virtual void Reset() = 0;
-
- // Notifies the decoder of an incoming packet to NetEQ.
- virtual int IncomingPacket(const uint8_t* payload,
- size_t payload_len,
- uint16_t rtp_sequence_number,
- uint32_t rtp_timestamp,
- uint32_t arrival_timestamp);
-
- // Returns the last error code from the decoder.
- virtual int ErrorCode();
-
- // Returns the duration in samples-per-channel of the payload in |encoded|
- // which is |encoded_len| bytes long. Returns kNotImplemented if no duration
- // estimate is available, or -1 in case of an error.
- virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
-
- // Returns the duration in samples-per-channel of the redandant payload in
- // |encoded| which is |encoded_len| bytes long. Returns kNotImplemented if no
- // duration estimate is available, or -1 in case of an error.
- virtual int PacketDurationRedundant(const uint8_t* encoded,
- size_t encoded_len) const;
-
- // Detects whether a packet has forward error correction. The packet is
- // comprised of the samples in |encoded| which is |encoded_len| bytes long.
- // Returns true if the packet has FEC and false otherwise.
- virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
-
- // If this is a CNG decoder, return the underlying CNG_dec_inst*. If this
- // isn't a CNG decoder, don't call this method.
- virtual CNG_dec_inst* CngDecoderInstance();
-
- virtual size_t Channels() const = 0;
-
- protected:
- static SpeechType ConvertSpeechType(int16_t type);
-
- virtual int DecodeInternal(const uint8_t* encoded,
- size_t encoded_len,
- int sample_rate_hz,
- int16_t* decoded,
- SpeechType* speech_type);
-
- virtual int DecodeRedundantInternal(const uint8_t* encoded,
- size_t encoded_len,
- int sample_rate_hz,
- int16_t* decoded,
- SpeechType* speech_type);
-
- private:
- RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoder);
-};
-
-} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_INCLUDE_AUDIO_DECODER_H_
+#endif // MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.cc b/webrtc/modules/audio_coding/codecs/audio_encoder.cc
deleted file mode 100644
index 6d76300..0000000
--- a/webrtc/modules/audio_coding/codecs/audio_encoder.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
-#include "webrtc/base/checks.h"
-
-namespace webrtc {
-
-AudioEncoder::EncodedInfo::EncodedInfo() = default;
-
-AudioEncoder::EncodedInfo::~EncodedInfo() = default;
-
-int AudioEncoder::RtpTimestampRateHz() const {
- return SampleRateHz();
-}
-
-AudioEncoder::EncodedInfo AudioEncoder::Encode(uint32_t rtp_timestamp,
- const int16_t* audio,
- size_t num_samples_per_channel,
- size_t max_encoded_bytes,
- uint8_t* encoded) {
- RTC_CHECK_EQ(num_samples_per_channel,
- static_cast<size_t>(SampleRateHz() / 100));
- EncodedInfo info =
- EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, encoded);
- RTC_CHECK_LE(info.encoded_bytes, max_encoded_bytes);
- return info;
-}
-
-bool AudioEncoder::SetFec(bool enable) {
- return !enable;
-}
-
-bool AudioEncoder::SetDtx(bool enable) {
- return !enable;
-}
-
-bool AudioEncoder::SetApplication(Application application) {
- return false;
-}
-
-void AudioEncoder::SetMaxPlaybackRate(int frequency_hz) {}
-
-void AudioEncoder::SetProjectedPacketLossRate(double fraction) {}
-
-void AudioEncoder::SetTargetBitrate(int target_bps) {}
-
-} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.h b/webrtc/modules/audio_coding/codecs/audio_encoder.h
index cda9d86..010ae67 100644
--- a/webrtc/modules/audio_coding/codecs/audio_encoder.h
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ * 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
@@ -8,136 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
+// This file is for backwards compatibility only! Use
+// webrtc/api/audio_codecs/audio_encoder.h instead!
+// TODO(ossu): Remove it.
-#include <algorithm>
-#include <vector>
+#ifndef MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
+#define MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
-#include "webrtc/typedefs.h"
+#include "api/audio_codecs/audio_encoder.h"
-namespace webrtc {
-
-// This is the interface class for encoders in AudioCoding module. Each codec
-// type must have an implementation of this class.
-class AudioEncoder {
- public:
- struct EncodedInfoLeaf {
- size_t encoded_bytes = 0;
- uint32_t encoded_timestamp = 0;
- int payload_type = 0;
- bool send_even_if_empty = false;
- bool speech = true;
- };
-
- // This is the main struct for auxiliary encoding information. Each encoded
- // packet should be accompanied by one EncodedInfo struct, containing the
- // total number of |encoded_bytes|, the |encoded_timestamp| and the
- // |payload_type|. If the packet contains redundant encodings, the |redundant|
- // vector will be populated with EncodedInfoLeaf structs. Each struct in the
- // vector represents one encoding; the order of structs in the vector is the
- // same as the order in which the actual payloads are written to the byte
- // stream. When EncoderInfoLeaf structs are present in the vector, the main
- // struct's |encoded_bytes| will be the sum of all the |encoded_bytes| in the
- // vector.
- struct EncodedInfo : public EncodedInfoLeaf {
- EncodedInfo();
- ~EncodedInfo();
-
- std::vector<EncodedInfoLeaf> redundant;
- };
-
- virtual ~AudioEncoder() = default;
-
- // Returns the maximum number of bytes that can be produced by the encoder
- // at each Encode() call. The caller can use the return value to determine
- // the size of the buffer that needs to be allocated. This value is allowed
- // to depend on encoder parameters like bitrate, frame size etc., so if
- // any of these change, the caller of Encode() is responsible for checking
- // that the buffer is large enough by calling MaxEncodedBytes() again.
- virtual size_t MaxEncodedBytes() const = 0;
-
- // Returns the input sample rate in Hz and the number of input channels.
- // These are constants set at instantiation time.
- virtual int SampleRateHz() const = 0;
- virtual int NumChannels() const = 0;
-
- // Returns the rate at which the RTP timestamps are updated. The default
- // implementation returns SampleRateHz().
- virtual int RtpTimestampRateHz() const;
-
- // Returns the number of 10 ms frames the encoder will put in the next
- // packet. This value may only change when Encode() outputs a packet; i.e.,
- // the encoder may vary the number of 10 ms frames from packet to packet, but
- // it must decide the length of the next packet no later than when outputting
- // the preceding packet.
- virtual size_t Num10MsFramesInNextPacket() const = 0;
-
- // Returns the maximum value that can be returned by
- // Num10MsFramesInNextPacket().
- virtual size_t Max10MsFramesInAPacket() const = 0;
-
- // Returns the current target bitrate in bits/s. The value -1 means that the
- // codec adapts the target automatically, and a current target cannot be
- // provided.
- virtual int GetTargetBitrate() const = 0;
-
- // Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 *
- // NumChannels() samples). Multi-channel audio must be sample-interleaved.
- // The encoder produces zero or more bytes of output in |encoded| and
- // returns additional encoding information.
- // The caller is responsible for making sure that |max_encoded_bytes| is
- // not smaller than the number of bytes actually produced by the encoder.
- // Encode() checks some preconditions, calls EncodeInternal() which does the
- // actual work, and then checks some postconditions.
- EncodedInfo Encode(uint32_t rtp_timestamp,
- const int16_t* audio,
- size_t num_samples_per_channel,
- size_t max_encoded_bytes,
- uint8_t* encoded);
-
- virtual EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
- const int16_t* audio,
- size_t max_encoded_bytes,
- uint8_t* encoded) = 0;
-
- // Resets the encoder to its starting state, discarding any input that has
- // been fed to the encoder but not yet emitted in a packet.
- virtual void Reset() = 0;
-
- // Enables or disables codec-internal FEC (forward error correction). Returns
- // true if the codec was able to comply. The default implementation returns
- // true when asked to disable FEC and false when asked to enable it (meaning
- // that FEC isn't supported).
- virtual bool SetFec(bool enable);
-
- // Enables or disables codec-internal VAD/DTX. Returns true if the codec was
- // able to comply. The default implementation returns true when asked to
- // disable DTX and false when asked to enable it (meaning that DTX isn't
- // supported).
- virtual bool SetDtx(bool enable);
-
- // Sets the application mode. Returns true if the codec was able to comply.
- // The default implementation just returns false.
- enum class Application { kSpeech, kAudio };
- virtual bool SetApplication(Application application);
-
- // Tells the encoder about the highest sample rate the decoder is expected to
- // use when decoding the bitstream. The encoder would typically use this
- // information to adjust the quality of the encoding. The default
- // implementation just returns true.
- virtual void SetMaxPlaybackRate(int frequency_hz);
-
- // Tells the encoder what the projected packet loss rate is. The rate is in
- // the range [0.0, 1.0]. The encoder would typically use this information to
- // adjust channel coding efforts, such as FEC. The default implementation
- // does nothing.
- virtual void SetProjectedPacketLossRate(double fraction);
-
- // Tells the encoder what average bitrate we'd like it to produce. The
- // encoder is free to adjust or disregard the given bitrate (the default
- // implementation does the latter).
- virtual void SetTargetBitrate(int target_bps);
-};
-} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
+#endif // MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
diff --git a/webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h b/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h
index 35660c4..35660c4 100644
--- a/webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h
+++ b/webrtc/modules/audio_coding/codecs/cng/webrtc_cng.h
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
index 845af42..23a3020 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h
@@ -8,32 +8,33 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
#include <vector>
-#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
-#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
+#include "absl/types/optional.h"
+#include "api/audio_codecs/audio_decoder.h"
+#include "api/scoped_refptr.h"
+#include "rtc_base/constructor_magic.h"
namespace webrtc {
template <typename T>
class AudioDecoderIsacT final : public AudioDecoder {
public:
- AudioDecoderIsacT();
- explicit AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo);
- ~AudioDecoderIsacT() override;
+ struct Config {
+ bool IsOk() const;
+ int sample_rate_hz = 16000;
+ };
+ explicit AudioDecoderIsacT(const Config& config);
+ virtual ~AudioDecoderIsacT() override;
bool HasDecodePlc() const override;
size_t DecodePlc(size_t num_frames, int16_t* decoded) override;
void Reset() override;
- int IncomingPacket(const uint8_t* payload,
- size_t payload_len,
- uint16_t rtp_sequence_number,
- uint32_t rtp_timestamp,
- uint32_t arrival_timestamp) override;
int ErrorCode() override;
+ int SampleRateHz() const override;
size_t Channels() const override;
int DecodeInternal(const uint8_t* encoded,
size_t encoded_len,
@@ -43,12 +44,11 @@ class AudioDecoderIsacT final : public AudioDecoder {
private:
typename T::instance_type* isac_state_;
- LockedIsacBandwidthInfo* bwinfo_;
- int decoder_sample_rate_hz_;
+ int sample_rate_hz_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacT);
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h
index a986bc4..2e43fd3 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h
@@ -8,29 +8,26 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
-#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h"
-
-#include "webrtc/base/checks.h"
+#include "rtc_base/checks.h"
namespace webrtc {
template <typename T>
-AudioDecoderIsacT<T>::AudioDecoderIsacT()
- : AudioDecoderIsacT(nullptr) {}
+bool AudioDecoderIsacT<T>::Config::IsOk() const {
+ return (sample_rate_hz == 16000 || sample_rate_hz == 32000);
+}
template <typename T>
-AudioDecoderIsacT<T>::AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo)
- : bwinfo_(bwinfo), decoder_sample_rate_hz_(-1) {
+AudioDecoderIsacT<T>::AudioDecoderIsacT(const Config& config)
+ : sample_rate_hz_(config.sample_rate_hz) {
+ RTC_CHECK(config.IsOk()) << "Unsupported sample rate "
+ << config.sample_rate_hz;
RTC_CHECK_EQ(0, T::Create(&isac_state_));
T::DecoderInit(isac_state_);
- if (bwinfo_) {
- IsacBandwidthInfo bi;
- T::GetBandwidthInfo(isac_state_, &bi);
- bwinfo_->Set(bi);
- }
+ RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, sample_rate_hz_));
}
template <typename T>
@@ -44,12 +41,7 @@ int AudioDecoderIsacT<T>::DecodeInternal(const uint8_t* encoded,
int sample_rate_hz,
int16_t* decoded,
SpeechType* speech_type) {
- RTC_CHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000)
- << "Unsupported sample rate " << sample_rate_hz;
- if (sample_rate_hz != decoder_sample_rate_hz_) {
- RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, sample_rate_hz));
- decoder_sample_rate_hz_ = sample_rate_hz;
- }
+ RTC_CHECK_EQ(sample_rate_hz_, sample_rate_hz);
int16_t temp_type = 1; // Default is speech.
int ret =
T::DecodeInternal(isac_state_, encoded, encoded_len, decoded, &temp_type);
@@ -73,25 +65,13 @@ void AudioDecoderIsacT<T>::Reset() {
}
template <typename T>
-int AudioDecoderIsacT<T>::IncomingPacket(const uint8_t* payload,
- size_t payload_len,
- uint16_t rtp_sequence_number,
- uint32_t rtp_timestamp,
- uint32_t arrival_timestamp) {
- int ret = T::UpdateBwEstimate(isac_state_, payload, payload_len,
- rtp_sequence_number, rtp_timestamp,
- arrival_timestamp);
- if (bwinfo_) {
- IsacBandwidthInfo bwinfo;
- T::GetBandwidthInfo(isac_state_, &bwinfo);
- bwinfo_->Set(bwinfo);
- }
- return ret;
+int AudioDecoderIsacT<T>::ErrorCode() {
+ return T::GetErrorCode(isac_state_);
}
template <typename T>
-int AudioDecoderIsacT<T>::ErrorCode() {
- return T::GetErrorCode(isac_state_);
+int AudioDecoderIsacT<T>::SampleRateHz() const {
+ return sample_rate_hz_;
}
template <typename T>
@@ -101,4 +81,4 @@ size_t AudioDecoderIsacT<T>::Channels() const {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
index b15ad94..d99e9c8 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -8,18 +8,21 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
+#include <utility>
#include <vector>
-#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
-#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
+#include "absl/types/optional.h"
+#include "api/audio_codecs/audio_encoder.h"
+#include "api/scoped_refptr.h"
+#include "api/units/time_delta.h"
+#include "rtc_base/constructor_magic.h"
+#include "system_wrappers/include/field_trial.h"
namespace webrtc {
-struct CodecInst;
-
template <typename T>
class AudioEncoderIsacT final : public AudioEncoder {
public:
@@ -29,9 +32,6 @@ class AudioEncoderIsacT final : public AudioEncoder {
// - 32000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support)
struct Config {
bool IsOk() const;
-
- LockedIsacBandwidthInfo* bwinfo = nullptr;
-
int payload_type = 103;
int sample_rate_hz = 16000;
int frame_size_ms = 30;
@@ -39,46 +39,48 @@ class AudioEncoderIsacT final : public AudioEncoder {
// rate, in bits/s.
int max_payload_size_bytes = -1;
int max_bit_rate = -1;
-
- // If true, the encoder will dynamically adjust frame size and bit rate;
- // the configured values are then merely the starting point.
- bool adaptive_mode = false;
-
- // In adaptive mode, prevent adaptive changes to the frame size. (Not used
- // in nonadaptive mode.)
- bool enforce_frame_size = false;
};
explicit AudioEncoderIsacT(const Config& config);
- explicit AudioEncoderIsacT(const CodecInst& codec_inst,
- LockedIsacBandwidthInfo* bwinfo);
~AudioEncoderIsacT() override;
- size_t MaxEncodedBytes() const override;
int SampleRateHz() const override;
- int NumChannels() const override;
+ size_t NumChannels() const override;
size_t Num10MsFramesInNextPacket() const override;
size_t Max10MsFramesInAPacket() const override;
int GetTargetBitrate() const override;
- EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
- const int16_t* audio,
- size_t max_encoded_bytes,
- uint8_t* encoded) override;
+ void SetTargetBitrate(int target_bps) override;
+ void OnReceivedTargetAudioBitrate(int target_bps) override;
+ void OnReceivedUplinkBandwidth(
+ int target_audio_bitrate_bps,
+ absl::optional<int64_t> bwe_period_ms) override;
+ void OnReceivedUplinkAllocation(BitrateAllocationUpdate update) override;
+ void OnReceivedOverhead(size_t overhead_bytes_per_packet) override;
+ EncodedInfo EncodeImpl(uint32_t rtp_timestamp,
+ rtc::ArrayView<const int16_t> audio,
+ rtc::Buffer* encoded) override;
void Reset() override;
+ absl::optional<std::pair<TimeDelta, TimeDelta>> GetFrameLengthRange()
+ const override;
private:
// This value is taken from STREAM_SIZE_MAX_60 for iSAC float (60 ms) and
// STREAM_MAXW16_60MS for iSAC fix (60 ms).
static const size_t kSufficientEncodeBufferSizeBytes = 400;
- static const int kDefaultBitRate = 32000;
+ static constexpr int kDefaultBitRate = 32000;
+ static constexpr int kMinBitrateBps = 10000;
+ static constexpr int MaxBitrateBps(int sample_rate_hz) {
+ return sample_rate_hz == 32000 ? 56000 : 32000;
+ }
+
+ void SetTargetBitrate(int target_bps, bool subtract_per_packet_overhead);
// Recreate the iSAC encoder instance with the given settings, and save them.
void RecreateEncoderInstance(const Config& config);
Config config_;
typename T::instance_type* isac_state_ = nullptr;
- LockedIsacBandwidthInfo* bwinfo_ = nullptr;
// Have we accepted input but not yet emitted it in a packet?
bool packet_in_progress_ = false;
@@ -89,9 +91,18 @@ class AudioEncoderIsacT final : public AudioEncoder {
// Timestamp of the previously encoded packet.
uint32_t last_encoded_timestamp_;
+ // Cache the value of the "WebRTC-SendSideBwe-WithOverhead" field trial.
+ const bool send_side_bwe_with_overhead_ =
+ field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead");
+
+ // When we send a packet, expect this many bytes of headers to be added to it.
+ // Start out with a reasonable default that we can use until we receive a real
+ // value.
+ DataSize overhead_per_packet_ = DataSize::Bytes(28);
+
RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT);
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
index 279f80d..0bde3f7 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
@@ -8,39 +8,21 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
-#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
-
-#include "webrtc/base/checks.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
namespace webrtc {
template <typename T>
-typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
- const CodecInst& codec_inst,
- LockedIsacBandwidthInfo* bwinfo) {
- typename AudioEncoderIsacT<T>::Config config;
- config.bwinfo = bwinfo;
- config.payload_type = codec_inst.pltype;
- config.sample_rate_hz = codec_inst.plfreq;
- config.frame_size_ms =
- rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz);
- config.adaptive_mode = (codec_inst.rate == -1);
- if (codec_inst.rate != -1)
- config.bit_rate = codec_inst.rate;
- return config;
-}
-
-template <typename T>
bool AudioEncoderIsacT<T>::Config::IsOk() const {
if (max_bit_rate < 32000 && max_bit_rate != -1)
return false;
if (max_payload_size_bytes < 120 && max_payload_size_bytes != -1)
return false;
- if (adaptive_mode && !bwinfo)
- return false;
+
switch (sample_rate_hz) {
case 16000:
if (max_bit_rate > 53400)
@@ -68,36 +50,25 @@ AudioEncoderIsacT<T>::AudioEncoderIsacT(const Config& config) {
}
template <typename T>
-AudioEncoderIsacT<T>::AudioEncoderIsacT(const CodecInst& codec_inst,
- LockedIsacBandwidthInfo* bwinfo)
- : AudioEncoderIsacT(CreateIsacConfig<T>(codec_inst, bwinfo)) {}
-
-template <typename T>
AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
RTC_CHECK_EQ(0, T::Free(isac_state_));
}
template <typename T>
-size_t AudioEncoderIsacT<T>::MaxEncodedBytes() const {
- return kSufficientEncodeBufferSizeBytes;
-}
-
-template <typename T>
int AudioEncoderIsacT<T>::SampleRateHz() const {
return T::EncSampRate(isac_state_);
}
template <typename T>
-int AudioEncoderIsacT<T>::NumChannels() const {
+size_t AudioEncoderIsacT<T>::NumChannels() const {
return 1;
}
template <typename T>
size_t AudioEncoderIsacT<T>::Num10MsFramesInNextPacket() const {
const int samples_in_next_packet = T::GetNewFrameLen(isac_state_);
- return static_cast<size_t>(
- rtc::CheckedDivExact(samples_in_next_packet,
- rtc::CheckedDivExact(SampleRateHz(), 100)));
+ return static_cast<size_t>(rtc::CheckedDivExact(
+ samples_in_next_packet, rtc::CheckedDivExact(SampleRateHz(), 100)));
}
template <typename T>
@@ -107,44 +78,85 @@ size_t AudioEncoderIsacT<T>::Max10MsFramesInAPacket() const {
template <typename T>
int AudioEncoderIsacT<T>::GetTargetBitrate() const {
- if (config_.adaptive_mode)
- return -1;
return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate;
}
template <typename T>
-AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::EncodeInternal(
+void AudioEncoderIsacT<T>::SetTargetBitrate(int target_bps) {
+ // Set target bitrate directly without subtracting per-packet overhead,
+ // because that's what AudioEncoderOpus does.
+ SetTargetBitrate(target_bps,
+ /*subtract_per_packet_overhead=*/false);
+}
+
+template <typename T>
+void AudioEncoderIsacT<T>::OnReceivedTargetAudioBitrate(int target_bps) {
+ // Set target bitrate directly without subtracting per-packet overhead,
+ // because that's what AudioEncoderOpus does.
+ SetTargetBitrate(target_bps,
+ /*subtract_per_packet_overhead=*/false);
+}
+
+template <typename T>
+void AudioEncoderIsacT<T>::OnReceivedUplinkBandwidth(
+ int target_audio_bitrate_bps,
+ absl::optional<int64_t> /*bwe_period_ms*/) {
+ // Set target bitrate, subtracting the per-packet overhead if
+ // WebRTC-SendSideBwe-WithOverhead is enabled, because that's what
+ // AudioEncoderOpus does.
+ SetTargetBitrate(
+ target_audio_bitrate_bps,
+ /*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_);
+}
+
+template <typename T>
+void AudioEncoderIsacT<T>::OnReceivedUplinkAllocation(
+ BitrateAllocationUpdate update) {
+ // Set target bitrate, subtracting the per-packet overhead if
+ // WebRTC-SendSideBwe-WithOverhead is enabled, because that's what
+ // AudioEncoderOpus does.
+ SetTargetBitrate(
+ update.target_bitrate.bps<int>(),
+ /*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_);
+}
+
+template <typename T>
+void AudioEncoderIsacT<T>::OnReceivedOverhead(
+ size_t overhead_bytes_per_packet) {
+ overhead_per_packet_ = DataSize::Bytes(overhead_bytes_per_packet);
+}
+
+template <typename T>
+AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::EncodeImpl(
uint32_t rtp_timestamp,
- const int16_t* audio,
- size_t max_encoded_bytes,
- uint8_t* encoded) {
+ rtc::ArrayView<const int16_t> audio,
+ rtc::Buffer* encoded) {
if (!packet_in_progress_) {
// Starting a new packet; remember the timestamp for later.
packet_in_progress_ = true;
packet_timestamp_ = rtp_timestamp;
}
- if (bwinfo_) {
- IsacBandwidthInfo bwinfo = bwinfo_->Get();
- T::SetBandwidthInfo(isac_state_, &bwinfo);
- }
- int r = T::Encode(isac_state_, audio, encoded);
- RTC_CHECK_GE(r, 0) << "Encode failed (error code "
- << T::GetErrorCode(isac_state_) << ")";
+ size_t encoded_bytes = encoded->AppendData(
+ kSufficientEncodeBufferSizeBytes, [&](rtc::ArrayView<uint8_t> encoded) {
+ int r = T::Encode(isac_state_, audio.data(), encoded.data());
+
+ RTC_CHECK_GE(r, 0) << "Encode failed (error code "
+ << T::GetErrorCode(isac_state_) << ")";
- // T::Encode doesn't allow us to tell it the size of the output
- // buffer. All we can do is check for an overrun after the fact.
- RTC_CHECK_LE(static_cast<size_t>(r), max_encoded_bytes);
+ return static_cast<size_t>(r);
+ });
- if (r == 0)
+ if (encoded_bytes == 0)
return EncodedInfo();
// Got enough input to produce a packet. Return the saved timestamp from
// the first chunk of input that went into the packet.
packet_in_progress_ = false;
EncodedInfo info;
- info.encoded_bytes = r;
+ info.encoded_bytes = encoded_bytes;
info.encoded_timestamp = packet_timestamp_;
info.payload_type = config_.payload_type;
+ info.encoder_type = CodecType::kIsac;
return info;
}
@@ -154,22 +166,39 @@ void AudioEncoderIsacT<T>::Reset() {
}
template <typename T>
+absl::optional<std::pair<TimeDelta, TimeDelta>>
+AudioEncoderIsacT<T>::GetFrameLengthRange() const {
+ return {{TimeDelta::Millis(config_.frame_size_ms),
+ TimeDelta::Millis(config_.frame_size_ms)}};
+}
+
+template <typename T>
+void AudioEncoderIsacT<T>::SetTargetBitrate(int target_bps,
+ bool subtract_per_packet_overhead) {
+ if (subtract_per_packet_overhead) {
+ const DataRate overhead_rate =
+ overhead_per_packet_ / TimeDelta::Millis(config_.frame_size_ms);
+ target_bps -= overhead_rate.bps();
+ }
+ target_bps = rtc::SafeClamp(target_bps, kMinBitrateBps,
+ MaxBitrateBps(config_.sample_rate_hz));
+ int result = T::Control(isac_state_, target_bps, config_.frame_size_ms);
+ RTC_DCHECK_EQ(result, 0);
+ config_.bit_rate = target_bps;
+}
+
+template <typename T>
void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) {
RTC_CHECK(config.IsOk());
packet_in_progress_ = false;
- bwinfo_ = config.bwinfo;
if (isac_state_)
RTC_CHECK_EQ(0, T::Free(isac_state_));
RTC_CHECK_EQ(0, T::Create(&isac_state_));
- RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, config.adaptive_mode ? 0 : 1));
+ RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, /*coding_mode=*/1));
RTC_CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz));
const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate;
- if (config.adaptive_mode) {
- RTC_CHECK_EQ(0, T::ControlBwe(isac_state_, bit_rate, config.frame_size_ms,
- config.enforce_frame_size));
- } else {
- RTC_CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));
- }
+ RTC_CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));
+
if (config.max_payload_size_bytes != -1)
RTC_CHECK_EQ(
0, T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes));
@@ -187,4 +216,4 @@ void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h b/webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h
index 1e3f4c9..c3830a5 100644
--- a/webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h
+++ b/webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
-#include "webrtc/typedefs.h"
+#include <stdint.h>
typedef struct {
int in_use;
@@ -21,4 +21,4 @@ typedef struct {
int16_t jitter_info;
} IsacBandwidthInfo;
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h b/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h
index dcd4852..fae2f3d 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
-#include "webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
+#include "modules/audio_coding/codecs/isac/audio_decoder_isac_t.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
namespace webrtc {
-using AudioDecoderIsac = AudioDecoderIsacT<IsacFloat>;
+using AudioDecoderIsacFloatImpl = AudioDecoderIsacT<IsacFloat>;
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h b/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h
index cc8665d..dc32bcd 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h
@@ -8,15 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
-#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
+#include "modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
namespace webrtc {
-using AudioEncoderIsac = AudioEncoderIsacT<IsacFloat>;
+using AudioEncoderIsacFloatImpl = AudioEncoderIsacT<IsacFloat>;
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/include/isac.h b/webrtc/modules/audio_coding/codecs/isac/main/include/isac.h
index 327e7f4..3d2caef 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/include/isac.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/include/isac.h
@@ -8,717 +8,610 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_
#include <stddef.h>
-#include "webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_coding/codecs/isac/bandwidth_info.h"
-typedef struct WebRtcISACStruct ISACStruct;
+typedef struct WebRtcISACStruct ISACStruct;
#if defined(__cplusplus)
extern "C" {
#endif
- /******************************************************************************
- * WebRtcIsac_AssignSize(...)
- *
- * This function returns the size of the ISAC instance, so that the instance
- * can be created outside iSAC.
- *
- * Input:
- * - samplingRate : sampling rate of the input/output audio.
- *
- * Output:
- * - sizeinbytes : number of bytes needed to allocate for the
- * instance.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-
- int16_t WebRtcIsac_AssignSize(
- int* sizeinbytes);
-
-
- /******************************************************************************
- * WebRtcIsac_Assign(...)
- *
- * This function assignes the memory already created to the ISAC instance.
- *
- * Input:
- * - *ISAC_main_inst : a pointer to the coder instance.
- * - samplingRate : sampling rate of the input/output audio.
- * - ISAC_inst_Addr : the already allocated memory, where we put the
- * iSAC structure.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-
- int16_t WebRtcIsac_Assign(
- ISACStruct** ISAC_main_inst,
- void* ISAC_inst_Addr);
-
-
- /******************************************************************************
- * WebRtcIsac_Create(...)
- *
- * This function creates an ISAC instance, which will contain the state
- * information for one coding/decoding channel.
- *
- * Input:
- * - *ISAC_main_inst : a pointer to the coder instance.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-
- int16_t WebRtcIsac_Create(
- ISACStruct** ISAC_main_inst);
-
-
- /******************************************************************************
- * WebRtcIsac_Free(...)
- *
- * This function frees the ISAC instance created at the beginning.
- *
- * Input:
- * - ISAC_main_inst : an ISAC instance.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-
- int16_t WebRtcIsac_Free(
- ISACStruct* ISAC_main_inst);
-
-
- /******************************************************************************
- * WebRtcIsac_EncoderInit(...)
- *
- * This function initializes an ISAC instance prior to the encoder calls.
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - CodingMode : 0 -> Bit rate and frame length are
- * automatically adjusted to available bandwidth
- * on transmission channel, just valid if codec
- * is created to work in wideband mode.
- * 1 -> User sets a frame length and a target bit
- * rate which is taken as the maximum
- * short-term average bit rate.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-
- int16_t WebRtcIsac_EncoderInit(
- ISACStruct* ISAC_main_inst,
- int16_t CodingMode);
-
-
- /******************************************************************************
- * WebRtcIsac_Encode(...)
- *
- * This function encodes 10ms audio blocks and inserts it into a package.
- * Input speech length has 160 samples if operating at 16 kHz sampling
- * rate, or 320 if operating at 32 kHz sampling rate. The encoder buffers the
- * input audio until the whole frame is buffered then proceeds with encoding.
- *
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - speechIn : input speech vector.
- *
- * Output:
- * - encoded : the encoded data vector
- *
- * Return value:
- * : >0 - Length (in bytes) of coded data
- * : 0 - The buffer didn't reach the chosen
- * frame-size so it keeps buffering speech
- * samples.
- * : -1 - Error
- */
-
- int WebRtcIsac_Encode(
- ISACStruct* ISAC_main_inst,
- const int16_t* speechIn,
- uint8_t* encoded);
-
-
- /******************************************************************************
- * WebRtcIsac_DecoderInit(...)
- *
- * This function initializes an ISAC instance prior to the decoder calls.
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- */
-
- void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst);
-
- /******************************************************************************
- * WebRtcIsac_UpdateBwEstimate(...)
- *
- * This function updates the estimate of the bandwidth.
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - encoded : encoded ISAC frame(s).
- * - packet_size : size of the packet.
- * - rtp_seq_number : the RTP number of the packet.
- * - send_ts : the RTP send timestamp, given in samples
- * - arr_ts : the arrival time of the packet (from NetEq)
- * in samples.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-
- int16_t WebRtcIsac_UpdateBwEstimate(
- ISACStruct* ISAC_main_inst,
- const uint8_t* encoded,
- size_t packet_size,
- uint16_t rtp_seq_number,
- uint32_t send_ts,
- uint32_t arr_ts);
-
-
- /******************************************************************************
- * WebRtcIsac_Decode(...)
- *
- * This function decodes an ISAC frame. At 16 kHz sampling rate, the length
- * of the output audio could be either 480 or 960 samples, equivalent to
- * 30 or 60 ms respectively. At 32 kHz sampling rate, the length of the
- * output audio is 960 samples, which is 30 ms.
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - encoded : encoded ISAC frame(s).
- * - len : bytes in encoded vector.
- *
- * Output:
- * - decoded : The decoded vector.
- *
- * Return value : >0 - number of samples in decoded vector.
- * -1 - Error.
- */
-
- int WebRtcIsac_Decode(
- ISACStruct* ISAC_main_inst,
- const uint8_t* encoded,
- size_t len,
- int16_t* decoded,
- int16_t* speechType);
-
-
- /******************************************************************************
- * WebRtcIsac_DecodePlc(...)
- *
- * This function conducts PLC for ISAC frame(s). Output speech length
- * will be a multiple of frames, i.e. multiples of 30 ms audio. Therefore,
- * the output is multiple of 480 samples if operating at 16 kHz and multiple
- * of 960 if operating at 32 kHz.
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - noOfLostFrames : Number of PLC frames to produce.
- *
- * Output:
- * - decoded : The decoded vector.
- *
- * Return value : Number of samples in decoded PLC vector
- */
-
- size_t WebRtcIsac_DecodePlc(
- ISACStruct* ISAC_main_inst,
- int16_t* decoded,
- size_t noOfLostFrames);
-
-
- /******************************************************************************
- * WebRtcIsac_Control(...)
- *
- * This function sets the limit on the short-term average bit-rate and the
- * frame length. Should be used only in Instantaneous mode. At 16 kHz sampling
- * rate, an average bit-rate between 10000 to 32000 bps is valid and a
- * frame-size of 30 or 60 ms is acceptable. At 32 kHz, an average bit-rate
- * between 10000 to 56000 is acceptable, and the valid frame-size is 30 ms.
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - rate : limit on the short-term average bit rate,
- * in bits/second.
- * - framesize : frame-size in millisecond.
- *
- * Return value : 0 - ok
- * -1 - Error
- */
-
- int16_t WebRtcIsac_Control(
- ISACStruct* ISAC_main_inst,
- int32_t rate,
- int framesize);
-
- void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst,
- int bottleneck_bits_per_second);
-
- /******************************************************************************
- * WebRtcIsac_ControlBwe(...)
- *
- * This function sets the initial values of bottleneck and frame-size if
- * iSAC is used in channel-adaptive mode. Therefore, this API is not
- * applicable if the codec is created to operate in super-wideband mode.
- *
- * Through this API, users can enforce a frame-size for all values of
- * bottleneck. Then iSAC will not automatically change the frame-size.
- *
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - rateBPS : initial value of bottleneck in bits/second
- * 10000 <= rateBPS <= 56000 is accepted
- * For default bottleneck set rateBPS = 0
- * - frameSizeMs : number of milliseconds per frame (30 or 60)
- * - enforceFrameSize : 1 to enforce the given frame-size through
- * out the adaptation process, 0 to let iSAC
- * change the frame-size if required.
- *
- * Return value : 0 - ok
- * -1 - Error
- */
-
- int16_t WebRtcIsac_ControlBwe(
- ISACStruct* ISAC_main_inst,
- int32_t rateBPS,
- int frameSizeMs,
- int16_t enforceFrameSize);
-
-
- /******************************************************************************
- * WebRtcIsac_ReadFrameLen(...)
- *
- * This function returns the length of the frame represented in the packet.
- *
- * Input:
- * - encoded : Encoded bit-stream
- *
- * Output:
- * - frameLength : Length of frame in packet (in samples)
- *
- */
-
- int16_t WebRtcIsac_ReadFrameLen(
- ISACStruct* ISAC_main_inst,
- const uint8_t* encoded,
- int16_t* frameLength);
-
-
- /******************************************************************************
- * WebRtcIsac_version(...)
- *
- * This function returns the version number.
- *
- * Output:
- * - version : Pointer to character string
- *
- */
-
- void WebRtcIsac_version(
- char *version);
-
-
- /******************************************************************************
- * WebRtcIsac_GetErrorCode(...)
- *
- * This function can be used to check the error code of an iSAC instance. When
- * a function returns -1 a error code will be set for that instance. The
- * function below extract the code of the last error that occurred in the
- * specified instance.
- *
- * Input:
- * - ISAC_main_inst : ISAC instance
- *
- * Return value : Error code
- */
-
- int16_t WebRtcIsac_GetErrorCode(
- ISACStruct* ISAC_main_inst);
-
-
- /****************************************************************************
- * WebRtcIsac_GetUplinkBw(...)
- *
- * This function outputs the target bottleneck of the codec. In
- * channel-adaptive mode, the target bottleneck is specified through in-band
- * signalling retreived by bandwidth estimator.
- * In channel-independent, also called instantaneous mode, the target
- * bottleneck is provided to the encoder by calling xxx_control(...). If
- * xxx_control is never called the default values is returned. The default
- * value for bottleneck at 16 kHz encoder sampling rate is 32000 bits/sec,
- * and it is 56000 bits/sec for 32 kHz sampling rate.
- * Note that the output is the iSAC internal operating bottleneck which might
- * differ slightly from the one provided through xxx_control().
- *
- * Input:
- * - ISAC_main_inst : iSAC instance
- *
- * Output:
- * - *bottleneck : bottleneck in bits/sec
- *
- * Return value : -1 if error happens
- * 0 bit-rates computed correctly.
- */
-
- int16_t WebRtcIsac_GetUplinkBw(
- ISACStruct* ISAC_main_inst,
- int32_t* bottleneck);
-
-
- /******************************************************************************
- * WebRtcIsac_SetMaxPayloadSize(...)
- *
- * This function sets a limit for the maximum payload size of iSAC. The same
- * value is used both for 30 and 60 ms packets. If the encoder sampling rate
- * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the
- * encoder sampling rate is 32 kHz the maximum payload size is between 120
- * and 600 bytes.
- *
- * If an out of range limit is used, the function returns -1, but the closest
- * valid value will be applied.
- *
- * ---------------
- * IMPORTANT NOTES
- * ---------------
- * The size of a packet is limited to the minimum of 'max-payload-size' and
- * 'max-rate.' For instance, let's assume the max-payload-size is set to
- * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
- * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
- * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
- * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
- * 170 bytes, i.e. min(170, 300).
- *
- * Input:
- * - ISAC_main_inst : iSAC instance
- * - maxPayloadBytes : maximum size of the payload in bytes
- * valid values are between 120 and 400 bytes
- * if encoder sampling rate is 16 kHz. For
- * 32 kHz encoder sampling rate valid values
- * are between 120 and 600 bytes.
- *
- * Return value : 0 if successful
- * -1 if error happens
- */
-
- int16_t WebRtcIsac_SetMaxPayloadSize(
- ISACStruct* ISAC_main_inst,
- int16_t maxPayloadBytes);
-
-
- /******************************************************************************
- * WebRtcIsac_SetMaxRate(...)
- *
- * This function sets the maximum rate which the codec may not exceed for
- * any signal packet. The maximum rate is defined and payload-size per
- * frame-size in bits per second.
- *
- * The codec has a maximum rate of 53400 bits per second (200 bytes per 30
- * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms)
- * if the encoder sampling rate is 32 kHz.
- *
- * It is possible to set a maximum rate between 32000 and 53400 bits/sec
- * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode.
- *
- * If an out of range limit is used, the function returns -1, but the closest
- * valid value will be applied.
- *
- * ---------------
- * IMPORTANT NOTES
- * ---------------
- * The size of a packet is limited to the minimum of 'max-payload-size' and
- * 'max-rate.' For instance, let's assume the max-payload-size is set to
- * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
- * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
- * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
- * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
- * 170 bytes, min(170, 300).
- *
- * Input:
- * - ISAC_main_inst : iSAC instance
- * - maxRate : maximum rate in bits per second,
- * valid values are 32000 to 53400 bits/sec in
- * wideband mode, and 32000 to 160000 bits/sec in
- * super-wideband mode.
- *
- * Return value : 0 if successful
- * -1 if error happens
- */
-
- int16_t WebRtcIsac_SetMaxRate(
- ISACStruct* ISAC_main_inst,
- int32_t maxRate);
-
-
- /******************************************************************************
- * WebRtcIsac_DecSampRate()
- * Return the sampling rate of the decoded audio.
- *
- * Input:
- * - ISAC_main_inst : iSAC instance
- *
- * Return value : sampling frequency in Hertz.
- *
- */
-
- uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst);
-
-
- /******************************************************************************
- * WebRtcIsac_EncSampRate()
- *
- * Input:
- * - ISAC_main_inst : iSAC instance
- *
- * Return value : sampling rate in Hertz.
- *
- */
-
- uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst);
-
-
- /******************************************************************************
- * WebRtcIsac_SetDecSampRate()
- * Set the sampling rate of the decoder. Initialization of the decoder WILL
- * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
- * which is set when the instance is created.
- *
- * Input:
- * - ISAC_main_inst : iSAC instance
- * - sampRate : sampling rate in Hertz.
- *
- * Return value : 0 if successful
- * -1 if failed.
- */
-
- int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst,
- uint16_t samp_rate_hz);
-
-
- /******************************************************************************
- * WebRtcIsac_SetEncSampRate()
- * Set the sampling rate of the encoder. Initialization of the encoder WILL
- * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
- * which is set when the instance is created. The encoding-mode and the
- * bottleneck remain unchanged by this call, however, the maximum rate and
- * maximum payload-size will reset to their default value.
- *
- * Input:
- * - ISAC_main_inst : iSAC instance
- * - sampRate : sampling rate in Hertz.
- *
- * Return value : 0 if successful
- * -1 if failed.
- */
-
- int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst,
- uint16_t sample_rate_hz);
-
-
-
- /******************************************************************************
- * WebRtcIsac_GetNewBitStream(...)
- *
- * This function returns encoded data, with the recieved bwe-index in the
- * stream. If the rate is set to a value less than bottleneck of codec
- * the new bistream will be re-encoded with the given target rate.
- * It should always return a complete packet, i.e. only called once
- * even for 60 msec frames.
- *
- * NOTE 1! This function does not write in the ISACStruct, it is not allowed.
- * NOTE 2! Currently not implemented for SWB mode.
- * NOTE 3! Rates larger than the bottleneck of the codec will be limited
- * to the current bottleneck.
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - bweIndex : Index of bandwidth estimate to put in new
- * bitstream
- * - rate : target rate of the transcoder is bits/sec.
- * Valid values are the accepted rate in iSAC,
- * i.e. 10000 to 56000.
- * - isRCU : if the new bit-stream is an RCU stream.
- * Note that the rate parameter always indicates
- * the target rate of the main payload, regardless
- * of 'isRCU' value.
- *
- * Output:
- * - encoded : The encoded data vector
- *
- * Return value : >0 - Length (in bytes) of coded data
- * -1 - Error or called in SWB mode
- * NOTE! No error code is written to
- * the struct since it is only allowed to read
- * the struct.
- */
- int16_t WebRtcIsac_GetNewBitStream(
- ISACStruct* ISAC_main_inst,
- int16_t bweIndex,
- int16_t jitterInfo,
- int32_t rate,
- uint8_t* encoded,
- int16_t isRCU);
-
-
-
- /****************************************************************************
- * WebRtcIsac_GetDownLinkBwIndex(...)
- *
- * This function returns index representing the Bandwidth estimate from
- * other side to this side.
- *
- * Input:
- * - ISAC_main_inst : iSAC struct
- *
- * Output:
- * - bweIndex : Bandwidth estimate to transmit to other side.
- *
- */
-
- int16_t WebRtcIsac_GetDownLinkBwIndex(
- ISACStruct* ISAC_main_inst,
- int16_t* bweIndex,
- int16_t* jitterInfo);
-
-
- /****************************************************************************
- * WebRtcIsac_UpdateUplinkBw(...)
- *
- * This function takes an index representing the Bandwidth estimate from
- * this side to other side and updates BWE.
- *
- * Input:
- * - ISAC_main_inst : iSAC struct
- * - bweIndex : Bandwidth estimate from other side.
- *
- */
-
- int16_t WebRtcIsac_UpdateUplinkBw(
- ISACStruct* ISAC_main_inst,
- int16_t bweIndex);
-
-
- /****************************************************************************
- * WebRtcIsac_ReadBwIndex(...)
- *
- * This function returns the index of the Bandwidth estimate from the bitstream.
- *
- * Input:
- * - encoded : Encoded bitstream
- *
- * Output:
- * - frameLength : Length of frame in packet (in samples)
- * - bweIndex : Bandwidth estimate in bitstream
- *
- */
-
- int16_t WebRtcIsac_ReadBwIndex(
- const uint8_t* encoded,
- int16_t* bweIndex);
-
-
-
- /*******************************************************************************
- * WebRtcIsac_GetNewFrameLen(...)
- *
- * returns the frame lenght (in samples) of the next packet. In the case of channel-adaptive
- * mode, iSAC decides on its frame lenght based on the estimated bottleneck
- * this allows a user to prepare for the next packet (at the encoder)
- *
- * The primary usage is in CE to make the iSAC works in channel-adaptive mode
- *
- * Input:
- * - ISAC_main_inst : iSAC struct
- *
- * Return Value : frame lenght in samples
- *
- */
-
- int16_t WebRtcIsac_GetNewFrameLen(
- ISACStruct* ISAC_main_inst);
-
-
- /****************************************************************************
- * WebRtcIsac_GetRedPayload(...)
- *
- * Populates "encoded" with the redundant payload of the recently encoded
- * frame. This function has to be called once that WebRtcIsac_Encode(...)
- * returns a positive value. Regardless of the frame-size this function will
- * be called only once after encoding is completed.
- *
- * Input:
- * - ISAC_main_inst : iSAC struct
- *
- * Output:
- * - encoded : the encoded data vector
- *
- *
- * Return value:
- * : >0 - Length (in bytes) of coded data
- * : -1 - Error
- *
- *
- */
- int16_t WebRtcIsac_GetRedPayload(
- ISACStruct* ISAC_main_inst,
- uint8_t* encoded);
-
-
- /****************************************************************************
- * WebRtcIsac_DecodeRcu(...)
- *
- * This function decodes a redundant (RCU) iSAC frame. Function is called in
- * NetEq with a stored RCU payload i case of packet loss. Output speech length
- * will be a multiple of 480 samples: 480 or 960 samples,
- * depending on the framesize (30 or 60 ms).
- *
- * Input:
- * - ISAC_main_inst : ISAC instance.
- * - encoded : encoded ISAC RCU frame(s)
- * - len : bytes in encoded vector
- *
- * Output:
- * - decoded : The decoded vector
- *
- * Return value : >0 - number of samples in decoded vector
- * -1 - Error
- */
- int WebRtcIsac_DecodeRcu(
- ISACStruct* ISAC_main_inst,
- const uint8_t* encoded,
- size_t len,
- int16_t* decoded,
- int16_t* speechType);
-
- /* Fills in an IsacBandwidthInfo struct. |inst| should be a decoder. */
- void WebRtcIsac_GetBandwidthInfo(ISACStruct* inst, IsacBandwidthInfo* bwinfo);
-
- /* Uses the values from an IsacBandwidthInfo struct. |inst| should be an
- encoder. */
- void WebRtcIsac_SetBandwidthInfo(ISACStruct* inst,
- const IsacBandwidthInfo* bwinfo);
-
- /* If |inst| is a decoder but not an encoder: tell it what sample rate the
- encoder is using, for bandwidth estimation purposes. */
- void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst, int sample_rate_hz);
+/******************************************************************************
+ * WebRtcIsac_Create(...)
+ *
+ * This function creates an ISAC instance, which will contain the state
+ * information for one coding/decoding channel.
+ *
+ * Input:
+ * - *ISAC_main_inst : a pointer to the coder instance.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+
+int16_t WebRtcIsac_Create(ISACStruct** ISAC_main_inst);
+
+/******************************************************************************
+ * WebRtcIsac_Free(...)
+ *
+ * This function frees the ISAC instance created at the beginning.
+ *
+ * Input:
+ * - ISAC_main_inst : an ISAC instance.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+
+int16_t WebRtcIsac_Free(ISACStruct* ISAC_main_inst);
+
+/******************************************************************************
+ * WebRtcIsac_EncoderInit(...)
+ *
+ * This function initializes an ISAC instance prior to the encoder calls.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - CodingMode : 0 -> Bit rate and frame length are
+ * automatically adjusted to available bandwidth
+ * on transmission channel, just valid if codec
+ * is created to work in wideband mode.
+ * 1 -> User sets a frame length and a target bit
+ * rate which is taken as the maximum
+ * short-term average bit rate.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+
+int16_t WebRtcIsac_EncoderInit(ISACStruct* ISAC_main_inst, int16_t CodingMode);
+
+/******************************************************************************
+ * WebRtcIsac_Encode(...)
+ *
+ * This function encodes 10ms audio blocks and inserts it into a package.
+ * Input speech length has 160 samples if operating at 16 kHz sampling
+ * rate, or 320 if operating at 32 kHz sampling rate. The encoder buffers the
+ * input audio until the whole frame is buffered then proceeds with encoding.
+ *
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - speechIn : input speech vector.
+ *
+ * Output:
+ * - encoded : the encoded data vector
+ *
+ * Return value:
+ * : >0 - Length (in bytes) of coded data
+ * : 0 - The buffer didn't reach the chosen
+ * frame-size so it keeps buffering speech
+ * samples.
+ * : -1 - Error
+ */
+
+int WebRtcIsac_Encode(ISACStruct* ISAC_main_inst,
+ const int16_t* speechIn,
+ uint8_t* encoded);
+
+/******************************************************************************
+ * WebRtcIsac_DecoderInit(...)
+ *
+ * This function initializes an ISAC instance prior to the decoder calls.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ */
+
+void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst);
+
+/******************************************************************************
+ * WebRtcIsac_UpdateBwEstimate(...)
+ *
+ * This function updates the estimate of the bandwidth.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - encoded : encoded ISAC frame(s).
+ * - packet_size : size of the packet.
+ * - rtp_seq_number : the RTP number of the packet.
+ * - send_ts : the RTP send timestamp, given in samples
+ * - arr_ts : the arrival time of the packet (from NetEq)
+ * in samples.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+
+int16_t WebRtcIsac_UpdateBwEstimate(ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ size_t packet_size,
+ uint16_t rtp_seq_number,
+ uint32_t send_ts,
+ uint32_t arr_ts);
+
+/******************************************************************************
+ * WebRtcIsac_Decode(...)
+ *
+ * This function decodes an ISAC frame. At 16 kHz sampling rate, the length
+ * of the output audio could be either 480 or 960 samples, equivalent to
+ * 30 or 60 ms respectively. At 32 kHz sampling rate, the length of the
+ * output audio is 960 samples, which is 30 ms.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - encoded : encoded ISAC frame(s).
+ * - len : bytes in encoded vector.
+ *
+ * Output:
+ * - decoded : The decoded vector.
+ *
+ * Return value : >0 - number of samples in decoded vector.
+ * -1 - Error.
+ */
+
+int WebRtcIsac_Decode(ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ size_t len,
+ int16_t* decoded,
+ int16_t* speechType);
+
+/******************************************************************************
+ * WebRtcIsac_DecodePlc(...)
+ *
+ * This function conducts PLC for ISAC frame(s). Output speech length
+ * will be a multiple of frames, i.e. multiples of 30 ms audio. Therefore,
+ * the output is multiple of 480 samples if operating at 16 kHz and multiple
+ * of 960 if operating at 32 kHz.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - noOfLostFrames : Number of PLC frames to produce.
+ *
+ * Output:
+ * - decoded : The decoded vector.
+ *
+ * Return value : Number of samples in decoded PLC vector
+ */
+
+size_t WebRtcIsac_DecodePlc(ISACStruct* ISAC_main_inst,
+ int16_t* decoded,
+ size_t noOfLostFrames);
+
+/******************************************************************************
+ * WebRtcIsac_Control(...)
+ *
+ * This function sets the limit on the short-term average bit-rate and the
+ * frame length. Should be used only in Instantaneous mode. At 16 kHz sampling
+ * rate, an average bit-rate between 10000 to 32000 bps is valid and a
+ * frame-size of 30 or 60 ms is acceptable. At 32 kHz, an average bit-rate
+ * between 10000 to 56000 is acceptable, and the valid frame-size is 30 ms.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - rate : limit on the short-term average bit rate,
+ * in bits/second.
+ * - framesize : frame-size in millisecond.
+ *
+ * Return value : 0 - ok
+ * -1 - Error
+ */
+
+int16_t WebRtcIsac_Control(ISACStruct* ISAC_main_inst,
+ int32_t rate,
+ int framesize);
+
+void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst,
+ int bottleneck_bits_per_second);
+
+/******************************************************************************
+ * WebRtcIsac_ControlBwe(...)
+ *
+ * This function sets the initial values of bottleneck and frame-size if
+ * iSAC is used in channel-adaptive mode. Therefore, this API is not
+ * applicable if the codec is created to operate in super-wideband mode.
+ *
+ * Through this API, users can enforce a frame-size for all values of
+ * bottleneck. Then iSAC will not automatically change the frame-size.
+ *
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - rateBPS : initial value of bottleneck in bits/second
+ * 10000 <= rateBPS <= 56000 is accepted
+ * For default bottleneck set rateBPS = 0
+ * - frameSizeMs : number of milliseconds per frame (30 or 60)
+ * - enforceFrameSize : 1 to enforce the given frame-size through
+ * out the adaptation process, 0 to let iSAC
+ * change the frame-size if required.
+ *
+ * Return value : 0 - ok
+ * -1 - Error
+ */
+
+int16_t WebRtcIsac_ControlBwe(ISACStruct* ISAC_main_inst,
+ int32_t rateBPS,
+ int frameSizeMs,
+ int16_t enforceFrameSize);
+
+/******************************************************************************
+ * WebRtcIsac_ReadFrameLen(...)
+ *
+ * This function returns the length of the frame represented in the packet.
+ *
+ * Input:
+ * - encoded : Encoded bit-stream
+ *
+ * Output:
+ * - frameLength : Length of frame in packet (in samples)
+ *
+ */
+
+int16_t WebRtcIsac_ReadFrameLen(const ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ int16_t* frameLength);
+
+/******************************************************************************
+ * WebRtcIsac_version(...)
+ *
+ * This function returns the version number.
+ *
+ * Output:
+ * - version : Pointer to character string
+ *
+ */
+
+void WebRtcIsac_version(char* version);
+
+/******************************************************************************
+ * WebRtcIsac_GetErrorCode(...)
+ *
+ * This function can be used to check the error code of an iSAC instance. When
+ * a function returns -1 a error code will be set for that instance. The
+ * function below extract the code of the last error that occurred in the
+ * specified instance.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance
+ *
+ * Return value : Error code
+ */
+
+int16_t WebRtcIsac_GetErrorCode(ISACStruct* ISAC_main_inst);
+
+/****************************************************************************
+ * WebRtcIsac_GetUplinkBw(...)
+ *
+ * This function outputs the target bottleneck of the codec. In
+ * channel-adaptive mode, the target bottleneck is specified through in-band
+ * signalling retreived by bandwidth estimator.
+ * In channel-independent, also called instantaneous mode, the target
+ * bottleneck is provided to the encoder by calling xxx_control(...). If
+ * xxx_control is never called the default values is returned. The default
+ * value for bottleneck at 16 kHz encoder sampling rate is 32000 bits/sec,
+ * and it is 56000 bits/sec for 32 kHz sampling rate.
+ * Note that the output is the iSAC internal operating bottleneck which might
+ * differ slightly from the one provided through xxx_control().
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ *
+ * Output:
+ * - *bottleneck : bottleneck in bits/sec
+ *
+ * Return value : -1 if error happens
+ * 0 bit-rates computed correctly.
+ */
+
+int16_t WebRtcIsac_GetUplinkBw(ISACStruct* ISAC_main_inst, int32_t* bottleneck);
+
+/******************************************************************************
+ * WebRtcIsac_SetMaxPayloadSize(...)
+ *
+ * This function sets a limit for the maximum payload size of iSAC. The same
+ * value is used both for 30 and 60 ms packets. If the encoder sampling rate
+ * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the
+ * encoder sampling rate is 32 kHz the maximum payload size is between 120
+ * and 600 bytes.
+ *
+ * If an out of range limit is used, the function returns -1, but the closest
+ * valid value will be applied.
+ *
+ * ---------------
+ * IMPORTANT NOTES
+ * ---------------
+ * The size of a packet is limited to the minimum of 'max-payload-size' and
+ * 'max-rate.' For instance, let's assume the max-payload-size is set to
+ * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
+ * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
+ * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
+ * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
+ * 170 bytes, i.e. min(170, 300).
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ * - maxPayloadBytes : maximum size of the payload in bytes
+ * valid values are between 120 and 400 bytes
+ * if encoder sampling rate is 16 kHz. For
+ * 32 kHz encoder sampling rate valid values
+ * are between 120 and 600 bytes.
+ *
+ * Return value : 0 if successful
+ * -1 if error happens
+ */
+
+int16_t WebRtcIsac_SetMaxPayloadSize(ISACStruct* ISAC_main_inst,
+ int16_t maxPayloadBytes);
+
+/******************************************************************************
+ * WebRtcIsac_SetMaxRate(...)
+ *
+ * This function sets the maximum rate which the codec may not exceed for
+ * any signal packet. The maximum rate is defined and payload-size per
+ * frame-size in bits per second.
+ *
+ * The codec has a maximum rate of 53400 bits per second (200 bytes per 30
+ * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms)
+ * if the encoder sampling rate is 32 kHz.
+ *
+ * It is possible to set a maximum rate between 32000 and 53400 bits/sec
+ * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode.
+ *
+ * If an out of range limit is used, the function returns -1, but the closest
+ * valid value will be applied.
+ *
+ * ---------------
+ * IMPORTANT NOTES
+ * ---------------
+ * The size of a packet is limited to the minimum of 'max-payload-size' and
+ * 'max-rate.' For instance, let's assume the max-payload-size is set to
+ * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
+ * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
+ * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
+ * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
+ * 170 bytes, min(170, 300).
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ * - maxRate : maximum rate in bits per second,
+ * valid values are 32000 to 53400 bits/sec in
+ * wideband mode, and 32000 to 160000 bits/sec in
+ * super-wideband mode.
+ *
+ * Return value : 0 if successful
+ * -1 if error happens
+ */
+
+int16_t WebRtcIsac_SetMaxRate(ISACStruct* ISAC_main_inst, int32_t maxRate);
+
+/******************************************************************************
+ * WebRtcIsac_DecSampRate()
+ * Return the sampling rate of the decoded audio.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ *
+ * Return value : sampling frequency in Hertz.
+ *
+ */
+
+uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst);
+
+/******************************************************************************
+ * WebRtcIsac_EncSampRate()
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ *
+ * Return value : sampling rate in Hertz.
+ *
+ */
+
+uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst);
+
+/******************************************************************************
+ * WebRtcIsac_SetDecSampRate()
+ * Set the sampling rate of the decoder. Initialization of the decoder WILL
+ * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
+ * which is set when the instance is created.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ * - sampRate : sampling rate in Hertz.
+ *
+ * Return value : 0 if successful
+ * -1 if failed.
+ */
+
+int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst,
+ uint16_t samp_rate_hz);
+
+/******************************************************************************
+ * WebRtcIsac_SetEncSampRate()
+ * Set the sampling rate of the encoder. Initialization of the encoder WILL
+ * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
+ * which is set when the instance is created. The encoding-mode and the
+ * bottleneck remain unchanged by this call, however, the maximum rate and
+ * maximum payload-size will reset to their default value.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC instance
+ * - sampRate : sampling rate in Hertz.
+ *
+ * Return value : 0 if successful
+ * -1 if failed.
+ */
+
+int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst,
+ uint16_t sample_rate_hz);
+
+/******************************************************************************
+ * WebRtcIsac_GetNewBitStream(...)
+ *
+ * This function returns encoded data, with the recieved bwe-index in the
+ * stream. If the rate is set to a value less than bottleneck of codec
+ * the new bistream will be re-encoded with the given target rate.
+ * It should always return a complete packet, i.e. only called once
+ * even for 60 msec frames.
+ *
+ * NOTE 1! This function does not write in the ISACStruct, it is not allowed.
+ * NOTE 2! Currently not implemented for SWB mode.
+ * NOTE 3! Rates larger than the bottleneck of the codec will be limited
+ * to the current bottleneck.
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - bweIndex : Index of bandwidth estimate to put in new
+ * bitstream
+ * - rate : target rate of the transcoder is bits/sec.
+ * Valid values are the accepted rate in iSAC,
+ * i.e. 10000 to 56000.
+ * - isRCU : if the new bit-stream is an RCU
+ * stream. Note that the rate parameter always indicates the target rate of the
+ * main payload, regardless of 'isRCU' value.
+ *
+ * Output:
+ * - encoded : The encoded data vector
+ *
+ * Return value : >0 - Length (in bytes) of coded data
+ * -1 - Error or called in SWB mode
+ * NOTE! No error code is written to
+ * the struct since it is only allowed to read
+ * the struct.
+ */
+int16_t WebRtcIsac_GetNewBitStream(ISACStruct* ISAC_main_inst,
+ int16_t bweIndex,
+ int16_t jitterInfo,
+ int32_t rate,
+ uint8_t* encoded,
+ int16_t isRCU);
+
+/****************************************************************************
+ * WebRtcIsac_GetDownLinkBwIndex(...)
+ *
+ * This function returns index representing the Bandwidth estimate from
+ * other side to this side.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC struct
+ *
+ * Output:
+ * - bweIndex : Bandwidth estimate to transmit to other side.
+ *
+ */
+
+int16_t WebRtcIsac_GetDownLinkBwIndex(ISACStruct* ISAC_main_inst,
+ int16_t* bweIndex,
+ int16_t* jitterInfo);
+
+/****************************************************************************
+ * WebRtcIsac_UpdateUplinkBw(...)
+ *
+ * This function takes an index representing the Bandwidth estimate from
+ * this side to other side and updates BWE.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC struct
+ * - bweIndex : Bandwidth estimate from other side.
+ *
+ */
+
+int16_t WebRtcIsac_UpdateUplinkBw(ISACStruct* ISAC_main_inst, int16_t bweIndex);
+
+/****************************************************************************
+ * WebRtcIsac_ReadBwIndex(...)
+ *
+ * This function returns the index of the Bandwidth estimate from the bitstream.
+ *
+ * Input:
+ * - encoded : Encoded bitstream
+ *
+ * Output:
+ * - frameLength : Length of frame in packet (in samples)
+ * - bweIndex : Bandwidth estimate in bitstream
+ *
+ */
+
+int16_t WebRtcIsac_ReadBwIndex(const uint8_t* encoded, int16_t* bweIndex);
+
+/*******************************************************************************
+ * WebRtcIsac_GetNewFrameLen(...)
+ *
+ * returns the frame lenght (in samples) of the next packet. In the case of
+ * channel-adaptive mode, iSAC decides on its frame lenght based on the
+ * estimated bottleneck this allows a user to prepare for the next packet (at
+ * the encoder)
+ *
+ * The primary usage is in CE to make the iSAC works in channel-adaptive mode
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC struct
+ *
+ * Return Value : frame lenght in samples
+ *
+ */
+
+int16_t WebRtcIsac_GetNewFrameLen(ISACStruct* ISAC_main_inst);
+
+/****************************************************************************
+ * WebRtcIsac_GetRedPayload(...)
+ *
+ * Populates "encoded" with the redundant payload of the recently encoded
+ * frame. This function has to be called once that WebRtcIsac_Encode(...)
+ * returns a positive value. Regardless of the frame-size this function will
+ * be called only once after encoding is completed.
+ *
+ * Input:
+ * - ISAC_main_inst : iSAC struct
+ *
+ * Output:
+ * - encoded : the encoded data vector
+ *
+ *
+ * Return value:
+ * : >0 - Length (in bytes) of coded data
+ * : -1 - Error
+ *
+ *
+ */
+int16_t WebRtcIsac_GetRedPayload(ISACStruct* ISAC_main_inst, uint8_t* encoded);
+
+/****************************************************************************
+ * WebRtcIsac_DecodeRcu(...)
+ *
+ * This function decodes a redundant (RCU) iSAC frame. Function is called in
+ * NetEq with a stored RCU payload i case of packet loss. Output speech length
+ * will be a multiple of 480 samples: 480 or 960 samples,
+ * depending on the framesize (30 or 60 ms).
+ *
+ * Input:
+ * - ISAC_main_inst : ISAC instance.
+ * - encoded : encoded ISAC RCU frame(s)
+ * - len : bytes in encoded vector
+ *
+ * Output:
+ * - decoded : The decoded vector
+ *
+ * Return value : >0 - number of samples in decoded vector
+ * -1 - Error
+ */
+int WebRtcIsac_DecodeRcu(ISACStruct* ISAC_main_inst,
+ const uint8_t* encoded,
+ size_t len,
+ int16_t* decoded,
+ int16_t* speechType);
+
+/* If |inst| is a decoder but not an encoder: tell it what sample rate the
+ encoder is using, for bandwidth estimation purposes. */
+void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst, int sample_rate_hz);
#if defined(__cplusplus)
}
#endif
-
-
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_ISAC_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.c b/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.c
index 5c901bb..9d5c693 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.c
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "arith_routines.h"
-#include "settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
/*
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.h b/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.h
index 43ba40e..6e7ea1d 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines.h
@@ -15,49 +15,53 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
-
-#include "structs.h"
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
int WebRtcIsac_EncLogisticMulti2(
- Bitstr *streamdata, /* in-/output struct containing bitstream */
- int16_t *dataQ7, /* input: data vector */
- const uint16_t *env, /* input: side info vector defining the width of the pdf */
- const int N, /* input: data vector length */
+ Bitstr* streamdata, /* in-/output struct containing bitstream */
+ int16_t* dataQ7, /* input: data vector */
+ const uint16_t*
+ env, /* input: side info vector defining the width of the pdf */
+ const int N, /* input: data vector length */
const int16_t isSWB12kHz); /* if the codec is working in 12kHz bandwidth */
/* returns the number of bytes in the stream */
-int WebRtcIsac_EncTerminate(Bitstr *streamdata); /* in-/output struct containing bitstream */
+int WebRtcIsac_EncTerminate(
+ Bitstr* streamdata); /* in-/output struct containing bitstream */
/* returns the number of bytes in the stream so far */
int WebRtcIsac_DecLogisticMulti2(
- int16_t *data, /* output: data vector */
- Bitstr *streamdata, /* in-/output struct containing bitstream */
- const uint16_t *env, /* input: side info vector defining the width of the pdf */
- const int16_t *dither, /* input: dither vector */
- const int N, /* input: data vector length */
+ int16_t* data, /* output: data vector */
+ Bitstr* streamdata, /* in-/output struct containing bitstream */
+ const uint16_t*
+ env, /* input: side info vector defining the width of the pdf */
+ const int16_t* dither, /* input: dither vector */
+ const int N, /* input: data vector length */
const int16_t isSWB12kHz); /* if the codec is working in 12kHz bandwidth */
void WebRtcIsac_EncHistMulti(
- Bitstr *streamdata, /* in-/output struct containing bitstream */
- const int *data, /* input: data vector */
- const uint16_t **cdf, /* input: array of cdf arrays */
+ Bitstr* streamdata, /* in-/output struct containing bitstream */
+ const int* data, /* input: data vector */
+ const uint16_t* const* cdf, /* input: array of cdf arrays */
const int N); /* input: data vector length */
int WebRtcIsac_DecHistBisectMulti(
- int *data, /* output: data vector */
- Bitstr *streamdata, /* in-/output struct containing bitstream */
- const uint16_t **cdf, /* input: array of cdf arrays */
- const uint16_t *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */
- const int N); /* input: data vector length */
+ int* data, /* output: data vector */
+ Bitstr* streamdata, /* in-/output struct containing bitstream */
+ const uint16_t* const* cdf, /* input: array of cdf arrays */
+ const uint16_t*
+ cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */
+ const int N); /* input: data vector length */
int WebRtcIsac_DecHistOneStepMulti(
- int *data, /* output: data vector */
- Bitstr *streamdata, /* in-/output struct containing bitstream */
- const uint16_t **cdf, /* input: array of cdf arrays */
- const uint16_t *init_index,/* input: vector of initial cdf table search entries */
- const int N); /* input: data vector length */
+ int* data, /* output: data vector */
+ Bitstr* streamdata, /* in-/output struct containing bitstream */
+ const uint16_t* const* cdf, /* input: array of cdf arrays */
+ const uint16_t*
+ init_index, /* input: vector of initial cdf table search entries */
+ const int N); /* input: data vector length */
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c b/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c
index 63e4928..e948979 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "settings.h"
-#include "arith_routines.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
/*
@@ -17,7 +17,7 @@
*/
void WebRtcIsac_EncHistMulti(Bitstr *streamdata, /* in-/output struct containing bitstream */
const int *data, /* input: data vector */
- const uint16_t **cdf, /* input: array of cdf arrays */
+ const uint16_t *const *cdf, /* input: array of cdf arrays */
const int N) /* input: data vector length */
{
uint32_t W_lower, W_upper;
@@ -84,7 +84,7 @@ void WebRtcIsac_EncHistMulti(Bitstr *streamdata, /* in-/output struct containing
*/
int WebRtcIsac_DecHistBisectMulti(int *data, /* output: data vector */
Bitstr *streamdata, /* in-/output struct containing bitstream */
- const uint16_t **cdf, /* input: array of cdf arrays */
+ const uint16_t *const *cdf, /* input: array of cdf arrays */
const uint16_t *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */
const int N) /* input: data vector length */
{
@@ -192,7 +192,7 @@ int WebRtcIsac_DecHistBisectMulti(int *data, /* output: data vector */
*/
int WebRtcIsac_DecHistOneStepMulti(int *data, /* output: data vector */
Bitstr *streamdata, /* in-/output struct containing bitstream */
- const uint16_t **cdf, /* input: array of cdf arrays */
+ const uint16_t *const *cdf, /* input: array of cdf arrays */
const uint16_t *init_index, /* input: vector of initial cdf table search entries */
const int N) /* input: data vector length */
{
@@ -214,10 +214,10 @@ int WebRtcIsac_DecHistOneStepMulti(int *data, /* output: data vector */
if (streamdata->stream_index == 0) /* first time decoder is called for this stream */
{
/* read first word from bytestream */
- streamval = *stream_ptr << 24;
- streamval |= *++stream_ptr << 16;
- streamval |= *++stream_ptr << 8;
- streamval |= *++stream_ptr;
+ streamval = (uint32_t)(*stream_ptr) << 24;
+ streamval |= (uint32_t)(*++stream_ptr) << 16;
+ streamval |= (uint32_t)(*++stream_ptr) << 8;
+ streamval |= (uint32_t)(*++stream_ptr);
} else {
streamval = streamdata->streamval;
}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c b/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c
index eeed7ae..777780f 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c
@@ -17,7 +17,7 @@
*/
-#include "arith_routines.h"
+#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
@@ -185,11 +185,18 @@ int WebRtcIsac_DecLogisticMulti2(
int16_t candQ7;
int k;
+ // Position just past the end of the stream. STREAM_SIZE_MAX_60 instead of
+ // STREAM_SIZE_MAX (which is the size of the allocated buffer) because that's
+ // the limit to how much data is filled in.
+ const uint8_t* const stream_end = streamdata->stream + STREAM_SIZE_MAX_60;
+
stream_ptr = streamdata->stream + streamdata->stream_index;
W_upper = streamdata->W_upper;
if (streamdata->stream_index == 0) /* first time decoder is called for this stream */
{
/* read first word from bytestream */
+ if (stream_ptr + 3 >= stream_end)
+ return -1; // Would read out of bounds. Malformed input?
streamval = *stream_ptr << 24;
streamval |= *++stream_ptr << 16;
streamval |= *++stream_ptr << 8;
@@ -277,6 +284,8 @@ int WebRtcIsac_DecLogisticMulti2(
while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */
{
/* read next byte from stream */
+ if (stream_ptr + 1 >= stream_end)
+ return -1; // Would read out of bounds. Malformed input?
streamval = (streamval << 8) | *++stream_ptr;
W_upper <<= 8;
}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc
index 8e0603e..b671002 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_decoder_isac.cc
@@ -8,9 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h"
+#include "modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h"
-#include "webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h"
+#include "modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h"
namespace webrtc {
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc
index 64b9815..b7f2c0b 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac.cc
@@ -8,9 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
+#include "modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
-#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h"
+#include "modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h"
namespace webrtc {
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c
index 82fd053..486cd95 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c
@@ -16,14 +16,14 @@
*
*/
-#include "bandwidth_estimator.h"
-#include "settings.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
-
-#include <assert.h>
#include <math.h>
#include <string.h>
+#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/include/isac.h"
+#include "rtc_base/checks.h"
+
/* array of quantization levels for bottle neck info; Matlab code: */
/* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */
static const float kQRateTableWb[12] =
@@ -159,7 +159,7 @@ int16_t WebRtcIsac_UpdateBandwidthEstimator(
int immediate_set = 0;
int num_pkts_expected;
- assert(!bwest_str->external_bw_info.in_use);
+ RTC_DCHECK(!bwest_str->external_bw_info.in_use);
// We have to adjust the header-rate if the first packet has a
// frame-size different than the initialized value.
@@ -514,7 +514,7 @@ int16_t WebRtcIsac_UpdateUplinkBwImpl(
int16_t index,
enum IsacSamplingRate encoderSamplingFreq)
{
- assert(!bwest_str->external_bw_info.in_use);
+ RTC_DCHECK(!bwest_str->external_bw_info.in_use);
if((index < 0) || (index > 23))
{
@@ -572,7 +572,7 @@ int16_t WebRtcIsac_UpdateUplinkJitter(
BwEstimatorstr* bwest_str,
int32_t index)
{
- assert(!bwest_str->external_bw_info.in_use);
+ RTC_DCHECK(!bwest_str->external_bw_info.in_use);
if((index < 0) || (index > 23))
{
@@ -711,7 +711,7 @@ int32_t WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str)
float jitter_sign;
float bw_adjust;
- assert(!bwest_str->external_bw_info.in_use);
+ RTC_DCHECK(!bwest_str->external_bw_info.in_use);
/* create a value between -1.0 and 1.0 indicating "average sign" of jitter */
jitter_sign = bwest_str->rec_jitter_short_term /
@@ -741,7 +741,7 @@ WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str)
{
int32_t rec_max_delay;
- assert(!bwest_str->external_bw_info.in_use);
+ RTC_DCHECK(!bwest_str->external_bw_info.in_use);
rec_max_delay = (int32_t)(bwest_str->rec_max_delay);
@@ -759,7 +759,7 @@ WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str)
/* Clamp val to the closed interval [min,max]. */
static int32_t clamp(int32_t val, int32_t min, int32_t max) {
- assert(min <= max);
+ RTC_DCHECK_LE(min, max);
return val < min ? min : (val > max ? max : val);
}
@@ -775,24 +775,6 @@ int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str) {
: clamp(bwest_str->send_max_delay_avg, MIN_ISAC_MD, MAX_ISAC_MD);
}
-void WebRtcIsacBw_GetBandwidthInfo(BwEstimatorstr* bwest_str,
- enum IsacSamplingRate decoder_sample_rate_hz,
- IsacBandwidthInfo* bwinfo) {
- assert(!bwest_str->external_bw_info.in_use);
- bwinfo->in_use = 1;
- bwinfo->send_bw_avg = WebRtcIsac_GetUplinkBandwidth(bwest_str);
- bwinfo->send_max_delay_avg = WebRtcIsac_GetUplinkMaxDelay(bwest_str);
- WebRtcIsac_GetDownlinkBwJitIndexImpl(bwest_str, &bwinfo->bottleneck_idx,
- &bwinfo->jitter_info,
- decoder_sample_rate_hz);
-}
-
-void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
- const IsacBandwidthInfo* bwinfo) {
- memcpy(&bwest_str->external_bw_info, bwinfo,
- sizeof bwest_str->external_bw_info);
-}
-
/*
* update long-term average bitrate and amount of data in buffer
* returns minimum payload size (bytes)
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h
index 0704337..221e65f 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h
@@ -16,169 +16,150 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
-#include "structs.h"
-#include "settings.h"
+#include <stddef.h>
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
-#define MIN_ISAC_BW 10000
-#define MIN_ISAC_BW_LB 10000
-#define MIN_ISAC_BW_UB 25000
+#define MIN_ISAC_BW 10000
+#define MIN_ISAC_BW_LB 10000
+#define MIN_ISAC_BW_UB 25000
-#define MAX_ISAC_BW 56000
-#define MAX_ISAC_BW_UB 32000
-#define MAX_ISAC_BW_LB 32000
+#define MAX_ISAC_BW 56000
+#define MAX_ISAC_BW_UB 32000
+#define MAX_ISAC_BW_LB 32000
-#define MIN_ISAC_MD 5
-#define MAX_ISAC_MD 25
+#define MIN_ISAC_MD 5
+#define MAX_ISAC_MD 25
// assumed header size, in bytes; we don't know the exact number
// (header compression may be used)
-#define HEADER_SIZE 35
+#define HEADER_SIZE 35
// Initial Frame-Size, in ms, for Wideband & Super-Wideband Mode
-#define INIT_FRAME_LEN_WB 60
+#define INIT_FRAME_LEN_WB 60
#define INIT_FRAME_LEN_SWB 30
// Initial Bottleneck Estimate, in bits/sec, for
// Wideband & Super-wideband mode
-#define INIT_BN_EST_WB 20e3f
-#define INIT_BN_EST_SWB 56e3f
+#define INIT_BN_EST_WB 20e3f
+#define INIT_BN_EST_SWB 56e3f
// Initial Header rate (header rate depends on frame-size),
// in bits/sec, for Wideband & Super-Wideband mode.
-#define INIT_HDR_RATE_WB \
+#define INIT_HDR_RATE_WB \
((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_WB)
-#define INIT_HDR_RATE_SWB \
+#define INIT_HDR_RATE_SWB \
((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_SWB)
// number of packets in a row for a high rate burst
-#define BURST_LEN 3
+#define BURST_LEN 3
// ms, max time between two full bursts
-#define BURST_INTERVAL 500
+#define BURST_INTERVAL 500
// number of packets in a row for initial high rate burst
-#define INIT_BURST_LEN 5
+#define INIT_BURST_LEN 5
// bits/s, rate for the first BURST_LEN packets
-#define INIT_RATE_WB INIT_BN_EST_WB
-#define INIT_RATE_SWB INIT_BN_EST_SWB
-
+#define INIT_RATE_WB INIT_BN_EST_WB
+#define INIT_RATE_SWB INIT_BN_EST_SWB
#if defined(__cplusplus)
extern "C" {
#endif
- /* This function initializes the struct */
- /* to be called before using the struct for anything else */
- /* returns 0 if everything went fine, -1 otherwise */
- int32_t WebRtcIsac_InitBandwidthEstimator(
- BwEstimatorstr* bwest_str,
- enum IsacSamplingRate encoderSampRate,
- enum IsacSamplingRate decoderSampRate);
-
- /* This function updates the receiving estimate */
- /* Parameters: */
- /* rtp_number - value from RTP packet, from NetEq */
- /* frame length - length of signal frame in ms, from iSAC decoder */
- /* send_ts - value in RTP header giving send time in samples */
- /* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */
- /* pksize - size of packet in bytes, from NetEq */
- /* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
- /* returns 0 if everything went fine, -1 otherwise */
- int16_t WebRtcIsac_UpdateBandwidthEstimator(
- BwEstimatorstr* bwest_str,
- const uint16_t rtp_number,
- const int32_t frame_length,
- const uint32_t send_ts,
- const uint32_t arr_ts,
- const size_t pksize);
-
- /* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */
- int16_t WebRtcIsac_UpdateUplinkBwImpl(
- BwEstimatorstr* bwest_str,
- int16_t Index,
- enum IsacSamplingRate encoderSamplingFreq);
-
- /* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the sending iSAC payload */
- void WebRtcIsac_GetDownlinkBwJitIndexImpl(
- BwEstimatorstr* bwest_str,
- int16_t* bottleneckIndex,
- int16_t* jitterInfo,
- enum IsacSamplingRate decoderSamplingFreq);
-
- /* Returns the bandwidth estimation (in bps) */
- int32_t WebRtcIsac_GetDownlinkBandwidth(
- const BwEstimatorstr *bwest_str);
-
- /* Returns the max delay (in ms) */
- int32_t WebRtcIsac_GetDownlinkMaxDelay(
- const BwEstimatorstr *bwest_str);
-
- /* Returns the bandwidth that iSAC should send with in bps */
- int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str);
-
- /* Returns the max delay value from the other side in ms */
- int32_t WebRtcIsac_GetUplinkMaxDelay(
- const BwEstimatorstr *bwest_str);
-
- /* Fills in an IsacExternalBandwidthInfo struct. */
- void WebRtcIsacBw_GetBandwidthInfo(
- BwEstimatorstr* bwest_str,
- enum IsacSamplingRate decoder_sample_rate_hz,
- IsacBandwidthInfo* bwinfo);
-
- /* Uses the values from an IsacExternalBandwidthInfo struct. */
- void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
- const IsacBandwidthInfo* bwinfo);
-
- /*
- * update amount of data in bottle neck buffer and burst handling
- * returns minimum payload size (bytes)
- */
- int WebRtcIsac_GetMinBytes(
- RateModel* State,
- int StreamSize, /* bytes in bitstream */
- const int FrameLen, /* ms per frame */
- const double BottleNeck, /* bottle neck rate; excl headers (bps) */
- const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
- enum ISACBandwidth bandwidth
- /*,int16_t frequentLargePackets*/);
-
- /*
- * update long-term average bitrate and amount of data in buffer
- */
- void WebRtcIsac_UpdateRateModel(
- RateModel* State,
- int StreamSize, /* bytes in bitstream */
- const int FrameSamples, /* samples per frame */
- const double BottleNeck); /* bottle neck rate; excl headers (bps) */
-
-
- void WebRtcIsac_InitRateModel(
- RateModel *State);
-
- /* Returns the new framelength value (input argument: bottle_neck) */
- int WebRtcIsac_GetNewFrameLength(
- double bottle_neck,
- int current_framelength);
-
- /* Returns the new SNR value (input argument: bottle_neck) */
- double WebRtcIsac_GetSnr(
- double bottle_neck,
- int new_framelength);
-
-
- int16_t WebRtcIsac_UpdateUplinkJitter(
- BwEstimatorstr* bwest_str,
- int32_t index);
+/* This function initializes the struct */
+/* to be called before using the struct for anything else */
+/* returns 0 if everything went fine, -1 otherwise */
+int32_t WebRtcIsac_InitBandwidthEstimator(
+ BwEstimatorstr* bwest_str,
+ enum IsacSamplingRate encoderSampRate,
+ enum IsacSamplingRate decoderSampRate);
+
+/* This function updates the receiving estimate */
+/* Parameters: */
+/* rtp_number - value from RTP packet, from NetEq */
+/* frame length - length of signal frame in ms, from iSAC decoder */
+/* send_ts - value in RTP header giving send time in samples */
+/* arr_ts - value given by timeGetTime() time of arrival in samples of
+ * packet from NetEq */
+/* pksize - size of packet in bytes, from NetEq */
+/* Index - integer (range 0...23) indicating bottle neck & jitter as
+ * estimated by other side */
+/* returns 0 if everything went fine, -1 otherwise */
+int16_t WebRtcIsac_UpdateBandwidthEstimator(BwEstimatorstr* bwest_str,
+ const uint16_t rtp_number,
+ const int32_t frame_length,
+ const uint32_t send_ts,
+ const uint32_t arr_ts,
+ const size_t pksize);
+
+/* Update receiving estimates. Used when we only receive BWE index, no iSAC data
+ * packet. */
+int16_t WebRtcIsac_UpdateUplinkBwImpl(
+ BwEstimatorstr* bwest_str,
+ int16_t Index,
+ enum IsacSamplingRate encoderSamplingFreq);
+
+/* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the
+ * sending iSAC payload */
+void WebRtcIsac_GetDownlinkBwJitIndexImpl(
+ BwEstimatorstr* bwest_str,
+ int16_t* bottleneckIndex,
+ int16_t* jitterInfo,
+ enum IsacSamplingRate decoderSamplingFreq);
+
+/* Returns the bandwidth estimation (in bps) */
+int32_t WebRtcIsac_GetDownlinkBandwidth(const BwEstimatorstr* bwest_str);
+
+/* Returns the max delay (in ms) */
+int32_t WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr* bwest_str);
+
+/* Returns the bandwidth that iSAC should send with in bps */
+int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str);
+
+/* Returns the max delay value from the other side in ms */
+int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str);
+
+/*
+ * update amount of data in bottle neck buffer and burst handling
+ * returns minimum payload size (bytes)
+ */
+int WebRtcIsac_GetMinBytes(
+ RateModel* State,
+ int StreamSize, /* bytes in bitstream */
+ const int FrameLen, /* ms per frame */
+ const double BottleNeck, /* bottle neck rate; excl headers (bps) */
+ const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
+ enum ISACBandwidth bandwidth
+ /*,int16_t frequentLargePackets*/);
+
+/*
+ * update long-term average bitrate and amount of data in buffer
+ */
+void WebRtcIsac_UpdateRateModel(
+ RateModel* State,
+ int StreamSize, /* bytes in bitstream */
+ const int FrameSamples, /* samples per frame */
+ const double BottleNeck); /* bottle neck rate; excl headers (bps) */
+
+void WebRtcIsac_InitRateModel(RateModel* State);
+
+/* Returns the new framelength value (input argument: bottle_neck) */
+int WebRtcIsac_GetNewFrameLength(double bottle_neck, int current_framelength);
+
+/* Returns the new SNR value (input argument: bottle_neck) */
+double WebRtcIsac_GetSnr(double bottle_neck, int new_framelength);
+
+int16_t WebRtcIsac_UpdateUplinkJitter(BwEstimatorstr* bwest_str, int32_t index);
#if defined(__cplusplus)
}
#endif
-
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ \
+ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/codec.h b/webrtc/modules/audio_coding/codecs/isac/main/source/codec.h
index 7ef64b5..a7c7ddc 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/codec.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/codec.h
@@ -16,18 +16,22 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
-#include "structs.h"
+#include <stddef.h>
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "modules/third_party/fft/fft.h"
void WebRtcIsac_ResetBitstream(Bitstr* bit_stream);
-int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str, Bitstr* streamdata,
+int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str,
+ Bitstr* streamdata,
size_t packet_size,
uint16_t rtp_seq_number,
- uint32_t send_ts, uint32_t arr_ts,
+ uint32_t send_ts,
+ uint32_t arr_ts,
enum IsacSamplingRate encoderSampRate,
enum IsacSamplingRate decoderSampRate);
@@ -37,7 +41,8 @@ int WebRtcIsac_DecodeLb(const TransformTables* transform_tables,
int16_t* current_framesamples,
int16_t isRCUPayload);
-int WebRtcIsac_DecodeRcuLb(float* signal_out, ISACLBDecStruct* ISACdec_obj,
+int WebRtcIsac_DecodeRcuLb(float* signal_out,
+ ISACLBDecStruct* ISACdec_obj,
int16_t* current_framesamples);
int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
@@ -47,15 +52,20 @@ int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
int16_t bottleneckIndex);
int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj,
- Bitstr* ISACBitStr_obj, int BWnumber,
+ Bitstr* ISACBitStr_obj,
+ int BWnumber,
float scale);
int WebRtcIsac_EncodeStoredDataUb(
- const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, Bitstr* bitStream,
- int32_t jitterInfo, float scale, enum ISACBandwidth bandwidth);
+ const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
+ Bitstr* bitStream,
+ int32_t jitterInfo,
+ float scale,
+ enum ISACBandwidth bandwidth);
int16_t WebRtcIsac_GetRedPayloadUb(
- const ISACUBSaveEncDataStruct* ISACSavedEncObj, Bitstr* bitStreamObj,
+ const ISACUBSaveEncDataStruct* ISACSavedEncObj,
+ Bitstr* bitStreamObj,
enum ISACBandwidth bandwidth);
/******************************************************************************
@@ -81,7 +91,6 @@ int16_t WebRtcIsac_RateAllocation(int32_t inRateBitPerSec,
double* rateUBBitPerSec,
enum ISACBandwidth* bandwidthKHz);
-
/******************************************************************************
* WebRtcIsac_DecodeUb16()
*
@@ -166,15 +175,8 @@ int WebRtcIsac_EncodeUb12(const TransformTables* transform_tables,
void WebRtcIsac_InitMasking(MaskFiltstr* maskdata);
-void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata);
-
void WebRtcIsac_InitPostFilterbank(PostFiltBankstr* postfiltdata);
-void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata);
-
-void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State);
-
-
/**************************** transform functions ****************************/
void WebRtcIsac_InitTransform(TransformTables* tables);
@@ -193,41 +195,29 @@ void WebRtcIsac_Spec2time(const TransformTables* tables,
double* outre2,
FFTstr* fftstr_obj);
-/******************************* filter functions ****************************/
-
-void WebRtcIsac_AllPoleFilter(double* InOut, double* Coef, size_t lengthInOut,
- int orderCoef);
-
-void WebRtcIsac_AllZeroFilter(double* In, double* Coef, size_t lengthInOut,
- int orderCoef, double* Out);
-
-void WebRtcIsac_ZeroPoleFilter(double* In, double* ZeroCoef, double* PoleCoef,
- size_t lengthInOut, int orderCoef, double* Out);
-
-
/***************************** filterbank functions **************************/
-void WebRtcIsac_SplitAndFilterFloat(float* in, float* LP, float* HP,
- double* LP_la, double* HP_la,
- PreFiltBankstr* prefiltdata);
-
-
-void WebRtcIsac_FilterAndCombineFloat(float* InLP, float* InHP, float* Out,
+void WebRtcIsac_FilterAndCombineFloat(float* InLP,
+ float* InHP,
+ float* Out,
PostFiltBankstr* postfiltdata);
-
/************************* normalized lattice filters ************************/
-void WebRtcIsac_NormLatticeFilterMa(int orderCoef, float* stateF, float* stateG,
- float* lat_in, double* filtcoeflo,
+void WebRtcIsac_NormLatticeFilterMa(int orderCoef,
+ float* stateF,
+ float* stateG,
+ float* lat_in,
+ double* filtcoeflo,
double* lat_out);
-void WebRtcIsac_NormLatticeFilterAr(int orderCoef, float* stateF, float* stateG,
- double* lat_in, double* lo_filt_coef,
+void WebRtcIsac_NormLatticeFilterAr(int orderCoef,
+ float* stateF,
+ float* stateG,
+ double* lat_in,
+ double* lo_filt_coef,
float* lat_out);
void WebRtcIsac_Dir2Lat(double* a, int orderCoef, float* sth, float* cth);
-void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order);
-
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c b/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c
index ebef595..1bb0827 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/crc.c
@@ -8,9 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "crc.h"
#include <stdlib.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+#include "modules/audio_coding/codecs/isac/main/source/crc.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
#define POLYNOMIAL 0x04c11db7L
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/crc.h b/webrtc/modules/audio_coding/codecs/isac/main/source/crc.h
index 09583df..f031019 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/crc.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/crc.h
@@ -15,10 +15,10 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
-#include "webrtc/typedefs.h"
+#include <stdint.h>
/****************************************************************************
* WebRtcIsac_GetCrc(...)
@@ -36,11 +36,6 @@
* -1 - Error
*/
-int WebRtcIsac_GetCrc(
- const int16_t* encoded,
- int no_of_word8s,
- uint32_t* crc);
+int WebRtcIsac_GetCrc(const int16_t* encoded, int no_of_word8s, uint32_t* crc);
-
-
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c b/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c
index e925efb..6e114e4 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/decode.c
@@ -18,18 +18,17 @@
*
*/
-
-#include "codec.h"
-#include "entropy_coding.h"
-#include "pitch_estimator.h"
-#include "bandwidth_estimator.h"
-#include "structs.h"
-#include "settings.h"
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
/*
* function to decode the bitstream
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c b/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c
index 019cc89..89d970f 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/decode_bwe.c
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "structs.h"
-#include "bandwidth_estimator.h"
-#include "entropy_coding.h"
-#include "codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
int
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c b/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c
index 3f1912b..bf92d02 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/encode.c
@@ -21,20 +21,22 @@
#include <string.h>
#include <stdio.h>
-#include "structs.h"
-#include "codec.h"
-#include "pitch_estimator.h"
-#include "entropy_coding.h"
-#include "arith_routines.h"
-#include "pitch_gain_tables.h"
-#include "pitch_lag_tables.h"
-#include "spectrum_ar_model_tables.h"
-#include "lpc_tables.h"
-#include "lpc_analysis.h"
-#include "bandwidth_estimator.h"
-#include "lpc_shape_swb12_tables.h"
-#include "lpc_shape_swb16_tables.h"
-#include "lpc_gain_swb_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
+#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_analysis.h"
+#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
#define UB_LOOKAHEAD 24
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c b/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c
index 12a263d..7b02e64 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c
@@ -16,17 +16,15 @@
*
*/
-#include "encode_lpc_swb.h"
-
#include <math.h>
#include <stdio.h>
#include <string.h>
-#include "lpc_gain_swb_tables.h"
-#include "lpc_shape_swb12_tables.h"
-#include "lpc_shape_swb16_tables.h"
-#include "settings.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
/******************************************************************************
* WebRtcIsac_RemoveLarMean()
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h b/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h
index 3dd2311..8bc3d75 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h
@@ -16,12 +16,11 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
-#include "settings.h"
-#include "structs.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
/******************************************************************************
* WebRtcIsac_RemoveLarMean()
@@ -39,9 +38,7 @@
*
*
*/
-int16_t WebRtcIsac_RemoveLarMean(
- double* lar,
- int16_t bandwidth);
+int16_t WebRtcIsac_RemoveLarMean(double* lar, int16_t bandwidth);
/******************************************************************************
* WebRtcIsac_DecorrelateIntraVec()
@@ -59,11 +56,9 @@ int16_t WebRtcIsac_RemoveLarMean(
* Output:
* -out : decorrelated LAR vectors.
*/
-int16_t WebRtcIsac_DecorrelateIntraVec(
- const double* inLAR,
- double* out,
- int16_t bandwidth);
-
+int16_t WebRtcIsac_DecorrelateIntraVec(const double* inLAR,
+ double* out,
+ int16_t bandwidth);
/******************************************************************************
* WebRtcIsac_DecorrelateInterVec()
@@ -82,11 +77,9 @@ int16_t WebRtcIsac_DecorrelateIntraVec(
* Output:
* -out : decorrelated LAR vectors.
*/
-int16_t WebRtcIsac_DecorrelateInterVec(
- const double* data,
- double* out,
- int16_t bandwidth);
-
+int16_t WebRtcIsac_DecorrelateInterVec(const double* data,
+ double* out,
+ int16_t bandwidth);
/******************************************************************************
* WebRtcIsac_QuantizeUncorrLar()
@@ -102,11 +95,7 @@ int16_t WebRtcIsac_DecorrelateInterVec(
* -data : quantized version of the input.
* -idx : pointer to quantization indices.
*/
-double WebRtcIsac_QuantizeUncorrLar(
- double* data,
- int* idx,
- int16_t bandwidth);
-
+double WebRtcIsac_QuantizeUncorrLar(double* data, int* idx, int16_t bandwidth);
/******************************************************************************
* WebRtcIsac_CorrelateIntraVec()
@@ -121,11 +110,9 @@ double WebRtcIsac_QuantizeUncorrLar(
* Output:
* -out : correlated parametrs.
*/
-int16_t WebRtcIsac_CorrelateIntraVec(
- const double* data,
- double* out,
- int16_t bandwidth);
-
+int16_t WebRtcIsac_CorrelateIntraVec(const double* data,
+ double* out,
+ int16_t bandwidth);
/******************************************************************************
* WebRtcIsac_CorrelateInterVec()
@@ -140,17 +127,15 @@ int16_t WebRtcIsac_CorrelateIntraVec(
* Output:
* -out : correlated parametrs.
*/
-int16_t WebRtcIsac_CorrelateInterVec(
- const double* data,
- double* out,
- int16_t bandwidth);
-
+int16_t WebRtcIsac_CorrelateInterVec(const double* data,
+ double* out,
+ int16_t bandwidth);
/******************************************************************************
* WebRtcIsac_AddLarMean()
*
* This is the inverse of WebRtcIsac_RemoveLarMean()
- *
+ *
* Input:
* -data : pointer to mean-removed LAR:s.
* -bandwidth : indicates if the given LAR vectors belong
@@ -159,10 +144,7 @@ int16_t WebRtcIsac_CorrelateInterVec(
* Output:
* -data : pointer to LARs.
*/
-int16_t WebRtcIsac_AddLarMean(
- double* data,
- int16_t bandwidth);
-
+int16_t WebRtcIsac_AddLarMean(double* data, int16_t bandwidth);
/******************************************************************************
* WebRtcIsac_DequantizeLpcParam()
@@ -177,11 +159,9 @@ int16_t WebRtcIsac_AddLarMean(
* Output:
* -out : pointer to quantized values.
*/
-int16_t WebRtcIsac_DequantizeLpcParam(
- const int* idx,
- double* out,
- int16_t bandwidth);
-
+int16_t WebRtcIsac_DequantizeLpcParam(const int* idx,
+ double* out,
+ int16_t bandwidth);
/******************************************************************************
* WebRtcIsac_ToLogDomainRemoveMean()
@@ -194,9 +174,7 @@ int16_t WebRtcIsac_DequantizeLpcParam(
* Output:
* -lpcGain : mean-removed in log domain.
*/
-int16_t WebRtcIsac_ToLogDomainRemoveMean(
- double* lpGains);
-
+int16_t WebRtcIsac_ToLogDomainRemoveMean(double* lpGains);
/******************************************************************************
* WebRtcIsac_DecorrelateLPGain()
@@ -210,16 +188,13 @@ int16_t WebRtcIsac_ToLogDomainRemoveMean(
* Output:
* -out : decorrelated parameters.
*/
-int16_t WebRtcIsac_DecorrelateLPGain(
- const double* data,
- double* out);
-
+int16_t WebRtcIsac_DecorrelateLPGain(const double* data, double* out);
/******************************************************************************
* WebRtcIsac_QuantizeLpcGain()
*
* Quantize the decorrelated log-domain gains.
- *
+ *
* Input:
* -lpcGain : uncorrelated LPC gains.
*
@@ -227,10 +202,7 @@ int16_t WebRtcIsac_DecorrelateLPGain(
* -idx : quantization indices
* -lpcGain : quantized value of the inpt.
*/
-double WebRtcIsac_QuantizeLpcGain(
- double* lpGains,
- int* idx);
-
+double WebRtcIsac_QuantizeLpcGain(double* lpGains, int* idx);
/******************************************************************************
* WebRtcIsac_DequantizeLpcGain()
@@ -243,10 +215,7 @@ double WebRtcIsac_QuantizeLpcGain(
* Output:
* -lpcGains : quantized values of the given parametes.
*/
-int16_t WebRtcIsac_DequantizeLpcGain(
- const int* idx,
- double* lpGains);
-
+int16_t WebRtcIsac_DequantizeLpcGain(const int* idx, double* lpGains);
/******************************************************************************
* WebRtcIsac_CorrelateLpcGain()
@@ -259,10 +228,7 @@ int16_t WebRtcIsac_DequantizeLpcGain(
* Output:
* -out : correlated parameters.
*/
-int16_t WebRtcIsac_CorrelateLpcGain(
- const double* data,
- double* out);
-
+int16_t WebRtcIsac_CorrelateLpcGain(const double* data, double* out);
/******************************************************************************
* WebRtcIsac_AddMeanToLinearDomain()
@@ -275,8 +241,6 @@ int16_t WebRtcIsac_CorrelateLpcGain(
* Output:
* -lpcGain : LPC gain in normal domain.
*/
-int16_t WebRtcIsac_AddMeanToLinearDomain(
- double* lpcGains);
-
+int16_t WebRtcIsac_AddMeanToLinearDomain(double* lpcGains);
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c b/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c
index bc65396..6692a51 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c
@@ -17,19 +17,19 @@
*/
-#include "entropy_coding.h"
-#include "settings.h"
-#include "arith_routines.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "spectrum_ar_model_tables.h"
-#include "lpc_tables.h"
-#include "pitch_gain_tables.h"
-#include "pitch_lag_tables.h"
-#include "encode_lpc_swb.h"
-#include "lpc_shape_swb12_tables.h"
-#include "lpc_shape_swb16_tables.h"
-#include "lpc_gain_swb_tables.h"
-#include "os_specific_inline.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
+#include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
#include <math.h>
#include <string.h>
@@ -42,7 +42,7 @@ static const uint16_t kOneBitEqualProbCdf[3] = {
0, 32768, 65535 };
/* Pointer to cdf array for encoder bandwidth (12 vs 16 kHz) indicator. */
-static const uint16_t* kOneBitEqualProbCdf_ptr[1] = {
+static const uint16_t* const kOneBitEqualProbCdf_ptr[1] = {
kOneBitEqualProbCdf };
/*
@@ -96,7 +96,7 @@ static void FindInvArSpec(const int16_t* ARCoefQ12,
const int32_t gainQ10,
int32_t* CurveQ16) {
int32_t CorrQ11[AR_ORDER + 1];
- int32_t sum, tmpGain;
+ int64_t sum, tmpGain;
int32_t diffQ16[FRAMESAMPLES / 8];
const int16_t* CS_ptrQ9;
int k, n;
@@ -162,9 +162,9 @@ static void FindInvArSpec(const int16_t* ARCoefQ12,
}
for (k = 0; k < FRAMESAMPLES / 8; k++) {
- CurveQ16[FRAMESAMPLES_QUARTER - 1 - k] = CurveQ16[k] -
- (diffQ16[k] << shftVal);
- CurveQ16[k] += diffQ16[k] << shftVal;
+ int32_t diff_q16_shifted = (int32_t)((uint32_t)(diffQ16[k]) << shftVal);
+ CurveQ16[FRAMESAMPLES_QUARTER - 1 - k] = CurveQ16[k] - diff_q16_shifted;
+ CurveQ16[k] += diff_q16_shifted;
}
}
@@ -182,13 +182,13 @@ static void GenerateDitherQ7Lb(int16_t* bufQ7, uint32_t seed,
/* Fixed-point dither sample between -64 and 64 (Q7). */
/* dither = seed * 128 / 4294967295 */
- dither1_Q7 = (int16_t)(((int)seed + 16777216) >> 25);
+ dither1_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
/* New random unsigned int. */
seed = (seed * 196314165) + 907633515;
/* Fixed-point dither sample between -64 and 64. */
- dither2_Q7 = (int16_t)(((int)seed + 16777216) >> 25);
+ dither2_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
shft = (seed >> 25) & 15;
if (shft < 5) {
@@ -214,7 +214,7 @@ static void GenerateDitherQ7Lb(int16_t* bufQ7, uint32_t seed,
seed = (seed * 196314165) + 907633515;
/* Fixed-point dither sample between -64 and 64. */
- dither1_Q7 = (int16_t)(((int)seed + 16777216) >> 25);
+ dither1_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
/* Dither sample is placed in either even or odd index. */
shft = (seed >> 25) & 1; /* Either 0 or 1 */
@@ -254,7 +254,7 @@ static void GenerateDitherQ7LbUB(
/* Fixed-point dither sample between -64 and 64 (Q7). */
/* bufQ7 = seed * 128 / 4294967295 */
- bufQ7[k] = (int16_t)(((int)seed + 16777216) >> 25);
+ bufQ7[k] = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
/* Scale by 0.35. */
bufQ7[k] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(bufQ7[k], 2048, 13);
@@ -1843,7 +1843,7 @@ static const uint16_t kBwCdf[25] = {
62804, 65535 };
/* pointer to cdf array for estimated bandwidth */
-static const uint16_t* kBwCdfPtr[1] = { kBwCdf };
+static const uint16_t* const kBwCdfPtr[1] = { kBwCdf };
/* initial cdf index for decoder of estimated bandwidth*/
static const uint16_t kBwInitIndex[1] = { 7 };
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h b/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h
index d715d86..6c2b8d3 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h
@@ -16,11 +16,11 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
-#include "settings.h"
-#include "structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
/******************************************************************************
* WebRtcIsac_DecodeSpec()
@@ -46,8 +46,11 @@
* Return value : < 0 if an error occures
* 0 if succeeded.
*/
-int WebRtcIsac_DecodeSpec(Bitstr* streamdata, int16_t AvgPitchGain_Q12,
- enum ISACBand band, double* fr, double* fi);
+int WebRtcIsac_DecodeSpec(Bitstr* streamdata,
+ int16_t AvgPitchGain_Q12,
+ enum ISACBand band,
+ double* fr,
+ double* fi);
/******************************************************************************
* WebRtcIsac_EncodeSpec()
@@ -72,24 +75,31 @@ int WebRtcIsac_DecodeSpec(Bitstr* streamdata, int16_t AvgPitchGain_Q12,
* Return value : < 0 if an error occures
* 0 if succeeded.
*/
-int WebRtcIsac_EncodeSpec(const int16_t* fr, const int16_t* fi,
- int16_t AvgPitchGain_Q12, enum ISACBand band,
+int WebRtcIsac_EncodeSpec(const int16_t* fr,
+ const int16_t* fi,
+ int16_t AvgPitchGain_Q12,
+ enum ISACBand band,
Bitstr* streamdata);
/* decode & dequantize LPC Coef */
int WebRtcIsac_DecodeLpcCoef(Bitstr* streamdata, double* LPCCoef);
-int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata, double* lpcVecs,
+int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata,
+ double* lpcVecs,
double* percepFilterGains,
int16_t bandwidth);
-int WebRtcIsac_DecodeLpc(Bitstr* streamdata, double* LPCCoef_lo,
+int WebRtcIsac_DecodeLpc(Bitstr* streamdata,
+ double* LPCCoef_lo,
double* LPCCoef_hi);
/* quantize & code LPC Coef */
-void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo, double* LPCCoef_hi,
- Bitstr* streamdata, IsacSaveEncoderData* encData);
+void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo,
+ double* LPCCoef_hi,
+ Bitstr* streamdata,
+ IsacSaveEncoderData* encData);
-void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi,
+void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo,
+ double* LPCCoef_hi,
Bitstr* streamdata,
IsacSaveEncoderData* encData);
@@ -126,7 +136,8 @@ void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi,
* Return value : 0 if encoding is successful,
* <0 if failed to encode.
*/
-int16_t WebRtcIsac_EncodeLpcUB(double* lpcCoeff, Bitstr* streamdata,
+int16_t WebRtcIsac_EncodeLpcUB(double* lpcCoeff,
+ Bitstr* streamdata,
double* interpolLPCCoeff,
int16_t bandwidth,
ISACUBSaveEncDataStruct* encData);
@@ -184,9 +195,9 @@ void WebRtcIsac_EncodePitchLag(double* PitchLags,
Bitstr* streamdata,
IsacSaveEncoderData* encData);
-int WebRtcIsac_DecodePitchGain(Bitstr* streamdata,
- int16_t* PitchGain_Q12);
-int WebRtcIsac_DecodePitchLag(Bitstr* streamdata, int16_t* PitchGain_Q12,
+int WebRtcIsac_DecodePitchGain(Bitstr* streamdata, int16_t* PitchGain_Q12);
+int WebRtcIsac_DecodePitchLag(Bitstr* streamdata,
+ int16_t* PitchGain_Q12,
double* PitchLag);
int WebRtcIsac_DecodeFrameLen(Bitstr* streamdata, int16_t* framelength);
@@ -200,10 +211,10 @@ void WebRtcIsac_Poly2Rc(double* a, int N, double* RC);
/* Step-up */
void WebRtcIsac_Rc2Poly(double* RC, int N, double* a);
-void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi,
+void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo,
+ double* LPCCoef_hi,
int* index_g);
-
/******************************************************************************
* WebRtcIsac_EncodeLpcGainUb()
* Encode LPC gains of sub-Frames.
@@ -220,10 +231,10 @@ void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi,
* - lpcGainIndex : quantization indices for lpc gains, these will
* be stored to be used for FEC.
*/
-void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata,
+void WebRtcIsac_EncodeLpcGainUb(double* lpGains,
+ Bitstr* streamdata,
int* lpcGainIndex);
-
/******************************************************************************
* WebRtcIsac_EncodeLpcGainUb()
* Store LPC gains of sub-Frames in 'streamdata'.
@@ -239,7 +250,6 @@ void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata,
*/
void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata);
-
/******************************************************************************
* WebRtcIsac_DecodeLpcGainUb()
* Decode the LPC gain of sub-frames.
@@ -257,7 +267,6 @@ void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata);
*/
int16_t WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata);
-
/******************************************************************************
* WebRtcIsac_EncodeBandwidth()
* Encode if the bandwidth of encoded audio is 0-12 kHz or 0-16 kHz.
@@ -277,7 +286,6 @@ int16_t WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata);
int16_t WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth,
Bitstr* streamData);
-
/******************************************************************************
* WebRtcIsac_DecodeBandwidth()
* Decode the bandwidth of the encoded audio, i.e. if the bandwidth is 0-12 kHz
@@ -298,7 +306,6 @@ int16_t WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth,
int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData,
enum ISACBandwidth* bandwidth);
-
/******************************************************************************
* WebRtcIsac_EncodeJitterInfo()
* Decode the jitter information.
@@ -316,9 +323,7 @@ int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData,
* Return value : 0 if succeeded.
* <0 if failed.
*/
-int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex,
- Bitstr* streamData);
-
+int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex, Bitstr* streamData);
/******************************************************************************
* WebRtcIsac_DecodeJitterInfo()
@@ -337,7 +342,6 @@ int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex,
* Return value : 0 if succeeded.
* <0 if failed.
*/
-int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData,
- int32_t* jitterInfo);
+int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData, int32_t* jitterInfo);
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.c b/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.c
index d47eb1f..a4f297c 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.c
@@ -13,16 +13,14 @@
#ifdef WEBRTC_ANDROID
#include <stdlib.h>
#endif
-#include "pitch_estimator.h"
-#include "lpc_analysis.h"
-#include "codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
-
-void WebRtcIsac_AllPoleFilter(double* InOut,
- double* Coef,
- size_t lengthInOut,
- int orderCoef) {
+static void WebRtcIsac_AllPoleFilter(double* InOut,
+ double* Coef,
+ size_t lengthInOut,
+ int orderCoef) {
/* the state of filter is assumed to be in InOut[-1] to InOut[-orderCoef] */
double scal;
double sum;
@@ -55,12 +53,11 @@ void WebRtcIsac_AllPoleFilter(double* InOut,
}
}
-
-void WebRtcIsac_AllZeroFilter(double* In,
- double* Coef,
- size_t lengthInOut,
- int orderCoef,
- double* Out) {
+static void WebRtcIsac_AllZeroFilter(double* In,
+ double* Coef,
+ size_t lengthInOut,
+ int orderCoef,
+ double* Out) {
/* the state of filter is assumed to be in In[-1] to In[-orderCoef] */
size_t n;
@@ -80,13 +77,12 @@ void WebRtcIsac_AllZeroFilter(double* In,
}
}
-
-void WebRtcIsac_ZeroPoleFilter(double* In,
- double* ZeroCoef,
- double* PoleCoef,
- size_t lengthInOut,
- int orderCoef,
- double* Out) {
+static void WebRtcIsac_ZeroPoleFilter(double* In,
+ double* ZeroCoef,
+ double* PoleCoef,
+ size_t lengthInOut,
+ int orderCoef,
+ double* Out) {
/* the state of the zero section is assumed to be in In[-1] to In[-orderCoef] */
/* the state of the pole section is assumed to be in Out[-1] to Out[-orderCoef] */
@@ -115,8 +111,10 @@ void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order) {
}
-
-void WebRtcIsac_BwExpand(double* out, double* in, double coef, size_t length) {
+static void WebRtcIsac_BwExpand(double* out,
+ double* in,
+ double coef,
+ size_t length) {
size_t i;
double chirp;
@@ -195,69 +193,3 @@ void WebRtcIsac_WeightingFilter(const double* in,
memcpy(weiout, weoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN);
memcpy(whiout, whoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN);
}
-
-
-static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826};
-static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744};
-
-
-void WebRtcIsac_AllpassFilterForDec(double* InOut,
- const double* APSectionFactors,
- size_t lengthInOut,
- double* FilterState) {
- //This performs all-pass filtering--a series of first order all-pass sections are used
- //to filter the input in a cascade manner.
- size_t n,j;
- double temp;
- for (j=0; j<ALLPASSSECTIONS; j++){
- for (n=0;n<lengthInOut;n+=2){
- temp = InOut[n]; //store input
- InOut[n] = FilterState[j] + APSectionFactors[j]*temp;
- FilterState[j] = -APSectionFactors[j]*InOut[n] + temp;
- }
- }
-}
-
-void WebRtcIsac_DecimateAllpass(const double* in,
- double* state_in,
- size_t N,
- double* out) {
- size_t n;
- double data_vec[PITCH_FRAME_LEN];
-
- /* copy input */
- memcpy(data_vec+1, in, sizeof(double) * (N-1));
-
- data_vec[0] = state_in[2*ALLPASSSECTIONS]; //the z^(-1) state
- state_in[2*ALLPASSSECTIONS] = in[N-1];
-
- WebRtcIsac_AllpassFilterForDec(data_vec+1, APupper, N, state_in);
- WebRtcIsac_AllpassFilterForDec(data_vec, APlower, N, state_in+ALLPASSSECTIONS);
-
- for (n=0;n<N/2;n++)
- out[n] = data_vec[2*n] + data_vec[2*n+1];
-
-}
-
-
-/* create high-pass filter ocefficients
- * z = 0.998 * exp(j*2*pi*35/8000);
- * p = 0.94 * exp(j*2*pi*140/8000);
- * HP_b = [1, -2*real(z), abs(z)^2];
- * HP_a = [1, -2*real(p), abs(p)^2]; */
-static const double a_coef[2] = { 1.86864659625574, -0.88360000000000};
-static const double b_coef[2] = {-1.99524591718270, 0.99600400000000};
-
-/* second order high-pass filter */
-void WebRtcIsac_Highpass(const double* in,
- double* out,
- double* state,
- size_t N) {
- size_t k;
-
- for (k=0; k<N; k++) {
- *out = *in + state[1];
- state[1] = state[0] + b_coef[0] * *in + a_coef[0] * *out;
- state[0] = b_coef[1] * *in++ + a_coef[1] * *out++;
- }
-}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.h b/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.h
new file mode 100644
index 0000000..48a9b74
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/filter_functions.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
+
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+
+void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order);
+
+void WebRtcIsac_WeightingFilter(const double* in,
+ double* weiout,
+ double* whiout,
+ WeightFiltstr* wfdata);
+
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c b/webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c
deleted file mode 100644
index 0f844af..0000000
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.
- */
-
-/* filterbank_tables.c*/
-/* This file contains variables that are used in filterbanks.c*/
-
-#include "filterbank_tables.h"
-#include "settings.h"
-
-/* The composite all-pass filter factors */
-const float WebRtcIsac_kCompositeApFactorsFloat[4] = {
- 0.03470000000000f, 0.15440000000000f, 0.38260000000000f, 0.74400000000000f};
-
-/* The upper channel all-pass filter factors */
-const float WebRtcIsac_kUpperApFactorsFloat[2] = {
- 0.03470000000000f, 0.38260000000000f};
-
-/* The lower channel all-pass filter factors */
-const float WebRtcIsac_kLowerApFactorsFloat[2] = {
- 0.15440000000000f, 0.74400000000000f};
-
-/* The matrix for transforming the backward composite state to upper channel state */
-const float WebRtcIsac_kTransform1Float[8] = {
- -0.00158678506084f, 0.00127157815343f, -0.00104805672709f, 0.00084837248079f,
- 0.00134467983258f, -0.00107756549387f, 0.00088814793277f, -0.00071893072525f};
-
-/* The matrix for transforming the backward composite state to lower channel state */
-const float WebRtcIsac_kTransform2Float[8] = {
- -0.00170686041697f, 0.00136780109829f, -0.00112736532350f, 0.00091257055385f,
- 0.00103094281812f, -0.00082615076557f, 0.00068092756088f, -0.00055119165484f};
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.h b/webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.h
deleted file mode 100644
index e8fda5e..0000000
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/filterbank_tables.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * filterbank_tables.h
- *
- * Header file for variables that are defined in
- * filterbank_tables.c.
- *
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_
-
-#include "structs.h"
-
-/********************* Coefficient Tables ************************/
-/* The number of composite all-pass filter factors */
-#define NUMBEROFCOMPOSITEAPSECTIONS 4
-
-/* The number of all-pass filter factors in an upper or lower channel*/
-#define NUMBEROFCHANNELAPSECTIONS 2
-
-/* The composite all-pass filter factors */
-extern const float WebRtcIsac_kCompositeApFactorsFloat[4];
-
-/* The upper channel all-pass filter factors */
-extern const float WebRtcIsac_kUpperApFactorsFloat[2];
-
-/* The lower channel all-pass filter factors */
-extern const float WebRtcIsac_kLowerApFactorsFloat[2];
-
-/* The matrix for transforming the backward composite state to upper channel state */
-extern const float WebRtcIsac_kTransform1Float[8];
-
-/* The matrix for transforming the backward composite state to lower channel state */
-extern const float WebRtcIsac_kTransform2Float[8];
-
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/filterbanks.c b/webrtc/modules/audio_coding/codecs/isac/main/source/filterbanks.c
index 671fd32..d57b550 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/filterbanks.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/filterbanks.c
@@ -18,241 +18,9 @@
*
*/
-#include "settings.h"
-#include "filterbank_tables.h"
-#include "codec.h"
-
-/* This function performs all-pass filtering--a series of first order all-pass
- * sections are used to filter the input in a cascade manner.
- * The input is overwritten!!
- */
-static void WebRtcIsac_AllPassFilter2Float(float *InOut, const float *APSectionFactors,
- int lengthInOut, int NumberOfSections,
- float *FilterState)
-{
- int n, j;
- float temp;
- for (j=0; j<NumberOfSections; j++){
- for (n=0;n<lengthInOut;n++){
- temp = FilterState[j] + APSectionFactors[j] * InOut[n];
- FilterState[j] = -APSectionFactors[j] * temp + InOut[n];
- InOut[n] = temp;
- }
- }
-}
-
-/* HPstcoeff_in = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
-static const float kHpStCoefInFloat[4] =
-{-1.94895953203325f, 0.94984516000000f, -0.05101826139794f, 0.05015484000000f};
-
-/* Function WebRtcIsac_SplitAndFilter
- * This function creates low-pass and high-pass decimated versions of part of
- the input signal, and part of the signal in the input 'lookahead buffer'.
-
- INPUTS:
- in: a length FRAMESAMPLES array of input samples
- prefiltdata: input data structure containing the filterbank states
- and lookahead samples from the previous encoding
- iteration.
- OUTPUTS:
- LP: a FRAMESAMPLES_HALF array of low-pass filtered samples that
- have been phase equalized. The first QLOOKAHEAD samples are
- based on the samples in the two prefiltdata->INLABUFx arrays
- each of length QLOOKAHEAD.
- The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
- on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
- array in[].
- HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that
- have been phase equalized. The first QLOOKAHEAD samples are
- based on the samples in the two prefiltdata->INLABUFx arrays
- each of length QLOOKAHEAD.
- The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
- on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
- array in[].
-
- LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples.
- These samples are not phase equalized. They are computed
- from the samples in the in[] array.
- HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples
- that are not phase equalized. They are computed from
- the in[] vector.
- prefiltdata: this input data structure's filterbank state and
- lookahead sample buffers are updated for the next
- encoding iteration.
-*/
-void WebRtcIsac_SplitAndFilterFloat(float *pin, float *LP, float *HP,
- double *LP_la, double *HP_la,
- PreFiltBankstr *prefiltdata)
-{
- int k,n;
- float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
- float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
- float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS];
- float tempinoutvec[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
- float tempin_ch1[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
- float tempin_ch2[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
- float in[FRAMESAMPLES];
- float ftmp;
-
-
- /* High pass filter */
-
- for (k=0;k<FRAMESAMPLES;k++) {
- in[k] = pin[k] + kHpStCoefInFloat[2] * prefiltdata->HPstates_float[0] +
- kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1];
- ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] -
- kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1];
- prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0];
- prefiltdata->HPstates_float[0] = ftmp;
- }
-
- /*
- % backwards all-pass filtering to obtain zero-phase
- [tmp1(N2+LA:-1:LA+1, 1), state1] = filter(Q.coef, Q.coef(end:-1:1), in(N:-2:2));
- tmp1(LA:-1:1) = filter(Q.coef, Q.coef(end:-1:1), Q.LookAheadBuf1, state1);
- Q.LookAheadBuf1 = in(N:-2:N-2*LA+2);
- */
- /*Backwards all-pass filter the odd samples of the input (upper channel)
- to eventually obtain zero phase. The composite all-pass filter (comprised of both
- the upper and lower channel all-pass filsters in series) is used for the
- filtering. */
-
- /* First Channel */
-
- /*initial state of composite filter is zero */
- for (k=0;k<NUMBEROFCOMPOSITEAPSECTIONS;k++){
- CompositeAPFilterState[k] = 0.0;
- }
- /* put every other sample of input into a temporary vector in reverse (backward) order*/
- for (k=0;k<FRAMESAMPLES_HALF;k++) {
- tempinoutvec[k] = in[FRAMESAMPLES-1-2*k];
- }
-
- /* now all-pass filter the backwards vector. Output values overwrite the input vector. */
- WebRtcIsac_AllPassFilter2Float(tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat,
- FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
-
- /* save the backwards filtered output for later forward filtering,
- but write it in forward order*/
- for (k=0;k<FRAMESAMPLES_HALF;k++) {
- tempin_ch1[FRAMESAMPLES_HALF+QLOOKAHEAD-1-k] = tempinoutvec[k];
- }
-
- /* save the backwards filter state becaue it will be transformed
- later into a forward state */
- for (k=0; k<NUMBEROFCOMPOSITEAPSECTIONS; k++) {
- ForTransform_CompositeAPFilterState[k] = CompositeAPFilterState[k];
- }
-
- /* now backwards filter the samples in the lookahead buffer. The samples were
- placed there in the encoding of the previous frame. The output samples
- overwrite the input samples */
- WebRtcIsac_AllPassFilter2Float(prefiltdata->INLABUF1_float,
- WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,
- NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
-
- /* save the output, but write it in forward order */
- /* write the lookahead samples for the next encoding iteration. Every other
- sample at the end of the input frame is written in reverse order for the
- lookahead length. Exported in the prefiltdata structure. */
- for (k=0;k<QLOOKAHEAD;k++) {
- tempin_ch1[QLOOKAHEAD-1-k]=prefiltdata->INLABUF1_float[k];
- prefiltdata->INLABUF1_float[k]=in[FRAMESAMPLES-1-2*k];
- }
-
- /* Second Channel. This is exactly like the first channel, except that the
- even samples are now filtered instead (lower channel). */
- for (k=0;k<NUMBEROFCOMPOSITEAPSECTIONS;k++){
- CompositeAPFilterState[k] = 0.0;
- }
-
- for (k=0;k<FRAMESAMPLES_HALF;k++) {
- tempinoutvec[k] = in[FRAMESAMPLES-2-2*k];
- }
-
- WebRtcIsac_AllPassFilter2Float(tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat,
- FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
-
- for (k=0;k<FRAMESAMPLES_HALF;k++) {
- tempin_ch2[FRAMESAMPLES_HALF+QLOOKAHEAD-1-k] = tempinoutvec[k];
- }
-
- for (k=0; k<NUMBEROFCOMPOSITEAPSECTIONS; k++) {
- ForTransform_CompositeAPFilterState2[k] = CompositeAPFilterState[k];
- }
-
-
- WebRtcIsac_AllPassFilter2Float(prefiltdata->INLABUF2_float,
- WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,NUMBEROFCOMPOSITEAPSECTIONS,
- CompositeAPFilterState);
-
- for (k=0;k<QLOOKAHEAD;k++) {
- tempin_ch2[QLOOKAHEAD-1-k]=prefiltdata->INLABUF2_float[k];
- prefiltdata->INLABUF2_float[k]=in[FRAMESAMPLES-2-2*k];
- }
-
- /* Transform filter states from backward to forward */
- /*At this point, each of the states of the backwards composite filters for the
- two channels are transformed into forward filtering states for the corresponding
- forward channel filters. Each channel's forward filtering state from the previous
- encoding iteration is added to the transformed state to get a proper forward state */
-
- /* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is multiplied by a
- NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4) transform matrix to get the
- new state that is added to the previous 2x1 input state */
-
- for (k=0;k<NUMBEROFCHANNELAPSECTIONS;k++){ /* k is row variable */
- for (n=0; n<NUMBEROFCOMPOSITEAPSECTIONS;n++){/* n is column variable */
- prefiltdata->INSTAT1_float[k] += ForTransform_CompositeAPFilterState[n]*
- WebRtcIsac_kTransform1Float[k*NUMBEROFCHANNELAPSECTIONS+n];
- prefiltdata->INSTAT2_float[k] += ForTransform_CompositeAPFilterState2[n]*
- WebRtcIsac_kTransform2Float[k*NUMBEROFCHANNELAPSECTIONS+n];
- }
- }
-
- /*obtain polyphase components by forward all-pass filtering through each channel */
- /* the backward filtered samples are now forward filtered with the corresponding channel filters */
- /* The all pass filtering automatically updates the filter states which are exported in the
- prefiltdata structure */
- WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat,
- FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_float);
- WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat,
- FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_float);
-
- /* Now Construct low-pass and high-pass signals as combinations of polyphase components */
- for (k=0; k<FRAMESAMPLES_HALF; k++) {
- LP[k] = 0.5f*(tempin_ch1[k] + tempin_ch2[k]);/* low pass signal*/
- HP[k] = 0.5f*(tempin_ch1[k] - tempin_ch2[k]);/* high pass signal*/
- }
-
- /* Lookahead LP and HP signals */
- /* now create low pass and high pass signals of the input vector. However, no
- backwards filtering is performed, and hence no phase equalization is involved.
- Also, the input contains some samples that are lookahead samples. The high pass
- and low pass signals that are created are used outside this function for analysis
- (not encoding) purposes */
-
- /* set up input */
- for (k=0; k<FRAMESAMPLES_HALF; k++) {
- tempin_ch1[k]=in[2*k+1];
- tempin_ch2[k]=in[2*k];
- }
-
- /* the input filter states are passed in and updated by the all-pass filtering routine and
- exported in the prefiltdata structure*/
- WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat,
- FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA1_float);
- WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat,
- FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA2_float);
-
- for (k=0; k<FRAMESAMPLES_HALF; k++) {
- LP_la[k] = (float)(0.5f*(tempin_ch1[k] + tempin_ch2[k])); /*low pass */
- HP_la[k] = (double)(0.5f*(tempin_ch1[k] - tempin_ch2[k])); /* high pass */
- }
-
-
-}/*end of WebRtcIsac_SplitAndFilter */
-
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
/* Combining */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/intialize.c b/webrtc/modules/audio_coding/codecs/isac/main/source/intialize.c
index 01e683c..5c951f6 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/intialize.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/intialize.c
@@ -10,12 +10,12 @@
/* encode.c - Encoding function for the iSAC coder */
-#include "structs.h"
-#include "codec.h"
-#include "pitch_estimator.h"
-
#include <math.h>
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
+
void WebRtcIsac_InitMasking(MaskFiltstr *maskdata) {
int k;
@@ -43,39 +43,6 @@ void WebRtcIsac_InitMasking(MaskFiltstr *maskdata) {
return;
}
-void WebRtcIsac_InitPreFilterbank(PreFiltBankstr *prefiltdata)
-{
- int k;
-
- for (k = 0; k < QLOOKAHEAD; k++) {
- prefiltdata->INLABUF1[k] = 0;
- prefiltdata->INLABUF2[k] = 0;
-
- prefiltdata->INLABUF1_float[k] = 0;
- prefiltdata->INLABUF2_float[k] = 0;
- }
- for (k = 0; k < 2*(QORDER-1); k++) {
- prefiltdata->INSTAT1[k] = 0;
- prefiltdata->INSTAT2[k] = 0;
- prefiltdata->INSTATLA1[k] = 0;
- prefiltdata->INSTATLA2[k] = 0;
-
- prefiltdata->INSTAT1_float[k] = 0;
- prefiltdata->INSTAT2_float[k] = 0;
- prefiltdata->INSTATLA1_float[k] = 0;
- prefiltdata->INSTATLA2_float[k] = 0;
- }
-
- /* High pass filter states */
- prefiltdata->HPstates[0] = 0.0;
- prefiltdata->HPstates[1] = 0.0;
-
- prefiltdata->HPstates_float[0] = 0.0f;
- prefiltdata->HPstates_float[1] = 0.0f;
-
- return;
-}
-
void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata)
{
int k;
@@ -103,69 +70,3 @@ void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata)
return;
}
-
-
-void WebRtcIsac_InitPitchFilter(PitchFiltstr *pitchfiltdata)
-{
- int k;
-
- for (k = 0; k < PITCH_BUFFSIZE; k++) {
- pitchfiltdata->ubuf[k] = 0.0;
- }
- pitchfiltdata->ystate[0] = 0.0;
- for (k = 1; k < (PITCH_DAMPORDER); k++) {
- pitchfiltdata->ystate[k] = 0.0;
- }
- pitchfiltdata->oldlagp[0] = 50.0;
- pitchfiltdata->oldgainp[0] = 0.0;
-}
-
-void WebRtcIsac_InitWeightingFilter(WeightFiltstr *wfdata)
-{
- int k;
- double t, dtmp, dtmp2, denum, denum2;
-
- for (k=0;k<PITCH_WLPCBUFLEN;k++)
- wfdata->buffer[k]=0.0;
-
- for (k=0;k<PITCH_WLPCORDER;k++) {
- wfdata->istate[k]=0.0;
- wfdata->weostate[k]=0.0;
- wfdata->whostate[k]=0.0;
- }
-
- /* next part should be in Matlab, writing to a global table */
- t = 0.5;
- denum = 1.0 / ((double) PITCH_WLPCWINLEN);
- denum2 = denum * denum;
- for (k=0;k<PITCH_WLPCWINLEN;k++) {
- dtmp = PITCH_WLPCASYM * t * denum + (1-PITCH_WLPCASYM) * t * t * denum2;
- dtmp *= 3.14159265;
- dtmp2 = sin(dtmp);
- wfdata->window[k] = dtmp2 * dtmp2;
- t++;
- }
-}
-
-/* clear all buffers */
-void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct *State)
-{
- int k;
-
- for (k = 0; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k++)
- State->dec_buffer[k] = 0.0;
- for (k = 0; k < 2*ALLPASSSECTIONS+1; k++)
- State->decimator_state[k] = 0.0;
- for (k = 0; k < 2; k++)
- State->hp_state[k] = 0.0;
- for (k = 0; k < QLOOKAHEAD; k++)
- State->whitened_buf[k] = 0.0;
- for (k = 0; k < QLOOKAHEAD; k++)
- State->inbuf[k] = 0.0;
-
- WebRtcIsac_InitPitchFilter(&(State->PFstr_wght));
-
- WebRtcIsac_InitPitchFilter(&(State->PFstr));
-
- WebRtcIsac_InitWeightingFilter(&(State->Wghtstr));
-}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c b/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c
index 875e7ac..73f132c 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/isac.c
@@ -15,22 +15,24 @@
*
*/
-#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
+#include "modules/audio_coding/codecs/isac/main/include/isac.h"
-#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/codec.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/crc.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "rtc_base/checks.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/crc.h"
+#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
+#include "rtc_base/system/arch.h"
#define BIT_MASK_DEC_INIT 0x0001
#define BIT_MASK_ENC_INIT 0x0002
@@ -205,62 +207,6 @@ static void GetSendBandwidthInfo(ISACMainStruct* instISAC,
/****************************************************************************
- * WebRtcIsac_AssignSize(...)
- *
- * This function returns the size of the ISAC instance, so that the instance
- * can be created out side iSAC.
- *
- * Output:
- * - sizeinbytes : number of bytes needed to allocate for the
- * instance.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int16_t WebRtcIsac_AssignSize(int* sizeInBytes) {
- *sizeInBytes = sizeof(ISACMainStruct) * 2 / sizeof(int16_t);
- return 0;
-}
-
-
-/****************************************************************************
- * WebRtcIsac_Assign(...)
- *
- * This function assigns the memory already created to the ISAC instance.
- *
- * Input:
- * - ISAC_main_inst : address of the pointer to the coder instance.
- * - instISAC_Addr : the already allocated memory, where we put the
- * iSAC structure.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int16_t WebRtcIsac_Assign(ISACStruct** ISAC_main_inst,
- void* instISAC_Addr) {
- if (instISAC_Addr != NULL) {
- ISACMainStruct* instISAC = (ISACMainStruct*)instISAC_Addr;
- instISAC->errorCode = 0;
- instISAC->initFlag = 0;
-
- /* Assign the address. */
- *ISAC_main_inst = (ISACStruct*)instISAC_Addr;
-
- /* Default is wideband. */
- instISAC->encoderSamplingRateKHz = kIsacWideband;
- instISAC->decoderSamplingRateKHz = kIsacWideband;
- instISAC->bandwidthKHz = isac8kHz;
- instISAC->in_sample_rate_hz = 16000;
-
- WebRtcIsac_InitTransform(&instISAC->transform_tables);
- return 0;
- } else {
- return -1;
- }
-}
-
-
-/****************************************************************************
* WebRtcIsac_Create(...)
*
* This function creates an ISAC instance, which will contain the state
@@ -1253,10 +1199,23 @@ static int Decode(ISACStruct* ISAC_main_inst,
return -1;
}
+ if (numDecodedBytesUB < 0) {
+ instISAC->errorCode = numDecodedBytesUB;
+ return -1;
+ }
+ if (numDecodedBytesLB + numDecodedBytesUB > lenEncodedBytes) {
+ // We have supposedly decoded more bytes than we were given. Likely
+ // caused by bad input data.
+ instISAC->errorCode = ISAC_LENGTH_MISMATCH;
+ return -1;
+ }
+
/* It might be less due to garbage. */
if ((numDecodedBytesUB != lenNextStream) &&
- (numDecodedBytesUB != (lenNextStream -
- encoded[numDecodedBytesLB + 1 + numDecodedBytesUB]))) {
+ (numDecodedBytesLB + 1 + numDecodedBytesUB >= lenEncodedBytes ||
+ numDecodedBytesUB !=
+ (lenNextStream -
+ encoded[numDecodedBytesLB + 1 + numDecodedBytesUB]))) {
instISAC->errorCode = ISAC_LENGTH_MISMATCH;
return -1;
}
@@ -1539,8 +1498,8 @@ int16_t WebRtcIsac_Control(ISACStruct* ISAC_main_inst,
void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst,
int bottleneck_bits_per_second) {
ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
- assert(bottleneck_bits_per_second >= 10000 &&
- bottleneck_bits_per_second <= 32000);
+ RTC_DCHECK_GE(bottleneck_bits_per_second, 10000);
+ RTC_DCHECK_LE(bottleneck_bits_per_second, 32000);
instISAC->bwestimator_obj.send_bw_avg = (float)bottleneck_bits_per_second;
}
@@ -1760,7 +1719,7 @@ int16_t WebRtcIsac_ReadBwIndex(const uint8_t* encoded,
* - frameLength : Length of frame in packet (in samples)
*
*/
-int16_t WebRtcIsac_ReadFrameLen(ISACStruct* ISAC_main_inst,
+int16_t WebRtcIsac_ReadFrameLen(const ISACStruct* ISAC_main_inst,
const uint8_t* encoded,
int16_t* frameLength) {
Bitstr streamdata;
@@ -2338,26 +2297,11 @@ uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst) {
return instISAC->decoderSamplingRateKHz == kIsacWideband ? 16000 : 32000;
}
-void WebRtcIsac_GetBandwidthInfo(ISACStruct* inst,
- IsacBandwidthInfo* bwinfo) {
- ISACMainStruct* instISAC = (ISACMainStruct*)inst;
- assert(instISAC->initFlag & BIT_MASK_DEC_INIT);
- WebRtcIsacBw_GetBandwidthInfo(&instISAC->bwestimator_obj,
- instISAC->decoderSamplingRateKHz, bwinfo);
-}
-
-void WebRtcIsac_SetBandwidthInfo(ISACStruct* inst,
- const IsacBandwidthInfo* bwinfo) {
- ISACMainStruct* instISAC = (ISACMainStruct*)inst;
- assert(instISAC->initFlag & BIT_MASK_ENC_INIT);
- WebRtcIsacBw_SetBandwidthInfo(&instISAC->bwestimator_obj, bwinfo);
-}
-
void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst,
int sample_rate_hz) {
ISACMainStruct* instISAC = (ISACMainStruct*)inst;
- assert(instISAC->initFlag & BIT_MASK_DEC_INIT);
- assert(!(instISAC->initFlag & BIT_MASK_ENC_INIT));
- assert(sample_rate_hz == 16000 || sample_rate_hz == 32000);
+ RTC_DCHECK_NE(0, instISAC->initFlag & BIT_MASK_DEC_INIT);
+ RTC_DCHECK(!(instISAC->initFlag & BIT_MASK_ENC_INIT));
+ RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000);
instISAC->encoderSamplingRateKHz = sample_rate_hz / 1000;
}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h b/webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h
index e150d39..511bc97 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
-#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
+#include "modules/audio_coding/codecs/isac/main/include/isac.h"
namespace webrtc {
@@ -64,10 +64,6 @@ struct IsacFloat {
static inline int16_t Free(instance_type* inst) {
return WebRtcIsac_Free(inst);
}
- static inline void GetBandwidthInfo(instance_type* inst,
- IsacBandwidthInfo* bwinfo) {
- WebRtcIsac_GetBandwidthInfo(inst, bwinfo);
- }
static inline int16_t GetErrorCode(instance_type* inst) {
return WebRtcIsac_GetErrorCode(inst);
}
@@ -75,10 +71,6 @@ struct IsacFloat {
static inline int16_t GetNewFrameLen(instance_type* inst) {
return WebRtcIsac_GetNewFrameLen(inst);
}
- static inline void SetBandwidthInfo(instance_type* inst,
- const IsacBandwidthInfo* bwinfo) {
- WebRtcIsac_SetBandwidthInfo(inst, bwinfo);
- }
static inline int16_t SetDecSampRate(instance_type* inst,
uint16_t sample_rate_hz) {
return WebRtcIsac_SetDecSampRate(inst, sample_rate_hz);
@@ -95,15 +87,6 @@ struct IsacFloat {
int bottleneck_bits_per_second) {
WebRtcIsac_SetInitialBweBottleneck(inst, bottleneck_bits_per_second);
}
- static inline int16_t UpdateBwEstimate(instance_type* inst,
- const uint8_t* encoded,
- size_t packet_size,
- uint16_t rtp_seq_number,
- uint32_t send_ts,
- uint32_t arr_ts) {
- return WebRtcIsac_UpdateBwEstimate(inst, encoded, packet_size,
- rtp_seq_number, send_ts, arr_ts);
- }
static inline int16_t SetMaxPayloadSize(instance_type* inst,
int16_t max_payload_size_bytes) {
return WebRtcIsac_SetMaxPayloadSize(inst, max_payload_size_bytes);
@@ -114,4 +97,4 @@ struct IsacFloat {
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.c b/webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.c
new file mode 100644
index 0000000..57cf0c3
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
+
+#include <math.h>
+
+void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata) {
+ int k;
+
+ for (k = 0; k < PITCH_BUFFSIZE; k++) {
+ pitchfiltdata->ubuf[k] = 0.0;
+ }
+ pitchfiltdata->ystate[0] = 0.0;
+ for (k = 1; k < (PITCH_DAMPORDER); k++) {
+ pitchfiltdata->ystate[k] = 0.0;
+ }
+ pitchfiltdata->oldlagp[0] = 50.0;
+ pitchfiltdata->oldgainp[0] = 0.0;
+}
+
+static void WebRtcIsac_InitWeightingFilter(WeightFiltstr* wfdata) {
+ int k;
+ double t, dtmp, dtmp2, denum, denum2;
+
+ for (k = 0; k < PITCH_WLPCBUFLEN; k++)
+ wfdata->buffer[k] = 0.0;
+
+ for (k = 0; k < PITCH_WLPCORDER; k++) {
+ wfdata->istate[k] = 0.0;
+ wfdata->weostate[k] = 0.0;
+ wfdata->whostate[k] = 0.0;
+ }
+
+ /* next part should be in Matlab, writing to a global table */
+ t = 0.5;
+ denum = 1.0 / ((double)PITCH_WLPCWINLEN);
+ denum2 = denum * denum;
+ for (k = 0; k < PITCH_WLPCWINLEN; k++) {
+ dtmp = PITCH_WLPCASYM * t * denum + (1 - PITCH_WLPCASYM) * t * t * denum2;
+ dtmp *= 3.14159265;
+ dtmp2 = sin(dtmp);
+ wfdata->window[k] = dtmp2 * dtmp2;
+ t++;
+ }
+}
+
+void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State) {
+ int k;
+
+ for (k = 0; k < PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + PITCH_MAX_LAG / 2 -
+ PITCH_FRAME_LEN / 2 + 2;
+ k++)
+ State->dec_buffer[k] = 0.0;
+ for (k = 0; k < 2 * ALLPASSSECTIONS + 1; k++)
+ State->decimator_state[k] = 0.0;
+ for (k = 0; k < 2; k++)
+ State->hp_state[k] = 0.0;
+ for (k = 0; k < QLOOKAHEAD; k++)
+ State->whitened_buf[k] = 0.0;
+ for (k = 0; k < QLOOKAHEAD; k++)
+ State->inbuf[k] = 0.0;
+
+ WebRtcIsac_InitPitchFilter(&(State->PFstr_wght));
+
+ WebRtcIsac_InitPitchFilter(&(State->PFstr));
+
+ WebRtcIsac_InitWeightingFilter(&(State->Wghtstr));
+}
+
+void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata) {
+ int k;
+
+ for (k = 0; k < QLOOKAHEAD; k++) {
+ prefiltdata->INLABUF1[k] = 0;
+ prefiltdata->INLABUF2[k] = 0;
+
+ prefiltdata->INLABUF1_float[k] = 0;
+ prefiltdata->INLABUF2_float[k] = 0;
+ }
+ for (k = 0; k < 2 * (QORDER - 1); k++) {
+ prefiltdata->INSTAT1[k] = 0;
+ prefiltdata->INSTAT2[k] = 0;
+ prefiltdata->INSTATLA1[k] = 0;
+ prefiltdata->INSTATLA2[k] = 0;
+
+ prefiltdata->INSTAT1_float[k] = 0;
+ prefiltdata->INSTAT2_float[k] = 0;
+ prefiltdata->INSTATLA1_float[k] = 0;
+ prefiltdata->INSTATLA2_float[k] = 0;
+ }
+
+ /* High pass filter states */
+ prefiltdata->HPstates[0] = 0.0;
+ prefiltdata->HPstates[1] = 0.0;
+
+ prefiltdata->HPstates_float[0] = 0.0f;
+ prefiltdata->HPstates_float[1] = 0.0f;
+
+ return;
+}
+
+double WebRtcIsac_LevDurb(double* a, double* k, double* r, size_t order) {
+ const double LEVINSON_EPS = 1.0e-10;
+
+ double sum, alpha;
+ size_t m, m_h, i;
+ alpha = 0; // warning -DH
+ a[0] = 1.0;
+ if (r[0] < LEVINSON_EPS) { /* if r[0] <= 0, set LPC coeff. to zero */
+ for (i = 0; i < order; i++) {
+ k[i] = 0;
+ a[i + 1] = 0;
+ }
+ } else {
+ a[1] = k[0] = -r[1] / r[0];
+ alpha = r[0] + r[1] * k[0];
+ for (m = 1; m < order; m++) {
+ sum = r[m + 1];
+ for (i = 0; i < m; i++) {
+ sum += a[i + 1] * r[m - i];
+ }
+ k[m] = -sum / alpha;
+ alpha += k[m] * sum;
+ m_h = (m + 1) >> 1;
+ for (i = 0; i < m_h; i++) {
+ sum = a[i + 1] + k[m] * a[m - i];
+ a[m - i] += k[m] * a[i + 1];
+ a[i + 1] = sum;
+ }
+ a[m + 1] = k[m];
+ }
+ }
+ return alpha;
+}
+
+/* The upper channel all-pass filter factors */
+const float WebRtcIsac_kUpperApFactorsFloat[2] = {0.03470000000000f,
+ 0.38260000000000f};
+
+/* The lower channel all-pass filter factors */
+const float WebRtcIsac_kLowerApFactorsFloat[2] = {0.15440000000000f,
+ 0.74400000000000f};
+
+/* This function performs all-pass filtering--a series of first order all-pass
+ * sections are used to filter the input in a cascade manner.
+ * The input is overwritten!!
+ */
+void WebRtcIsac_AllPassFilter2Float(float* InOut,
+ const float* APSectionFactors,
+ int lengthInOut,
+ int NumberOfSections,
+ float* FilterState) {
+ int n, j;
+ float temp;
+ for (j = 0; j < NumberOfSections; j++) {
+ for (n = 0; n < lengthInOut; n++) {
+ temp = FilterState[j] + APSectionFactors[j] * InOut[n];
+ FilterState[j] = -APSectionFactors[j] * temp + InOut[n];
+ InOut[n] = temp;
+ }
+ }
+}
+
+/* The number of composite all-pass filter factors */
+#define NUMBEROFCOMPOSITEAPSECTIONS 4
+
+/* Function WebRtcIsac_SplitAndFilter
+ * This function creates low-pass and high-pass decimated versions of part of
+ the input signal, and part of the signal in the input 'lookahead buffer'.
+
+ INPUTS:
+ in: a length FRAMESAMPLES array of input samples
+ prefiltdata: input data structure containing the filterbank states
+ and lookahead samples from the previous encoding
+ iteration.
+ OUTPUTS:
+ LP: a FRAMESAMPLES_HALF array of low-pass filtered samples that
+ have been phase equalized. The first QLOOKAHEAD samples are
+ based on the samples in the two prefiltdata->INLABUFx arrays
+ each of length QLOOKAHEAD.
+ The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
+ on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
+ array in[].
+ HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that
+ have been phase equalized. The first QLOOKAHEAD samples are
+ based on the samples in the two prefiltdata->INLABUFx arrays
+ each of length QLOOKAHEAD.
+ The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
+ on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
+ array in[].
+
+ LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples.
+ These samples are not phase equalized. They are computed
+ from the samples in the in[] array.
+ HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples
+ that are not phase equalized. They are computed from
+ the in[] vector.
+ prefiltdata: this input data structure's filterbank state and
+ lookahead sample buffers are updated for the next
+ encoding iteration.
+*/
+void WebRtcIsac_SplitAndFilterFloat(float* pin,
+ float* LP,
+ float* HP,
+ double* LP_la,
+ double* HP_la,
+ PreFiltBankstr* prefiltdata) {
+ int k, n;
+ float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
+ float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
+ float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS];
+ float tempinoutvec[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
+ float tempin_ch1[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
+ float tempin_ch2[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
+ float in[FRAMESAMPLES];
+ float ftmp;
+
+ /* HPstcoeff_in = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
+ static const float kHpStCoefInFloat[4] = {
+ -1.94895953203325f, 0.94984516000000f, -0.05101826139794f,
+ 0.05015484000000f};
+
+ /* The composite all-pass filter factors */
+ static const float WebRtcIsac_kCompositeApFactorsFloat[4] = {
+ 0.03470000000000f, 0.15440000000000f, 0.38260000000000f,
+ 0.74400000000000f};
+
+ // The matrix for transforming the backward composite state to upper channel
+ // state.
+ static const float WebRtcIsac_kTransform1Float[8] = {
+ -0.00158678506084f, 0.00127157815343f, -0.00104805672709f,
+ 0.00084837248079f, 0.00134467983258f, -0.00107756549387f,
+ 0.00088814793277f, -0.00071893072525f};
+
+ // The matrix for transforming the backward composite state to lower channel
+ // state.
+ static const float WebRtcIsac_kTransform2Float[8] = {
+ -0.00170686041697f, 0.00136780109829f, -0.00112736532350f,
+ 0.00091257055385f, 0.00103094281812f, -0.00082615076557f,
+ 0.00068092756088f, -0.00055119165484f};
+
+ /* High pass filter */
+
+ for (k = 0; k < FRAMESAMPLES; k++) {
+ in[k] = pin[k] + kHpStCoefInFloat[2] * prefiltdata->HPstates_float[0] +
+ kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1];
+ ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] -
+ kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1];
+ prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0];
+ prefiltdata->HPstates_float[0] = ftmp;
+ }
+
+ /* First Channel */
+
+ /*initial state of composite filter is zero */
+ for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
+ CompositeAPFilterState[k] = 0.0;
+ }
+ /* put every other sample of input into a temporary vector in reverse
+ * (backward) order*/
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ tempinoutvec[k] = in[FRAMESAMPLES - 1 - 2 * k];
+ }
+
+ /* now all-pass filter the backwards vector. Output values overwrite the
+ * input vector. */
+ WebRtcIsac_AllPassFilter2Float(
+ tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat, FRAMESAMPLES_HALF,
+ NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
+
+ /* save the backwards filtered output for later forward filtering,
+ but write it in forward order*/
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ tempin_ch1[FRAMESAMPLES_HALF + QLOOKAHEAD - 1 - k] = tempinoutvec[k];
+ }
+
+ /* save the backwards filter state becaue it will be transformed
+ later into a forward state */
+ for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
+ ForTransform_CompositeAPFilterState[k] = CompositeAPFilterState[k];
+ }
+
+ /* now backwards filter the samples in the lookahead buffer. The samples were
+ placed there in the encoding of the previous frame. The output samples
+ overwrite the input samples */
+ WebRtcIsac_AllPassFilter2Float(
+ prefiltdata->INLABUF1_float, WebRtcIsac_kCompositeApFactorsFloat,
+ QLOOKAHEAD, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
+
+ /* save the output, but write it in forward order */
+ /* write the lookahead samples for the next encoding iteration. Every other
+ sample at the end of the input frame is written in reverse order for the
+ lookahead length. Exported in the prefiltdata structure. */
+ for (k = 0; k < QLOOKAHEAD; k++) {
+ tempin_ch1[QLOOKAHEAD - 1 - k] = prefiltdata->INLABUF1_float[k];
+ prefiltdata->INLABUF1_float[k] = in[FRAMESAMPLES - 1 - 2 * k];
+ }
+
+ /* Second Channel. This is exactly like the first channel, except that the
+ even samples are now filtered instead (lower channel). */
+ for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
+ CompositeAPFilterState[k] = 0.0;
+ }
+
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ tempinoutvec[k] = in[FRAMESAMPLES - 2 - 2 * k];
+ }
+
+ WebRtcIsac_AllPassFilter2Float(
+ tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat, FRAMESAMPLES_HALF,
+ NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
+
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ tempin_ch2[FRAMESAMPLES_HALF + QLOOKAHEAD - 1 - k] = tempinoutvec[k];
+ }
+
+ for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
+ ForTransform_CompositeAPFilterState2[k] = CompositeAPFilterState[k];
+ }
+
+ WebRtcIsac_AllPassFilter2Float(
+ prefiltdata->INLABUF2_float, WebRtcIsac_kCompositeApFactorsFloat,
+ QLOOKAHEAD, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
+
+ for (k = 0; k < QLOOKAHEAD; k++) {
+ tempin_ch2[QLOOKAHEAD - 1 - k] = prefiltdata->INLABUF2_float[k];
+ prefiltdata->INLABUF2_float[k] = in[FRAMESAMPLES - 2 - 2 * k];
+ }
+
+ /* Transform filter states from backward to forward */
+ /*At this point, each of the states of the backwards composite filters for the
+ two channels are transformed into forward filtering states for the
+ corresponding forward channel filters. Each channel's forward filtering
+ state from the previous
+ encoding iteration is added to the transformed state to get a proper forward
+ state */
+
+ /* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is
+ multiplied by a NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4)
+ transform matrix to get the new state that is added to the previous 2x1
+ input state */
+
+ for (k = 0; k < NUMBEROFCHANNELAPSECTIONS; k++) { /* k is row variable */
+ for (n = 0; n < NUMBEROFCOMPOSITEAPSECTIONS;
+ n++) { /* n is column variable */
+ prefiltdata->INSTAT1_float[k] +=
+ ForTransform_CompositeAPFilterState[n] *
+ WebRtcIsac_kTransform1Float[k * NUMBEROFCHANNELAPSECTIONS + n];
+ prefiltdata->INSTAT2_float[k] +=
+ ForTransform_CompositeAPFilterState2[n] *
+ WebRtcIsac_kTransform2Float[k * NUMBEROFCHANNELAPSECTIONS + n];
+ }
+ }
+
+ /*obtain polyphase components by forward all-pass filtering through each
+ * channel */
+ /* the backward filtered samples are now forward filtered with the
+ * corresponding channel filters */
+ /* The all pass filtering automatically updates the filter states which are
+ exported in the prefiltdata structure */
+ WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kUpperApFactorsFloat,
+ FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
+ prefiltdata->INSTAT1_float);
+ WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kLowerApFactorsFloat,
+ FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
+ prefiltdata->INSTAT2_float);
+
+ /* Now Construct low-pass and high-pass signals as combinations of polyphase
+ * components */
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ LP[k] = 0.5f * (tempin_ch1[k] + tempin_ch2[k]); /* low pass signal*/
+ HP[k] = 0.5f * (tempin_ch1[k] - tempin_ch2[k]); /* high pass signal*/
+ }
+
+ /* Lookahead LP and HP signals */
+ /* now create low pass and high pass signals of the input vector. However, no
+ backwards filtering is performed, and hence no phase equalization is
+ involved. Also, the input contains some samples that are lookahead samples.
+ The high pass and low pass signals that are created are used outside this
+ function for analysis (not encoding) purposes */
+
+ /* set up input */
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ tempin_ch1[k] = in[2 * k + 1];
+ tempin_ch2[k] = in[2 * k];
+ }
+
+ /* the input filter states are passed in and updated by the all-pass filtering
+ routine and exported in the prefiltdata structure*/
+ WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kUpperApFactorsFloat,
+ FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
+ prefiltdata->INSTATLA1_float);
+ WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kLowerApFactorsFloat,
+ FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
+ prefiltdata->INSTATLA2_float);
+
+ for (k = 0; k < FRAMESAMPLES_HALF; k++) {
+ LP_la[k] = (float)(0.5f * (tempin_ch1[k] + tempin_ch2[k])); /*low pass */
+ HP_la[k] = (double)(0.5f * (tempin_ch1[k] - tempin_ch2[k])); /* high pass */
+ }
+}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.h b/webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.h
new file mode 100644
index 0000000..1aecfc4
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
+
+#include <stddef.h>
+
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+
+void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata);
+void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* state);
+void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata);
+
+double WebRtcIsac_LevDurb(double* a, double* k, double* r, size_t order);
+
+/* The number of all-pass filter factors in an upper or lower channel*/
+#define NUMBEROFCHANNELAPSECTIONS 2
+
+/* The upper channel all-pass filter factors */
+extern const float WebRtcIsac_kUpperApFactorsFloat[2];
+
+/* The lower channel all-pass filter factors */
+extern const float WebRtcIsac_kLowerApFactorsFloat[2];
+
+void WebRtcIsac_AllPassFilter2Float(float* InOut,
+ const float* APSectionFactors,
+ int lengthInOut,
+ int NumberOfSections,
+ float* FilterState);
+void WebRtcIsac_SplitAndFilterFloat(float* in,
+ float* LP,
+ float* HP,
+ double* LP_la,
+ double* HP_la,
+ PreFiltBankstr* prefiltdata);
+
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c b/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c
index eabe708..d9d2d65 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lattice.c
@@ -14,8 +14,6 @@
* contains the normalized lattice filter routines (MA and AR) for iSAC codec
*
*/
-#include "settings.h"
-#include "codec.h"
#include <math.h>
#include <memory.h>
@@ -24,6 +22,9 @@
#include <stdlib.h>
#endif
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+
/* filter the signal using normalized lattice filter */
/* MA filter */
void WebRtcIsac_NormLatticeFilterMa(int orderCoef,
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c
index 60fc25b..0fda73b 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c
@@ -8,16 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "lpc_analysis.h"
-#include "settings.h"
-#include "codec.h"
-#include "entropy_coding.h"
-
#include <math.h>
#include <string.h>
-#define LEVINSON_EPS 1.0e-10
-
+#include "modules/audio_coding/codecs/isac/main/source/lpc_analysis.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
+#include "modules/audio_coding/codecs/isac/main/source/filter_functions.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
/* window */
/* Matlab generation code:
@@ -75,45 +74,10 @@ static const double kLpcCorrWindow[WINLEN] = {
0.00155690, 0.00124918, 0.00094895, 0.00066112, 0.00039320, 0.00015881
};
-double WebRtcIsac_LevDurb(double *a, double *k, double *r, size_t order)
-{
-
- double sum, alpha;
- size_t m, m_h, i;
- alpha = 0; //warning -DH
- a[0] = 1.0;
- if (r[0] < LEVINSON_EPS) { /* if r[0] <= 0, set LPC coeff. to zero */
- for (i = 0; i < order; i++) {
- k[i] = 0;
- a[i+1] = 0;
- }
- } else {
- a[1] = k[0] = -r[1]/r[0];
- alpha = r[0] + r[1] * k[0];
- for (m = 1; m < order; m++){
- sum = r[m + 1];
- for (i = 0; i < m; i++){
- sum += a[i+1] * r[m - i];
- }
- k[m] = -sum / alpha;
- alpha += k[m] * sum;
- m_h = (m + 1) >> 1;
- for (i = 0; i < m_h; i++){
- sum = a[i+1] + k[m] * a[m - i];
- a[m - i] += k[m] * a[i+1];
- a[i+1] = sum;
- }
- a[m+1] = k[m];
- }
- }
- return alpha;
-}
-
-
-//was static before, but didn't work with MEX file
-void WebRtcIsac_GetVars(const double *input, const int16_t *pitchGains_Q12,
- double *oldEnergy, double *varscale)
-{
+static void WebRtcIsac_GetVars(const double* input,
+ const int16_t* pitchGains_Q12,
+ double* oldEnergy,
+ double* varscale) {
double nrg[4], chng, pg;
int k;
@@ -162,12 +126,9 @@ void WebRtcIsac_GetVars(const double *input, const int16_t *pitchGains_Q12,
*oldEnergy = nrg[3];
}
-void
-WebRtcIsac_GetVarsUB(
- const double* input,
- double* oldEnergy,
- double* varscale)
-{
+static void WebRtcIsac_GetVarsUB(const double* input,
+ double* oldEnergy,
+ double* varscale) {
double nrg[4], chng;
int k;
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h
index 8dfe383..5503e2d 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h
@@ -15,36 +15,32 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
-
-#include "settings.h"
-#include "structs.h"
-
-double WebRtcIsac_LevDurb(double *a, double *k, double *r, size_t order);
-
-void WebRtcIsac_GetVars(const double *input, const int16_t *pitchGains_Q12,
- double *oldEnergy, double *varscale);
-
-void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata,
- double signal_noise_ratio, const int16_t *pitchGains_Q12,
- double *lo_coeff, double *hi_coeff);
-
-
-void WebRtcIsac_GetLpcGain(
- double signal_noise_ratio,
- const double* filtCoeffVecs,
- int numVecs,
- double* gain,
- double corrLo[][UB_LPC_ORDER + 1],
- const double* varscale);
-
-void WebRtcIsac_GetLpcCoefUb(
- double* inSignal,
- MaskFiltstr* maskdata,
- double* lpCoeff,
- double corr[][UB_LPC_ORDER + 1],
- double* varscale,
- int16_t bandwidth);
-
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYIS_H_ */
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
+
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+
+void WebRtcIsac_GetLpcCoefLb(double* inLo,
+ double* inHi,
+ MaskFiltstr* maskdata,
+ double signal_noise_ratio,
+ const int16_t* pitchGains_Q12,
+ double* lo_coeff,
+ double* hi_coeff);
+
+void WebRtcIsac_GetLpcGain(double signal_noise_ratio,
+ const double* filtCoeffVecs,
+ int numVecs,
+ double* gain,
+ double corrLo[][UB_LPC_ORDER + 1],
+ const double* varscale);
+
+void WebRtcIsac_GetLpcCoefUb(double* inSignal,
+ MaskFiltstr* maskdata,
+ double* lpCoeff,
+ double corr[][UB_LPC_ORDER + 1],
+ double* varscale,
+ int16_t bandwidth);
+
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYIS_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c
index 5cc6c11..6707540 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c
@@ -16,9 +16,8 @@
*
*/
-#include "lpc_gain_swb_tables.h"
-#include "settings.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
const double WebRtcIsac_kQSizeLpcGain = 0.100000;
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h
index c163f4a..39c4a24 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h
@@ -16,11 +16,12 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
-#include "settings.h"
-#include "webrtc/typedefs.h"
+#include <stdint.h>
+
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
extern const double WebRtcIsac_kQSizeLpcGain;
@@ -46,4 +47,4 @@ extern const uint16_t* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES];
extern const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES];
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c
index 599b89d..e3600a7 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c
@@ -16,9 +16,8 @@
*
*/
-#include "lpc_shape_swb12_tables.h"
-#include "settings.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
/*
* Mean value of LAR
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h
index 256f1d4..7448a1e 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h
@@ -16,32 +16,33 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
-#include "settings.h"
-#include "webrtc/typedefs.h"
+#include <stdint.h>
+
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
extern const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER];
extern const double WebRtcIsac_kMeanLpcGain;
-extern const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER];
+extern const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER]
+ [UB_LPC_ORDER];
-extern const double WebRtcIsac_kInterVecDecorrMatUb12
-[UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME];
+extern const double WebRtcIsac_kInterVecDecorrMatUb12[UB_LPC_VEC_PER_FRAME]
+ [UB_LPC_VEC_PER_FRAME];
extern const double WebRtcIsac_kLpcShapeQStepSizeUb12;
-extern const double WebRtcIsac_kLpcShapeLeftRecPointUb12
-[UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME];
-
+extern const double
+ WebRtcIsac_kLpcShapeLeftRecPointUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
-extern const int16_t WebRtcIsac_kLpcShapeNumRecPointUb12
-[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
+extern const int16_t
+ WebRtcIsac_kLpcShapeNumRecPointUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
-extern const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb12
-[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
+extern const uint16_t
+ WebRtcIsac_kLpcShapeEntropySearchUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec0Ub12[14];
@@ -59,7 +60,7 @@ extern const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub12[33];
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub12[49];
-extern const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb12
-[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
+extern const uint16_t*
+ WebRtcIsac_kLpcShapeCdfMatUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c
index 6176d2c..59617fd 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c
@@ -16,9 +16,8 @@
*
*/
-#include "lpc_shape_swb16_tables.h"
-#include "settings.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
/*
* Mean value of LAR
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h
index 3e1bdf7..51101db 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h
@@ -16,18 +16,20 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
-#include "settings.h"
-#include "webrtc/typedefs.h"
+#include <stdint.h>
+
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
extern const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER];
-extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER];
+extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER]
+ [UB_LPC_ORDER];
-extern const double WebRtcIsac_kInterVecDecorrMatUb16
-[UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME];
+extern const double WebRtcIsac_kInterVecDecorrMatUb16[UB16_LPC_VEC_PER_FRAME]
+ [UB16_LPC_VEC_PER_FRAME];
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub16[14];
@@ -61,18 +63,19 @@ extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub165[34];
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub166[71];
-extern const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb16
-[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+extern const uint16_t*
+ WebRtcIsac_kLpcShapeCdfMatUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
-extern const double WebRtcIsac_kLpcShapeLeftRecPointUb16
-[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+extern const double
+ WebRtcIsac_kLpcShapeLeftRecPointUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
-extern const int16_t WebRtcIsac_kLpcShapeNumRecPointUb16
-[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+extern const int16_t
+ WebRtcIsac_kLpcShapeNumRecPointUb16[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
-extern const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb16
-[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+extern const uint16_t
+ WebRtcIsac_kLpcShapeEntropySearchUb16[UB_LPC_ORDER *
+ UB16_LPC_VEC_PER_FRAME];
extern const double WebRtcIsac_kLpcShapeQStepSizeUb16;
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c
index 909809b..461b92e 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c
@@ -10,8 +10,8 @@
/* coding tables for the KLT coefficients */
-#include "lpc_tables.h"
-#include "settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
/* cdf array for model indicator */
const uint16_t WebRtcIsac_kQKltModelCdf[4] = {
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.h b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.h
index 51f6316..56ff22c 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.h
@@ -15,34 +15,33 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
-#include "structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
-#include "settings.h"
+#define KLT_STEPSIZE 1.00000000
+#define KLT_NUM_AVG_GAIN 0
+#define KLT_NUM_AVG_SHAPE 0
+#define KLT_NUM_MODELS 3
+#define LPC_GAIN_SCALE 4.000f
+#define LPC_LOBAND_SCALE 2.100f
+#define LPC_LOBAND_ORDER ORDERLO
+#define LPC_HIBAND_SCALE 0.450f
+#define LPC_HIBAND_ORDER ORDERHI
+#define LPC_GAIN_ORDER 2
-#define KLT_STEPSIZE 1.00000000
-#define KLT_NUM_AVG_GAIN 0
-#define KLT_NUM_AVG_SHAPE 0
-#define KLT_NUM_MODELS 3
-#define LPC_GAIN_SCALE 4.000f
-#define LPC_LOBAND_SCALE 2.100f
-#define LPC_LOBAND_ORDER ORDERLO
-#define LPC_HIBAND_SCALE 0.450f
-#define LPC_HIBAND_ORDER ORDERHI
-#define LPC_GAIN_ORDER 2
+#define LPC_SHAPE_ORDER (LPC_LOBAND_ORDER + LPC_HIBAND_ORDER)
-#define LPC_SHAPE_ORDER (LPC_LOBAND_ORDER + LPC_HIBAND_ORDER)
-
-#define KLT_ORDER_GAIN (LPC_GAIN_ORDER * SUBFRAMES)
-#define KLT_ORDER_SHAPE (LPC_SHAPE_ORDER * SUBFRAMES)
+#define KLT_ORDER_GAIN (LPC_GAIN_ORDER * SUBFRAMES)
+#define KLT_ORDER_SHAPE (LPC_SHAPE_ORDER * SUBFRAMES)
/* cdf array for model indicator */
-extern const uint16_t WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS+1];
+extern const uint16_t WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS + 1];
/* pointer to cdf array for model indicator */
-extern const uint16_t *WebRtcIsac_kQKltModelCdfPtr[1];
+extern const uint16_t* WebRtcIsac_kQKltModelCdfPtr[1];
/* initial cdf index for decoder of model indicator */
extern const uint16_t WebRtcIsac_kQKltModelInitIndex[1];
@@ -78,9 +77,9 @@ extern const uint16_t WebRtcIsac_kQKltCdfGain[404];
extern const uint16_t WebRtcIsac_kQKltCdfShape[686];
/* pointers to cdf tables for quantizer indices */
-extern const uint16_t *WebRtcIsac_kQKltCdfPtrGain[12];
+extern const uint16_t* WebRtcIsac_kQKltCdfPtrGain[12];
-extern const uint16_t *WebRtcIsac_kQKltCdfPtrShape[108];
+extern const uint16_t* WebRtcIsac_kQKltCdfPtrShape[108];
/* left KLT transforms */
extern const double WebRtcIsac_kKltT1Gain[4];
@@ -97,4 +96,4 @@ extern const double WebRtcIsac_kLpcMeansGain[12];
extern const double WebRtcIsac_kLpcMeansShape[108];
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h b/webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h
index 2b446e9..fe9afa4 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
#include <math.h>
-#include "webrtc/typedefs.h"
+
+#include "rtc_base/system/arch.h"
#if defined(WEBRTC_POSIX)
#define WebRtcIsac_lrint lrint
@@ -24,11 +24,12 @@ static __inline long int WebRtcIsac_lrint(double x_dbl) {
__asm {
fld x_dbl
fistp x_int
- };
+ }
+ ;
return x_int;
}
-#else // Do a slow but correct implementation of lrint
+#else // Do a slow but correct implementation of lrint
static __inline long int WebRtcIsac_lrint(double x_dbl) {
long int x_int;
@@ -38,4 +39,4 @@ static __inline long int WebRtcIsac_lrint(double x_dbl) {
#endif
-#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c
index 090b94c..8a19ac1 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "pitch_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
#include <math.h>
#include <memory.h>
@@ -17,6 +17,10 @@
#include <stdlib.h>
#endif
+#include "modules/audio_coding/codecs/isac/main/source/filter_functions.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
+#include "rtc_base/system/ignore_warnings.h"
+
static const double kInterpolWin[8] = {-0.00067556028640, 0.02184247643159, -0.12203175715679, 0.60086484101160,
0.60086484101160, -0.12203175715679, 0.02184247643159, -0.00067556028640};
@@ -122,13 +126,56 @@ static void PCorr(const double *in, double *outcorr)
}
}
+static void WebRtcIsac_AllpassFilterForDec(double* InOut,
+ const double* APSectionFactors,
+ size_t lengthInOut,
+ double* FilterState) {
+ // This performs all-pass filtering--a series of first order all-pass
+ // sections are used to filter the input in a cascade manner.
+ size_t n, j;
+ double temp;
+ for (j = 0; j < ALLPASSSECTIONS; j++) {
+ for (n = 0; n < lengthInOut; n += 2) {
+ temp = InOut[n]; // store input
+ InOut[n] = FilterState[j] + APSectionFactors[j] * temp;
+ FilterState[j] = -APSectionFactors[j] * InOut[n] + temp;
+ }
+ }
+}
-void WebRtcIsac_InitializePitch(const double *in,
- const double old_lag,
- const double old_gain,
- PitchAnalysisStruct *State,
- double *lags)
-{
+static void WebRtcIsac_DecimateAllpass(
+ const double* in,
+ double* state_in, // array of size: 2*ALLPASSSECTIONS+1
+ size_t N, // number of input samples
+ double* out) { // array of size N/2
+
+ static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826};
+ static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744};
+
+ size_t n;
+ double data_vec[PITCH_FRAME_LEN];
+
+ /* copy input */
+ memcpy(data_vec + 1, in, sizeof(double) * (N - 1));
+
+ data_vec[0] = state_in[2 * ALLPASSSECTIONS]; // the z^(-1) state
+ state_in[2 * ALLPASSSECTIONS] = in[N - 1];
+
+ WebRtcIsac_AllpassFilterForDec(data_vec + 1, APupper, N, state_in);
+ WebRtcIsac_AllpassFilterForDec(data_vec, APlower, N,
+ state_in + ALLPASSSECTIONS);
+
+ for (n = 0; n < N / 2; n++)
+ out[n] = data_vec[2 * n] + data_vec[2 * n + 1];
+}
+
+RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
+
+static void WebRtcIsac_InitializePitch(const double* in,
+ const double old_lag,
+ const double old_gain,
+ PitchAnalysisStruct* State,
+ double* lags) {
double buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2];
double ratio, log_lag, gain_bias;
double bias;
@@ -449,7 +496,7 @@ void WebRtcIsac_InitializePitch(const double *in,
}
}
-
+RTC_POP_IGNORING_WFRAME_LARGER_THAN()
/* create weighting matrix by orthogonalizing a basis of polynomials of increasing order
* t = (0:4)';
@@ -464,6 +511,29 @@ static const double kWeight[5][5] = {
{ 0.01714285714286, 0.05142857142857, -0.05714285714286, -0.30857142857143, 0.29714285714286}
};
+/* second order high-pass filter */
+static void WebRtcIsac_Highpass(const double* in,
+ double* out,
+ double* state,
+ size_t N) {
+ /* create high-pass filter ocefficients
+ * z = 0.998 * exp(j*2*pi*35/8000);
+ * p = 0.94 * exp(j*2*pi*140/8000);
+ * HP_b = [1, -2*real(z), abs(z)^2];
+ * HP_a = [1, -2*real(p), abs(p)^2]; */
+ static const double a_coef[2] = { 1.86864659625574, -0.88360000000000};
+ static const double b_coef[2] = {-1.99524591718270, 0.99600400000000};
+
+ size_t k;
+
+ for (k=0; k<N; k++) {
+ *out = *in + state[1];
+ state[1] = state[0] + b_coef[0] * *in + a_coef[0] * *out;
+ state[0] = b_coef[1] * *in++ + a_coef[1] * *out++;
+ }
+}
+
+RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */
double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
@@ -621,3 +691,5 @@ void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN
for (k = 0; k < QLOOKAHEAD; k++)
State->inbuf[k] = inbuf[k + PITCH_FRAME_LEN];
}
+
+RTC_POP_IGNORING_WFRAME_LARGER_THAN()
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h
index 6fb02b3..4ab78c2 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h
@@ -15,61 +15,18 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
-#include "structs.h"
+#include <stddef.h>
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+void WebRtcIsac_PitchAnalysis(
+ const double* in, /* PITCH_FRAME_LEN samples */
+ double* out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
+ PitchAnalysisStruct* State,
+ double* lags,
+ double* gains);
-void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */
- double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
- PitchAnalysisStruct *State,
- double *lags,
- double *gains);
-
-void WebRtcIsac_InitializePitch(const double *in,
- const double old_lag,
- const double old_gain,
- PitchAnalysisStruct *State,
- double *lags);
-
-void WebRtcIsac_PitchfilterPre(double *indat,
- double *outdat,
- PitchFiltstr *pfp,
- double *lags,
- double *gains);
-
-void WebRtcIsac_PitchfilterPost(double *indat,
- double *outdat,
- PitchFiltstr *pfp,
- double *lags,
- double *gains);
-
-void WebRtcIsac_PitchfilterPre_la(double *indat,
- double *outdat,
- PitchFiltstr *pfp,
- double *lags,
- double *gains);
-
-void WebRtcIsac_PitchfilterPre_gains(double *indat,
- double *outdat,
- double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD],
- PitchFiltstr *pfp,
- double *lags,
- double *gains);
-
-void WebRtcIsac_WeightingFilter(const double *in, double *weiout, double *whiout, WeightFiltstr *wfdata);
-
-void WebRtcIsac_Highpass(const double *in,
- double *out,
- double *state,
- size_t N);
-
-void WebRtcIsac_DecimateAllpass(const double *in,
- double *state_in, /* array of size:
- * 2*ALLPASSSECTIONS+1 */
- size_t N, /* number of input samples */
- double *out); /* array of size N/2 */
-
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.c b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.c
index f03d230..61cd533 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.c
@@ -8,13 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "pitch_estimator.h"
-
#include <math.h>
#include <memory.h>
#include <stdlib.h>
-#include "os_specific_inline.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
+#include "rtc_base/compile_assert_c.h"
/*
* We are implementing the following filters;
@@ -275,6 +275,11 @@ static void FilterFrame(const double* in_data, PitchFiltstr* filter_state,
/* Copy states to local variables. */
memcpy(filter_parameters.buffer, filter_state->ubuf,
sizeof(filter_state->ubuf));
+ RTC_COMPILE_ASSERT(sizeof(filter_parameters.buffer) >=
+ sizeof(filter_state->ubuf));
+ memset(filter_parameters.buffer +
+ sizeof(filter_state->ubuf) / sizeof(filter_state->ubuf[0]),
+ 0, sizeof(filter_parameters.buffer) - sizeof(filter_state->ubuf));
memcpy(filter_parameters.damper_state, filter_state->ystate,
sizeof(filter_state->ystate));
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.h b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.h
new file mode 100644
index 0000000..9a232de
--- /dev/null
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_filter.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
+
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
+
+void WebRtcIsac_PitchfilterPre(double* indat,
+ double* outdat,
+ PitchFiltstr* pfp,
+ double* lags,
+ double* gains);
+
+void WebRtcIsac_PitchfilterPost(double* indat,
+ double* outdat,
+ PitchFiltstr* pfp,
+ double* lags,
+ double* gains);
+
+void WebRtcIsac_PitchfilterPre_la(double* indat,
+ double* outdat,
+ PitchFiltstr* pfp,
+ double* lags,
+ double* gains);
+
+void WebRtcIsac_PitchfilterPre_gains(
+ double* indat,
+ double* outdat,
+ double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD],
+ PitchFiltstr* pfp,
+ double* lags,
+ double* gains);
+
+#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c
index 947d3e7..080432c 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c
@@ -8,9 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "pitch_gain_tables.h"
-
-#include "settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
/* header file for coding tables for the pitch filter side-info in the entropy coder */
/********************* Pitch Filter Gain Coefficient Tables ************************/
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h
index 8d708ce..145fd4e 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h
@@ -11,17 +11,20 @@
/*
* pitch_gain_tables.h
*
- * This file contains tables for the pitch filter side-info in the entropy coder.
+ * This file contains tables for the pitch filter side-info in the entropy
+ * coder.
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_
-#include "webrtc/typedefs.h"
+#include <stdint.h>
-/* header file for coding tables for the pitch filter side-info in the entropy coder */
-/********************* Pitch Filter Gain Coefficient Tables ************************/
+/* header file for coding tables for the pitch filter side-info in the entropy
+ * coder */
+/********************* Pitch Filter Gain Coefficient Tables
+ * ************************/
/* cdf for quantized pitch filter gains */
extern const uint16_t WebRtcIsac_kQPitchGainCdf[255];
@@ -42,4 +45,4 @@ extern const int16_t WebRtcIsac_kQMeanGain4Q12[144];
/* size of cdf table */
extern const uint16_t WebRtcIsac_kQCdfTableSizeGain[1];
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c
index f845a22..57d1202 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "pitch_lag_tables.h"
-#include "settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
/* header file for coding tables for the pitch filter side-info in the entropy coder */
/********************* Pitch Filter Gain Coefficient Tables ************************/
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h
index 01989f0..b48e358 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h
@@ -11,16 +11,20 @@
/*
* pitch_lag_tables.h
*
- * This file contains tables for the pitch filter side-info in the entropy coder.
+ * This file contains tables for the pitch filter side-info in the entropy
+ * coder.
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_
-#include "webrtc/typedefs.h"
-/* header file for coding tables for the pitch filter side-info in the entropy coder */
-/********************* Pitch Filter Lag Coefficient Tables ************************/
+#include <stdint.h>
+
+/* header file for coding tables for the pitch filter side-info in the entropy
+ * coder */
+/********************* Pitch Filter Lag Coefficient Tables
+ * ************************/
/* tables for use with small pitch gain */
@@ -30,7 +34,7 @@ extern const uint16_t WebRtcIsac_kQPitchLagCdf2Lo[20];
extern const uint16_t WebRtcIsac_kQPitchLagCdf3Lo[2];
extern const uint16_t WebRtcIsac_kQPitchLagCdf4Lo[10];
-extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrLo[4];
+extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrLo[4];
/* size of first cdf table */
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeLo[1];
@@ -49,7 +53,6 @@ extern const double WebRtcIsac_kQMeanLag4Lo[9];
extern const double WebRtcIsac_kQPitchLagStepsizeLo;
-
/* tables for use with medium pitch gain */
/* cdfs for quantized pitch lags */
@@ -58,7 +61,7 @@ extern const uint16_t WebRtcIsac_kQPitchLagCdf2Mid[36];
extern const uint16_t WebRtcIsac_kQPitchLagCdf3Mid[2];
extern const uint16_t WebRtcIsac_kQPitchLagCdf4Mid[20];
-extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrMid[4];
+extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrMid[4];
/* size of first cdf table */
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeMid[1];
@@ -77,7 +80,6 @@ extern const double WebRtcIsac_kQMeanLag4Mid[19];
extern const double WebRtcIsac_kQPitchLagStepsizeMid;
-
/* tables for use with large pitch gain */
/* cdfs for quantized pitch lags */
@@ -86,7 +88,7 @@ extern const uint16_t WebRtcIsac_kQPitchLagCdf2Hi[68];
extern const uint16_t WebRtcIsac_kQPitchLagCdf3Hi[2];
extern const uint16_t WebRtcIsac_kQPitchLagCdf4Hi[35];
-extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrHi[4];
+extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrHi[4];
/* size of first cdf table */
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeHi[1];
@@ -111,4 +113,4 @@ extern const double WebRtcIsac_kTransform[4][4];
/* transpose transform matrix */
extern const double WebRtcIsac_kTransformTranspose[4][4];
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/settings.h b/webrtc/modules/audio_coding/codecs/isac/main/source/settings.h
index 31a8065..abce90c 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/settings.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/settings.h
@@ -15,191 +15,182 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
/* sampling frequency (Hz) */
-#define FS 16000
+#define FS 16000
/* number of samples per frame (either 320 (20ms), 480 (30ms) or 960 (60ms)) */
-#define INITIAL_FRAMESAMPLES 960
-
-
-#define MAXFFTSIZE 2048
-#define NFACTOR 11
-
-
+#define INITIAL_FRAMESAMPLES 960
/* do not modify the following; this will have to be modified if we
* have a 20ms framesize option */
/**********************************************************************/
/* miliseconds */
-#define FRAMESIZE 30
+#define FRAMESIZE 30
/* number of samples per frame processed in the encoder, 480 */
-#define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */
-#define FRAMESAMPLES_HALF 240
-#define FRAMESAMPLES_QUARTER 120
+#define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */
+#define FRAMESAMPLES_HALF 240
+#define FRAMESAMPLES_QUARTER 120
/**********************************************************************/
-
-
/* max number of samples per frame (= 60 ms frame) */
-#define MAX_FRAMESAMPLES 960
-#define MAX_SWBFRAMESAMPLES (MAX_FRAMESAMPLES * 2)
+#define MAX_FRAMESAMPLES 960
+#define MAX_SWBFRAMESAMPLES (MAX_FRAMESAMPLES * 2)
/* number of samples per 10ms frame */
-#define FRAMESAMPLES_10ms ((10*FS)/1000)
-#define SWBFRAMESAMPLES_10ms (FRAMESAMPLES_10ms * 2)
+#define FRAMESAMPLES_10ms ((10 * FS) / 1000)
+#define SWBFRAMESAMPLES_10ms (FRAMESAMPLES_10ms * 2)
/* number of samples in 30 ms frame */
-#define FRAMESAMPLES_30ms 480
+#define FRAMESAMPLES_30ms 480
/* number of subframes */
-#define SUBFRAMES 6
+#define SUBFRAMES 6
/* length of a subframe */
-#define UPDATE 80
+#define UPDATE 80
/* length of half a subframe (low/high band) */
-#define HALF_SUBFRAMELEN (UPDATE/2)
+#define HALF_SUBFRAMELEN (UPDATE / 2)
/* samples of look ahead (in a half-band, so actually
* half the samples of look ahead @ FS) */
-#define QLOOKAHEAD 24 /* 3 ms */
+#define QLOOKAHEAD 24 /* 3 ms */
/* order of AR model in spectral entropy coder */
-#define AR_ORDER 6
+#define AR_ORDER 6
/* order of LP model in spectral entropy coder */
-#define LP_ORDER 0
+#define LP_ORDER 0
/* window length (masking analysis) */
-#define WINLEN 256
+#define WINLEN 256
/* order of low-band pole filter used to approximate masking curve */
-#define ORDERLO 12
+#define ORDERLO 12
/* order of hi-band pole filter used to approximate masking curve */
-#define ORDERHI 6
-
-#define UB_LPC_ORDER 4
-#define UB_LPC_VEC_PER_FRAME 2
-#define UB16_LPC_VEC_PER_FRAME 4
-#define UB_ACTIVE_SUBFRAMES 2
-#define UB_MAX_LPC_ORDER 6
-#define UB_INTERPOL_SEGMENTS 1
-#define UB16_INTERPOL_SEGMENTS 3
-#define LB_TOTAL_DELAY_SAMPLES 48
-enum ISACBandwidth {isac8kHz = 8, isac12kHz = 12, isac16kHz = 16};
-enum ISACBand {kIsacLowerBand = 0, kIsacUpperBand12 = 1, kIsacUpperBand16 = 2};
-enum IsacSamplingRate {kIsacWideband = 16, kIsacSuperWideband = 32};
-#define UB_LPC_GAIN_DIM SUBFRAMES
-#define FB_STATE_SIZE_WORD32 6
-
+#define ORDERHI 6
+
+#define UB_LPC_ORDER 4
+#define UB_LPC_VEC_PER_FRAME 2
+#define UB16_LPC_VEC_PER_FRAME 4
+#define UB_ACTIVE_SUBFRAMES 2
+#define UB_MAX_LPC_ORDER 6
+#define UB_INTERPOL_SEGMENTS 1
+#define UB16_INTERPOL_SEGMENTS 3
+#define LB_TOTAL_DELAY_SAMPLES 48
+enum ISACBandwidth { isac8kHz = 8, isac12kHz = 12, isac16kHz = 16 };
+enum ISACBand {
+ kIsacLowerBand = 0,
+ kIsacUpperBand12 = 1,
+ kIsacUpperBand16 = 2
+};
+enum IsacSamplingRate { kIsacWideband = 16, kIsacSuperWideband = 32 };
+#define UB_LPC_GAIN_DIM SUBFRAMES
+#define FB_STATE_SIZE_WORD32 6
/* order for post_filter_bank */
-#define POSTQORDER 3
+#define POSTQORDER 3
/* order for pre-filterbank */
-#define QORDER 3
+#define QORDER 3
/* another order */
-#define QORDER_ALL (POSTQORDER+QORDER-1)
+#define QORDER_ALL (POSTQORDER + QORDER - 1)
/* for decimator */
-#define ALLPASSSECTIONS 2
-
+#define ALLPASSSECTIONS 2
/* array size for byte stream in number of bytes. */
/* The old maximum size still needed for the decoding */
-#define STREAM_SIZE_MAX 600
-#define STREAM_SIZE_MAX_30 200 /* 200 bytes=53.4 kbps @ 30 ms.framelength */
-#define STREAM_SIZE_MAX_60 400 /* 400 bytes=53.4 kbps @ 60 ms.framelength */
+#define STREAM_SIZE_MAX 600
+#define STREAM_SIZE_MAX_30 200 /* 200 bytes=53.4 kbps @ 30 ms.framelength */
+#define STREAM_SIZE_MAX_60 400 /* 400 bytes=53.4 kbps @ 60 ms.framelength */
/* storage size for bit counts */
-#define BIT_COUNTER_SIZE 30
+#define BIT_COUNTER_SIZE 30
/* maximum order of any AR model or filter */
-#define MAX_AR_MODEL_ORDER 12//50
-
+#define MAX_AR_MODEL_ORDER 12 // 50
/* For pitch analysis */
-#define PITCH_FRAME_LEN (FRAMESAMPLES_HALF) /* 30 ms */
-#define PITCH_MAX_LAG 140 /* 57 Hz */
-#define PITCH_MIN_LAG 20 /* 400 Hz */
-#define PITCH_MAX_GAIN 0.45
-#define PITCH_MAX_GAIN_06 0.27 /* PITCH_MAX_GAIN*0.6 */
-#define PITCH_MAX_GAIN_Q12 1843
-#define PITCH_LAG_SPAN2 (PITCH_MAX_LAG/2-PITCH_MIN_LAG/2+5)
-#define PITCH_CORR_LEN2 60 /* 15 ms */
-#define PITCH_CORR_STEP2 (PITCH_FRAME_LEN/4)
-#define PITCH_BW 11 /* half the band width of correlation surface */
-#define PITCH_SUBFRAMES 4
-#define PITCH_GRAN_PER_SUBFRAME 5
-#define PITCH_SUBFRAME_LEN (PITCH_FRAME_LEN/PITCH_SUBFRAMES)
-#define PITCH_UPDATE (PITCH_SUBFRAME_LEN/PITCH_GRAN_PER_SUBFRAME)
+#define PITCH_FRAME_LEN (FRAMESAMPLES_HALF) /* 30 ms */
+#define PITCH_MAX_LAG 140 /* 57 Hz */
+#define PITCH_MIN_LAG 20 /* 400 Hz */
+#define PITCH_MAX_GAIN 0.45
+#define PITCH_MAX_GAIN_06 0.27 /* PITCH_MAX_GAIN*0.6 */
+#define PITCH_MAX_GAIN_Q12 1843
+#define PITCH_LAG_SPAN2 (PITCH_MAX_LAG / 2 - PITCH_MIN_LAG / 2 + 5)
+#define PITCH_CORR_LEN2 60 /* 15 ms */
+#define PITCH_CORR_STEP2 (PITCH_FRAME_LEN / 4)
+#define PITCH_BW 11 /* half the band width of correlation surface */
+#define PITCH_SUBFRAMES 4
+#define PITCH_GRAN_PER_SUBFRAME 5
+#define PITCH_SUBFRAME_LEN (PITCH_FRAME_LEN / PITCH_SUBFRAMES)
+#define PITCH_UPDATE (PITCH_SUBFRAME_LEN / PITCH_GRAN_PER_SUBFRAME)
/* maximum number of peaks to be examined in correlation surface */
-#define PITCH_MAX_NUM_PEAKS 10
-#define PITCH_PEAK_DECAY 0.85
+#define PITCH_MAX_NUM_PEAKS 10
+#define PITCH_PEAK_DECAY 0.85
/* For weighting filter */
-#define PITCH_WLPCORDER 6
-#define PITCH_WLPCWINLEN PITCH_FRAME_LEN
-#define PITCH_WLPCASYM 0.3 /* asymmetry parameter */
-#define PITCH_WLPCBUFLEN PITCH_WLPCWINLEN
+#define PITCH_WLPCORDER 6
+#define PITCH_WLPCWINLEN PITCH_FRAME_LEN
+#define PITCH_WLPCASYM 0.3 /* asymmetry parameter */
+#define PITCH_WLPCBUFLEN PITCH_WLPCWINLEN
/* For pitch filter */
/* Extra 50 for fraction and LP filters */
-#define PITCH_BUFFSIZE (PITCH_MAX_LAG + 50)
-#define PITCH_INTBUFFSIZE (PITCH_FRAME_LEN+PITCH_BUFFSIZE)
+#define PITCH_BUFFSIZE (PITCH_MAX_LAG + 50)
+#define PITCH_INTBUFFSIZE (PITCH_FRAME_LEN + PITCH_BUFFSIZE)
/* Max rel. step for interpolation */
-#define PITCH_UPSTEP 1.5
+#define PITCH_UPSTEP 1.5
/* Max rel. step for interpolation */
-#define PITCH_DOWNSTEP 0.67
-#define PITCH_FRACS 8
-#define PITCH_FRACORDER 9
-#define PITCH_DAMPORDER 5
-#define PITCH_FILTDELAY 1.5f
+#define PITCH_DOWNSTEP 0.67
+#define PITCH_FRACS 8
+#define PITCH_FRACORDER 9
+#define PITCH_DAMPORDER 5
+#define PITCH_FILTDELAY 1.5f
/* stepsize for quantization of the pitch Gain */
-#define PITCH_GAIN_STEPSIZE 0.125
-
-
+#define PITCH_GAIN_STEPSIZE 0.125
/* Order of high pass filter */
-#define HPORDER 2
+#define HPORDER 2
/* some mathematical constants */
/* log2(exp) */
-#define LOG2EXP 1.44269504088896
-#define PI 3.14159265358979
+#define LOG2EXP 1.44269504088896
+#define PI 3.14159265358979
/* Maximum number of iterations allowed to limit payload size */
-#define MAX_PAYLOAD_LIMIT_ITERATION 5
+#define MAX_PAYLOAD_LIMIT_ITERATION 5
/* Redundant Coding */
-#define RCU_BOTTLENECK_BPS 16000
-#define RCU_TRANSCODING_SCALE 0.40f
-#define RCU_TRANSCODING_SCALE_INVERSE 2.5f
+#define RCU_BOTTLENECK_BPS 16000
+#define RCU_TRANSCODING_SCALE 0.40f
+#define RCU_TRANSCODING_SCALE_INVERSE 2.5f
-#define RCU_TRANSCODING_SCALE_UB 0.50f
-#define RCU_TRANSCODING_SCALE_UB_INVERSE 2.0f
+#define RCU_TRANSCODING_SCALE_UB 0.50f
+#define RCU_TRANSCODING_SCALE_UB_INVERSE 2.0f
/* Define Error codes */
/* 6000 General */
-#define ISAC_MEMORY_ALLOCATION_FAILED 6010
-#define ISAC_MODE_MISMATCH 6020
-#define ISAC_DISALLOWED_BOTTLENECK 6030
-#define ISAC_DISALLOWED_FRAME_LENGTH 6040
-#define ISAC_UNSUPPORTED_SAMPLING_FREQUENCY 6050
+#define ISAC_MEMORY_ALLOCATION_FAILED 6010
+#define ISAC_MODE_MISMATCH 6020
+#define ISAC_DISALLOWED_BOTTLENECK 6030
+#define ISAC_DISALLOWED_FRAME_LENGTH 6040
+#define ISAC_UNSUPPORTED_SAMPLING_FREQUENCY 6050
/* 6200 Bandwidth estimator */
-#define ISAC_RANGE_ERROR_BW_ESTIMATOR 6240
+#define ISAC_RANGE_ERROR_BW_ESTIMATOR 6240
/* 6400 Encoder */
-#define ISAC_ENCODER_NOT_INITIATED 6410
-#define ISAC_DISALLOWED_CODING_MODE 6420
-#define ISAC_DISALLOWED_FRAME_MODE_ENCODER 6430
-#define ISAC_DISALLOWED_BITSTREAM_LENGTH 6440
-#define ISAC_PAYLOAD_LARGER_THAN_LIMIT 6450
-#define ISAC_DISALLOWED_ENCODER_BANDWIDTH 6460
+#define ISAC_ENCODER_NOT_INITIATED 6410
+#define ISAC_DISALLOWED_CODING_MODE 6420
+#define ISAC_DISALLOWED_FRAME_MODE_ENCODER 6430
+#define ISAC_DISALLOWED_BITSTREAM_LENGTH 6440
+#define ISAC_PAYLOAD_LARGER_THAN_LIMIT 6450
+#define ISAC_DISALLOWED_ENCODER_BANDWIDTH 6460
/* 6600 Decoder */
-#define ISAC_DECODER_NOT_INITIATED 6610
-#define ISAC_EMPTY_PACKET 6620
-#define ISAC_DISALLOWED_FRAME_MODE_DECODER 6630
-#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH 6640
-#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH 6650
-#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN 6660
-#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG 6670
-#define ISAC_RANGE_ERROR_DECODE_LPC 6680
-#define ISAC_RANGE_ERROR_DECODE_SPECTRUM 6690
-#define ISAC_LENGTH_MISMATCH 6730
-#define ISAC_RANGE_ERROR_DECODE_BANDWITH 6740
-#define ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER 6750
-#define ISAC_DISALLOWED_LPC_MODEL 6760
+#define ISAC_DECODER_NOT_INITIATED 6610
+#define ISAC_EMPTY_PACKET 6620
+#define ISAC_DISALLOWED_FRAME_MODE_DECODER 6630
+#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH 6640
+#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH 6650
+#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN 6660
+#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG 6670
+#define ISAC_RANGE_ERROR_DECODE_LPC 6680
+#define ISAC_RANGE_ERROR_DECODE_SPECTRUM 6690
+#define ISAC_LENGTH_MISMATCH 6730
+#define ISAC_RANGE_ERROR_DECODE_BANDWITH 6740
+#define ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER 6750
+#define ISAC_DISALLOWED_LPC_MODEL 6760
/* 6800 Call setup formats */
-#define ISAC_INCOMPATIBLE_FORMATS 6810
+#define ISAC_INCOMPATIBLE_FORMATS 6810
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c b/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c
index 0f6d889..839d5d4 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "spectrum_ar_model_tables.h"
-#include "settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
/********************* AR Coefficient Tables ************************/
/* cdf for quantized reflection coefficient 1 */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h b/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h
index 989cb36..d272be0 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h
@@ -11,15 +11,15 @@
/*
* spectrum_ar_model_tables.h
*
- * This file contains definitions of tables with AR coefficients,
+ * This file contains definitions of tables with AR coefficients,
* Gain coefficients and cosine tables.
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_
-#include "structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
#define NUM_AR_RC_QUANT_BAUNDARY 12
@@ -45,15 +45,15 @@ extern const uint16_t WebRtcIsac_kQArRc6Cdf[NUM_AR_RC_QUANT_BAUNDARY];
/* quantization boundary levels for reflection coefficients */
extern const int16_t WebRtcIsac_kQArBoundaryLevels[NUM_AR_RC_QUANT_BAUNDARY];
-/* initial indices for AR reflection coefficient quantizer and cdf table search */
+/* initial indices for AR reflection coefficient quantizer and cdf table search
+ */
extern const uint16_t WebRtcIsac_kQArRcInitIndex[AR_ORDER];
/* pointers to AR cdf tables */
-extern const uint16_t *WebRtcIsac_kQArRcCdfPtr[AR_ORDER];
+extern const uint16_t* WebRtcIsac_kQArRcCdfPtr[AR_ORDER];
/* pointers to AR representation levels tables */
-extern const int16_t *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER];
-
+extern const int16_t* WebRtcIsac_kQArRcLevelsPtr[AR_ORDER];
/******************** GAIN Coefficient Tables ***********************/
/* cdf for Gain coefficient */
@@ -66,7 +66,7 @@ extern const int32_t WebRtcIsac_kQGain2Levels[18];
extern const int32_t WebRtcIsac_kQGain2BoundaryLevels[19];
/* pointer to Gain cdf table */
-extern const uint16_t *WebRtcIsac_kQGainCdf_ptr[1];
+extern const uint16_t* WebRtcIsac_kQGainCdf_ptr[1];
/* Gain initial index for gain quantizer and cdf table search */
extern const uint16_t WebRtcIsac_kQGainInitIndex[1];
@@ -75,4 +75,5 @@ extern const uint16_t WebRtcIsac_kQGainInitIndex[1];
/* Cosine table */
extern const int16_t WebRtcIsac_kCos[6][60];
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ \
+ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/structs.h b/webrtc/modules/audio_coding/codecs/isac/main/source/structs.h
index a2cdca2..6861ca4 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/structs.h
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/structs.h
@@ -15,187 +15,174 @@
*
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
+#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
+#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
-#include "webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/settings.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_coding/codecs/isac/bandwidth_info.h"
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/third_party/fft/fft.h"
typedef struct Bitstreamstruct {
-
- uint8_t stream[STREAM_SIZE_MAX];
- uint32_t W_upper;
- uint32_t streamval;
- uint32_t stream_index;
+ uint8_t stream[STREAM_SIZE_MAX];
+ uint32_t W_upper;
+ uint32_t streamval;
+ uint32_t stream_index;
} Bitstr;
typedef struct {
+ double DataBufferLo[WINLEN];
+ double DataBufferHi[WINLEN];
- double DataBufferLo[WINLEN];
- double DataBufferHi[WINLEN];
-
- double CorrBufLo[ORDERLO+1];
- double CorrBufHi[ORDERHI+1];
+ double CorrBufLo[ORDERLO + 1];
+ double CorrBufHi[ORDERHI + 1];
- float PreStateLoF[ORDERLO+1];
- float PreStateLoG[ORDERLO+1];
- float PreStateHiF[ORDERHI+1];
- float PreStateHiG[ORDERHI+1];
- float PostStateLoF[ORDERLO+1];
- float PostStateLoG[ORDERLO+1];
- float PostStateHiF[ORDERHI+1];
- float PostStateHiG[ORDERHI+1];
+ float PreStateLoF[ORDERLO + 1];
+ float PreStateLoG[ORDERLO + 1];
+ float PreStateHiF[ORDERHI + 1];
+ float PreStateHiG[ORDERHI + 1];
+ float PostStateLoF[ORDERLO + 1];
+ float PostStateLoG[ORDERLO + 1];
+ float PostStateHiF[ORDERHI + 1];
+ float PostStateHiG[ORDERHI + 1];
- double OldEnergy;
+ double OldEnergy;
} MaskFiltstr;
-
typedef struct {
-
- //state vectors for each of the two analysis filters
- double INSTAT1[2*(QORDER-1)];
- double INSTAT2[2*(QORDER-1)];
- double INSTATLA1[2*(QORDER-1)];
- double INSTATLA2[2*(QORDER-1)];
- double INLABUF1[QLOOKAHEAD];
- double INLABUF2[QLOOKAHEAD];
-
- float INSTAT1_float[2*(QORDER-1)];
- float INSTAT2_float[2*(QORDER-1)];
- float INSTATLA1_float[2*(QORDER-1)];
- float INSTATLA2_float[2*(QORDER-1)];
- float INLABUF1_float[QLOOKAHEAD];
- float INLABUF2_float[QLOOKAHEAD];
+ // state vectors for each of the two analysis filters
+ double INSTAT1[2 * (QORDER - 1)];
+ double INSTAT2[2 * (QORDER - 1)];
+ double INSTATLA1[2 * (QORDER - 1)];
+ double INSTATLA2[2 * (QORDER - 1)];
+ double INLABUF1[QLOOKAHEAD];
+ double INLABUF2[QLOOKAHEAD];
+
+ float INSTAT1_float[2 * (QORDER - 1)];
+ float INSTAT2_float[2 * (QORDER - 1)];
+ float INSTATLA1_float[2 * (QORDER - 1)];
+ float INSTATLA2_float[2 * (QORDER - 1)];
+ float INLABUF1_float[QLOOKAHEAD];
+ float INLABUF2_float[QLOOKAHEAD];
/* High pass filter */
- double HPstates[HPORDER];
- float HPstates_float[HPORDER];
+ double HPstates[HPORDER];
+ float HPstates_float[HPORDER];
} PreFiltBankstr;
-
typedef struct {
-
- //state vectors for each of the two analysis filters
- double STATE_0_LOWER[2*POSTQORDER];
- double STATE_0_UPPER[2*POSTQORDER];
+ // state vectors for each of the two analysis filters
+ double STATE_0_LOWER[2 * POSTQORDER];
+ double STATE_0_UPPER[2 * POSTQORDER];
/* High pass filter */
- double HPstates1[HPORDER];
- double HPstates2[HPORDER];
+ double HPstates1[HPORDER];
+ double HPstates2[HPORDER];
- float STATE_0_LOWER_float[2*POSTQORDER];
- float STATE_0_UPPER_float[2*POSTQORDER];
+ float STATE_0_LOWER_float[2 * POSTQORDER];
+ float STATE_0_UPPER_float[2 * POSTQORDER];
- float HPstates1_float[HPORDER];
- float HPstates2_float[HPORDER];
+ float HPstates1_float[HPORDER];
+ float HPstates2_float[HPORDER];
} PostFiltBankstr;
typedef struct {
+ // data buffer for pitch filter
+ double ubuf[PITCH_BUFFSIZE];
- //data buffer for pitch filter
- double ubuf[PITCH_BUFFSIZE];
-
- //low pass state vector
- double ystate[PITCH_DAMPORDER];
+ // low pass state vector
+ double ystate[PITCH_DAMPORDER];
- //old lag and gain
- double oldlagp[1];
- double oldgainp[1];
+ // old lag and gain
+ double oldlagp[1];
+ double oldgainp[1];
} PitchFiltstr;
typedef struct {
+ // data buffer
+ double buffer[PITCH_WLPCBUFLEN];
- //data buffer
- double buffer[PITCH_WLPCBUFLEN];
+ // state vectors
+ double istate[PITCH_WLPCORDER];
+ double weostate[PITCH_WLPCORDER];
+ double whostate[PITCH_WLPCORDER];
- //state vectors
- double istate[PITCH_WLPCORDER];
- double weostate[PITCH_WLPCORDER];
- double whostate[PITCH_WLPCORDER];
-
- //LPC window -> should be a global array because constant
- double window[PITCH_WLPCWINLEN];
+ // LPC window -> should be a global array because constant
+ double window[PITCH_WLPCWINLEN];
} WeightFiltstr;
typedef struct {
+ // for inital estimator
+ double dec_buffer[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + PITCH_MAX_LAG / 2 -
+ PITCH_FRAME_LEN / 2 + 2];
+ double decimator_state[2 * ALLPASSSECTIONS + 1];
+ double hp_state[2];
- //for inital estimator
- double dec_buffer[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 +
- PITCH_MAX_LAG/2 - PITCH_FRAME_LEN/2+2];
- double decimator_state[2*ALLPASSSECTIONS+1];
- double hp_state[2];
-
- double whitened_buf[QLOOKAHEAD];
+ double whitened_buf[QLOOKAHEAD];
- double inbuf[QLOOKAHEAD];
+ double inbuf[QLOOKAHEAD];
- PitchFiltstr PFstr_wght;
- PitchFiltstr PFstr;
+ PitchFiltstr PFstr_wght;
+ PitchFiltstr PFstr;
WeightFiltstr Wghtstr;
} PitchAnalysisStruct;
-
-
/* Have instance of struct together with other iSAC structs */
typedef struct {
-
/* Previous frame length (in ms) */
- int32_t prev_frame_length;
+ int32_t prev_frame_length;
/* Previous RTP timestamp from received
packet (in samples relative beginning) */
- int32_t prev_rec_rtp_number;
+ int32_t prev_rec_rtp_number;
/* Send timestamp for previous packet (in ms using timeGetTime()) */
- uint32_t prev_rec_send_ts;
+ uint32_t prev_rec_send_ts;
/* Arrival time for previous packet (in ms using timeGetTime()) */
- uint32_t prev_rec_arr_ts;
+ uint32_t prev_rec_arr_ts;
/* rate of previous packet, derived from RTP timestamps (in bits/s) */
- float prev_rec_rtp_rate;
+ float prev_rec_rtp_rate;
/* Time sinse the last update of the BN estimate (in ms) */
- uint32_t last_update_ts;
+ uint32_t last_update_ts;
/* Time sinse the last reduction (in ms) */
- uint32_t last_reduction_ts;
+ uint32_t last_reduction_ts;
/* How many times the estimate was update in the beginning */
- int32_t count_tot_updates_rec;
+ int32_t count_tot_updates_rec;
/* The estimated bottle neck rate from there to here (in bits/s) */
- int32_t rec_bw;
- float rec_bw_inv;
- float rec_bw_avg;
- float rec_bw_avg_Q;
+ int32_t rec_bw;
+ float rec_bw_inv;
+ float rec_bw_avg;
+ float rec_bw_avg_Q;
/* The estimated mean absolute jitter value,
as seen on this side (in ms) */
- float rec_jitter;
- float rec_jitter_short_term;
- float rec_jitter_short_term_abs;
- float rec_max_delay;
- float rec_max_delay_avg_Q;
+ float rec_jitter;
+ float rec_jitter_short_term;
+ float rec_jitter_short_term_abs;
+ float rec_max_delay;
+ float rec_max_delay_avg_Q;
/* (assumed) bitrate for headers (bps) */
- float rec_header_rate;
+ float rec_header_rate;
/* The estimated bottle neck rate from here to there (in bits/s) */
- float send_bw_avg;
+ float send_bw_avg;
/* The estimated mean absolute jitter value, as seen on
the other siee (in ms) */
- float send_max_delay_avg;
+ float send_max_delay_avg;
// number of packets received since last update
int num_pkts_rec;
@@ -218,72 +205,54 @@ typedef struct {
int change_to_WB;
- uint32_t senderTimestamp;
- uint32_t receiverTimestamp;
- //enum IsacSamplingRate incomingStreamSampFreq;
- uint16_t numConsecLatePkts;
- float consecLatency;
- int16_t inWaitLatePkts;
+ uint32_t senderTimestamp;
+ uint32_t receiverTimestamp;
+ // enum IsacSamplingRate incomingStreamSampFreq;
+ uint16_t numConsecLatePkts;
+ float consecLatency;
+ int16_t inWaitLatePkts;
IsacBandwidthInfo external_bw_info;
} BwEstimatorstr;
-
typedef struct {
-
/* boolean, flags if previous packet exceeded B.N. */
- int PrevExceed;
+ int PrevExceed;
/* ms */
- int ExceedAgo;
+ int ExceedAgo;
/* packets left to send in current burst */
- int BurstCounter;
+ int BurstCounter;
/* packets */
- int InitCounter;
+ int InitCounter;
/* ms remaining in buffer when next packet will be sent */
double StillBuffered;
} RateModel;
-
-typedef struct {
-
- unsigned int SpaceAlloced;
- unsigned int MaxPermAlloced;
- double Tmp0[MAXFFTSIZE];
- double Tmp1[MAXFFTSIZE];
- double Tmp2[MAXFFTSIZE];
- double Tmp3[MAXFFTSIZE];
- int Perm[MAXFFTSIZE];
- int factor [NFACTOR];
-
-} FFTstr;
-
-
/* The following strutc is used to store data from encoding, to make it
fast and easy to construct a new bitstream with a different Bandwidth
estimate. All values (except framelength and minBytes) is double size to
handle 60 ms of data.
*/
typedef struct {
-
/* Used to keep track of if it is first or second part of 60 msec packet */
- int startIdx;
+ int startIdx;
/* Frame length in samples */
int16_t framelength;
/* Pitch Gain */
- int pitchGain_index[2];
+ int pitchGain_index[2];
/* Pitch Lag */
- double meanGain[2];
- int pitchIndex[PITCH_SUBFRAMES*2];
+ double meanGain[2];
+ int pitchIndex[PITCH_SUBFRAMES * 2];
/* LPC */
- int LPCindex_s[108*2]; /* KLT_ORDER_SHAPE = 108 */
- int LPCindex_g[12*2]; /* KLT_ORDER_GAIN = 12 */
- double LPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*2];
- double LPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*2];
+ int LPCindex_s[108 * 2]; /* KLT_ORDER_SHAPE = 108 */
+ int LPCindex_g[12 * 2]; /* KLT_ORDER_GAIN = 12 */
+ double LPCcoeffs_lo[(ORDERLO + 1) * SUBFRAMES * 2];
+ double LPCcoeffs_hi[(ORDERHI + 1) * SUBFRAMES * 2];
/* Encode Spec */
int16_t fre[FRAMESAMPLES];
@@ -291,125 +260,109 @@ typedef struct {
int16_t AvgPitchGain[2];
/* Used in adaptive mode only */
- int minBytes;
+ int minBytes;
} IsacSaveEncoderData;
-
typedef struct {
+ int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
+ double lpcGain[SUBFRAMES << 1];
+ int lpcGainIndex[SUBFRAMES << 1];
- int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
- double lpcGain[SUBFRAMES<<1];
- int lpcGainIndex[SUBFRAMES<<1];
-
- Bitstr bitStreamObj;
+ Bitstr bitStreamObj;
int16_t realFFT[FRAMESAMPLES_HALF];
int16_t imagFFT[FRAMESAMPLES_HALF];
} ISACUBSaveEncDataStruct;
-
-
typedef struct {
-
- Bitstr bitstr_obj;
- MaskFiltstr maskfiltstr_obj;
- PreFiltBankstr prefiltbankstr_obj;
- PitchFiltstr pitchfiltstr_obj;
+ Bitstr bitstr_obj;
+ MaskFiltstr maskfiltstr_obj;
+ PreFiltBankstr prefiltbankstr_obj;
+ PitchFiltstr pitchfiltstr_obj;
PitchAnalysisStruct pitchanalysisstr_obj;
- FFTstr fftstr_obj;
+ FFTstr fftstr_obj;
IsacSaveEncoderData SaveEnc_obj;
- int buffer_index;
- int16_t current_framesamples;
+ int buffer_index;
+ int16_t current_framesamples;
- float data_buffer_float[FRAMESAMPLES_30ms];
+ float data_buffer_float[FRAMESAMPLES_30ms];
- int frame_nb;
- double bottleneck;
- int16_t new_framelength;
- double s2nr;
+ int frame_nb;
+ double bottleneck;
+ int16_t new_framelength;
+ double s2nr;
/* Maximum allowed number of bits for a 30 msec packet */
- int16_t payloadLimitBytes30;
+ int16_t payloadLimitBytes30;
/* Maximum allowed number of bits for a 30 msec packet */
- int16_t payloadLimitBytes60;
+ int16_t payloadLimitBytes60;
/* Maximum allowed number of bits for both 30 and 60 msec packet */
- int16_t maxPayloadBytes;
+ int16_t maxPayloadBytes;
/* Maximum allowed rate in bytes per 30 msec packet */
- int16_t maxRateInBytes;
+ int16_t maxRateInBytes;
/*---
- If set to 1 iSAC will not addapt the frame-size, if used in
+ If set to 1 iSAC will not adapt the frame-size, if used in
channel-adaptive mode. The initial value will be used for all rates.
---*/
- int16_t enforceFrameSize;
+ int16_t enforceFrameSize;
/*-----
This records the BWE index the encoder injected into the bit-stream.
It will be used in RCU. The same BWE index of main payload will be in
- the redundant payload. We can not retrive it from BWE because it is
+ the redundant payload. We can not retrieve it from BWE because it is
a recursive procedure (WebRtcIsac_GetDownlinkBwJitIndexImpl) and has to be
called only once per each encode.
-----*/
- int16_t lastBWIdx;
+ int16_t lastBWIdx;
} ISACLBEncStruct;
typedef struct {
-
- Bitstr bitstr_obj;
- MaskFiltstr maskfiltstr_obj;
- PreFiltBankstr prefiltbankstr_obj;
- FFTstr fftstr_obj;
+ Bitstr bitstr_obj;
+ MaskFiltstr maskfiltstr_obj;
+ PreFiltBankstr prefiltbankstr_obj;
+ FFTstr fftstr_obj;
ISACUBSaveEncDataStruct SaveEnc_obj;
- int buffer_index;
- float data_buffer_float[MAX_FRAMESAMPLES +
- LB_TOTAL_DELAY_SAMPLES];
- double bottleneck;
+ int buffer_index;
+ float data_buffer_float[MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES];
+ double bottleneck;
/* Maximum allowed number of bits for a 30 msec packet */
- //int16_t payloadLimitBytes30;
+ // int16_t payloadLimitBytes30;
/* Maximum allowed number of bits for both 30 and 60 msec packet */
- //int16_t maxPayloadBytes;
- int16_t maxPayloadSizeBytes;
+ // int16_t maxPayloadBytes;
+ int16_t maxPayloadSizeBytes;
- double lastLPCVec[UB_LPC_ORDER];
- int16_t numBytesUsed;
- int16_t lastJitterInfo;
+ double lastLPCVec[UB_LPC_ORDER];
+ int16_t numBytesUsed;
+ int16_t lastJitterInfo;
} ISACUBEncStruct;
-
-
typedef struct {
-
- Bitstr bitstr_obj;
- MaskFiltstr maskfiltstr_obj;
+ Bitstr bitstr_obj;
+ MaskFiltstr maskfiltstr_obj;
PostFiltBankstr postfiltbankstr_obj;
- PitchFiltstr pitchfiltstr_obj;
- FFTstr fftstr_obj;
+ PitchFiltstr pitchfiltstr_obj;
+ FFTstr fftstr_obj;
} ISACLBDecStruct;
typedef struct {
-
- Bitstr bitstr_obj;
- MaskFiltstr maskfiltstr_obj;
+ Bitstr bitstr_obj;
+ MaskFiltstr maskfiltstr_obj;
PostFiltBankstr postfiltbankstr_obj;
- FFTstr fftstr_obj;
+ FFTstr fftstr_obj;
} ISACUBDecStruct;
-
-
typedef struct {
-
ISACLBEncStruct ISACencLB_obj;
ISACLBDecStruct ISACdecLB_obj;
} ISACLBStruct;
-
typedef struct {
-
ISACUBEncStruct ISACencUB_obj;
ISACUBDecStruct ISACdecUB_obj;
} ISACUBStruct;
@@ -421,14 +374,14 @@ typedef struct {
*/
typedef struct {
/* 6 lower-band & 6 upper-band */
- double loFiltGain[SUBFRAMES];
- double hiFiltGain[SUBFRAMES];
+ double loFiltGain[SUBFRAMES];
+ double hiFiltGain[SUBFRAMES];
/* Upper boundary of interval W */
uint32_t W_upper;
uint32_t streamval;
/* Index to the current position in bytestream */
uint32_t stream_index;
- uint8_t stream[3];
+ uint8_t stream[3];
} transcode_obj;
typedef struct {
@@ -444,46 +397,46 @@ typedef struct {
typedef struct {
// lower-band codec instance
- ISACLBStruct instLB;
+ ISACLBStruct instLB;
// upper-band codec instance
- ISACUBStruct instUB;
+ ISACUBStruct instUB;
// Bandwidth Estimator and model for the rate.
- BwEstimatorstr bwestimator_obj;
- RateModel rate_data_obj;
- double MaxDelay;
+ BwEstimatorstr bwestimator_obj;
+ RateModel rate_data_obj;
+ double MaxDelay;
/* 0 = adaptive; 1 = instantaneous */
- int16_t codingMode;
+ int16_t codingMode;
// overall bottleneck of the codec
- int32_t bottleneck;
+ int32_t bottleneck;
// QMF Filter state
- int32_t analysisFBState1[FB_STATE_SIZE_WORD32];
- int32_t analysisFBState2[FB_STATE_SIZE_WORD32];
- int32_t synthesisFBState1[FB_STATE_SIZE_WORD32];
- int32_t synthesisFBState2[FB_STATE_SIZE_WORD32];
+ int32_t analysisFBState1[FB_STATE_SIZE_WORD32];
+ int32_t analysisFBState2[FB_STATE_SIZE_WORD32];
+ int32_t synthesisFBState1[FB_STATE_SIZE_WORD32];
+ int32_t synthesisFBState2[FB_STATE_SIZE_WORD32];
// Error Code
- int16_t errorCode;
+ int16_t errorCode;
// bandwidth of the encoded audio 8, 12 or 16 kHz
- enum ISACBandwidth bandwidthKHz;
+ enum ISACBandwidth bandwidthKHz;
// Sampling rate of audio, encoder and decode, 8 or 16 kHz
enum IsacSamplingRate encoderSamplingRateKHz;
enum IsacSamplingRate decoderSamplingRateKHz;
// Flag to keep track of initializations, lower & upper-band
// encoder and decoder.
- int16_t initFlag;
+ int16_t initFlag;
// Flag to to indicate signal bandwidth switch
- int16_t resetFlag_8kHz;
+ int16_t resetFlag_8kHz;
// Maximum allowed rate, measured in Bytes per 30 ms.
- int16_t maxRateBytesPer30Ms;
+ int16_t maxRateBytesPer30Ms;
// Maximum allowed payload-size, measured in Bytes.
- int16_t maxPayloadSizeBytes;
+ int16_t maxPayloadSizeBytes;
/* The expected sampling rate of the input signal. Valid values are 16000
* and 32000. This is not the operation sampling rate of the codec. */
uint16_t in_sample_rate_hz;
@@ -492,4 +445,4 @@ typedef struct {
TransformTables transform_tables;
} ISACMainStruct;
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */
+#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c b/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c
index 8992897..082ad94 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/transform.c
@@ -8,12 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "settings.h"
-#include "fft.h"
-#include "codec.h"
-#include "os_specific_inline.h"
#include <math.h>
+#include "modules/audio_coding/codecs/isac/main/source/settings.h"
+#include "modules/audio_coding/codecs/isac/main/source/codec.h"
+#include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
+#include "modules/third_party/fft/fft.h"
+
void WebRtcIsac_InitTransform(TransformTables* tables) {
int k;
double fact, phase;
diff --git a/webrtc/modules/audio_coding/meson.build b/webrtc/modules/audio_coding/meson.build
index fb46df8..983d3fb 100644
--- a/webrtc/modules/audio_coding/meson.build
+++ b/webrtc/modules/audio_coding/meson.build
@@ -2,12 +2,21 @@ webrtc_audio_coding_sources = [
'codecs/isac/main/source/arith_routines.c',
'codecs/isac/main/source/arith_routines_hist.c',
'codecs/isac/main/source/arith_routines_logist.c',
+ 'codecs/isac/main/source/audio_decoder_isac.cc',
+ 'codecs/isac/main/source/audio_encoder_isac.cc',
+ 'codecs/isac/main/source/bandwidth_estimator.c',
+ 'codecs/isac/main/source/crc.c',
+ 'codecs/isac/main/source/decode_bwe.c',
+ 'codecs/isac/main/source/decode.c',
+ 'codecs/isac/main/source/encode.c',
'codecs/isac/main/source/encode_lpc_swb.c',
'codecs/isac/main/source/entropy_coding.c',
- 'codecs/isac/main/source/filter_functions.c',
'codecs/isac/main/source/filterbanks.c',
- 'codecs/isac/main/source/filterbank_tables.c',
+ 'codecs/isac/main/source/filter_functions.c',
'codecs/isac/main/source/intialize.c',
+ 'codecs/isac/main/source/isac.c',
+ 'codecs/isac/main/source/isac_vad.c',
+ 'codecs/isac/main/source/lattice.c',
'codecs/isac/main/source/lpc_analysis.c',
'codecs/isac/main/source/lpc_gain_swb_tables.c',
'codecs/isac/main/source/lpc_shape_swb12_tables.c',
@@ -18,24 +27,12 @@ webrtc_audio_coding_sources = [
'codecs/isac/main/source/pitch_gain_tables.c',
'codecs/isac/main/source/pitch_lag_tables.c',
'codecs/isac/main/source/spectrum_ar_model_tables.c',
- 'codecs/audio_decoder.cc',
- 'codecs/audio_encoder.cc',
- 'codecs/isac/main/source/audio_decoder_isac.cc',
- 'codecs/isac/main/source/audio_encoder_isac.cc',
- 'codecs/isac/main/source/bandwidth_estimator.c',
- 'codecs/isac/main/source/crc.c',
- 'codecs/isac/main/source/decode.c',
- 'codecs/isac/main/source/decode_bwe.c',
- 'codecs/isac/main/source/encode.c',
- 'codecs/isac/main/source/fft.c',
- 'codecs/isac/main/source/isac.c',
- 'codecs/isac/main/source/lattice.c',
'codecs/isac/main/source/transform.c',
]
libwebrtc_audio_coding = library('webrtc_audio_coding',
webrtc_audio_coding_sources,
- dependencies: [base_dep, common_audio_dep] + common_deps,
+ dependencies: [base_dep, api_dep, common_audio_dep, system_wrappers_dep, fft_dep] + common_deps,
include_directories: webrtc_inc,
c_args: common_cflags,
cpp_args: common_cxxflags,
@@ -50,13 +47,13 @@ webrtc_audio_coding_dep = declare_dependency(
)
install_headers(['codecs/isac/bandwidth_info.h'],
- subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac'
+ subdir: 'webrtc_audio_processing/modules/audio_coding/codecs/isac'
)
install_headers(['codecs/isac/main/source/settings.h'],
- subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac/main/source'
+ subdir: 'webrtc_audio_processing/modules/audio_coding/codecs/isac/main/source'
)
install_headers(['codecs/isac/main/include/isac.h'],
- subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac/main/include'
+ subdir: 'webrtc_audio_processing/modules/audio_coding/codecs/isac/main/include'
)
diff --git a/webrtc/modules/audio_processing/BUILD.gn b/webrtc/modules/audio_processing/BUILD.gn
index 2d0c602..dbb1882 100644
--- a/webrtc/modules/audio_processing/BUILD.gn
+++ b/webrtc/modules/audio_processing/BUILD.gn
@@ -6,281 +6,606 @@
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
-import("//build/config/arm.gni")
-import("//third_party/protobuf/proto_library.gni")
-import("../../build/webrtc.gni")
-
-declare_args() {
- # Outputs some low-level debug files.
- aec_debug_dump = false
-
- # Disables the usual mode where we trust the reported system delay
- # values the AEC receives. The corresponding define is set appropriately
- # in the code, but it can be force-enabled here for testing.
- aec_untrusted_delay_for_testing = false
+import("../../webrtc.gni")
+if (rtc_enable_protobuf) {
+ import("//third_party/protobuf/proto_library.gni")
+}
+
+config("apm_debug_dump") {
+ if (apm_debug_dump) {
+ defines = [ "WEBRTC_APM_DEBUG_DUMP=1" ]
+ } else {
+ defines = [ "WEBRTC_APM_DEBUG_DUMP=0" ]
+ }
+}
+
+rtc_library("config") {
+ visibility = [ ":*" ]
+ sources = [
+ "include/config.cc",
+ "include/config.h",
+ ]
+ deps = [ "../../rtc_base/system:rtc_export" ]
}
-source_set("audio_processing") {
+rtc_library("api") {
+ visibility = [ "*" ]
+ sources = [
+ "include/audio_processing.cc",
+ "include/audio_processing.h",
+ ]
+ deps = [
+ ":audio_frame_view",
+ ":audio_processing_statistics",
+ ":config",
+ "../../api:array_view",
+ "../../api:scoped_refptr",
+ "../../api/audio:aec3_config",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio:echo_control",
+ "../../rtc_base:deprecation",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base/system:arch",
+ "../../rtc_base/system:file_wrapper",
+ "../../rtc_base/system:rtc_export",
+ "agc:gain_control_interface",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_library("audio_frame_proxies") {
+ visibility = [ "*" ]
+ sources = [
+ "include/audio_frame_proxies.cc",
+ "include/audio_frame_proxies.h",
+ ]
+ deps = [
+ ":api",
+ ":audio_frame_view",
+ "../../api/audio:audio_frame_api",
+ ]
+}
+
+rtc_library("audio_buffer") {
+ visibility = [ "*" ]
+
+ configs += [ ":apm_debug_dump" ]
+
sources = [
- "aec/aec_core.c",
- "aec/aec_core.h",
- "aec/aec_core_internal.h",
- "aec/aec_rdft.c",
- "aec/aec_rdft.h",
- "aec/aec_resampler.c",
- "aec/aec_resampler.h",
- "aec/echo_cancellation.c",
- "aec/echo_cancellation_internal.h",
- "aec/include/echo_cancellation.h",
- "aecm/aecm_core.c",
- "aecm/aecm_core.h",
- "aecm/echo_control_mobile.c",
- "aecm/include/echo_control_mobile.h",
- "agc/agc.cc",
- "agc/agc.h",
- "agc/agc_manager_direct.cc",
- "agc/agc_manager_direct.h",
- "agc/gain_map_internal.h",
- "agc/histogram.cc",
- "agc/histogram.h",
- "agc/legacy/analog_agc.c",
- "agc/legacy/analog_agc.h",
- "agc/legacy/digital_agc.c",
- "agc/legacy/digital_agc.h",
- "agc/legacy/gain_control.h",
- "agc/utility.cc",
- "agc/utility.h",
"audio_buffer.cc",
"audio_buffer.h",
+ "splitting_filter.cc",
+ "splitting_filter.h",
+ "three_band_filter_bank.cc",
+ "three_band_filter_bank.h",
+ ]
+
+ defines = []
+
+ deps = [
+ ":api",
+ "../../api:array_view",
+ "../../common_audio",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:checks",
+ ]
+}
+
+rtc_library("high_pass_filter") {
+ visibility = [ "*" ]
+
+ sources = [
+ "high_pass_filter.cc",
+ "high_pass_filter.h",
+ ]
+
+ defines = []
+
+ deps = [
+ ":audio_buffer",
+ "../../api:array_view",
+ "../../rtc_base:checks",
+ "utility:cascaded_biquad_filter",
+ ]
+}
+
+rtc_source_set("aec_dump_interface") {
+ visibility = [ "*" ]
+ sources = [
+ "include/aec_dump.cc",
+ "include/aec_dump.h",
+ ]
+
+ deps = [
+ ":api",
+ ":audio_frame_view",
+ "../../rtc_base:deprecation",
+ ]
+}
+
+rtc_library("audio_processing") {
+ visibility = [ "*" ]
+ configs += [ ":apm_debug_dump" ]
+ sources = [
+ "audio_processing_builder_impl.cc",
"audio_processing_impl.cc",
"audio_processing_impl.h",
- "beamformer/array_util.cc",
- "beamformer/array_util.h",
- "beamformer/beamformer.h",
- "beamformer/complex_matrix.h",
- "beamformer/covariance_matrix_generator.cc",
- "beamformer/covariance_matrix_generator.h",
- "beamformer/matrix.h",
- "beamformer/nonlinear_beamformer.cc",
- "beamformer/nonlinear_beamformer.h",
"common.h",
- "echo_cancellation_impl.cc",
- "echo_cancellation_impl.h",
"echo_control_mobile_impl.cc",
"echo_control_mobile_impl.h",
+ "echo_detector/circular_buffer.cc",
+ "echo_detector/circular_buffer.h",
+ "echo_detector/mean_variance_estimator.cc",
+ "echo_detector/mean_variance_estimator.h",
+ "echo_detector/moving_max.cc",
+ "echo_detector/moving_max.h",
+ "echo_detector/normalized_covariance_estimator.cc",
+ "echo_detector/normalized_covariance_estimator.h",
"gain_control_impl.cc",
"gain_control_impl.h",
- "high_pass_filter_impl.cc",
- "high_pass_filter_impl.h",
- "include/audio_processing.h",
- "intelligibility/intelligibility_enhancer.cc",
- "intelligibility/intelligibility_enhancer.h",
- "intelligibility/intelligibility_utils.cc",
- "intelligibility/intelligibility_utils.h",
- "level_estimator_impl.cc",
- "level_estimator_impl.h",
- "logging/aec_logging.h",
- "logging/aec_logging_file_handling.cc",
- "logging/aec_logging_file_handling.h",
- "noise_suppression_impl.cc",
- "noise_suppression_impl.h",
- "processing_component.cc",
- "processing_component.h",
- "rms_level.cc",
- "rms_level.h",
- "splitting_filter.cc",
- "splitting_filter.h",
- "three_band_filter_bank.cc",
- "three_band_filter_bank.h",
- "transient/common.h",
- "transient/daubechies_8_wavelet_coeffs.h",
- "transient/dyadic_decimator.h",
- "transient/moving_moments.cc",
- "transient/moving_moments.h",
- "transient/transient_detector.cc",
- "transient/transient_detector.h",
- "transient/transient_suppressor.cc",
- "transient/transient_suppressor.h",
- "transient/wpd_node.cc",
- "transient/wpd_node.h",
- "transient/wpd_tree.cc",
- "transient/wpd_tree.h",
+ "gain_controller2.cc",
+ "gain_controller2.h",
+ "level_estimator.cc",
+ "level_estimator.h",
+ "render_queue_item_verifier.h",
+ "residual_echo_detector.cc",
+ "residual_echo_detector.h",
"typing_detection.cc",
"typing_detection.h",
- "utility/delay_estimator.c",
- "utility/delay_estimator.h",
- "utility/delay_estimator_internal.h",
- "utility/delay_estimator_wrapper.c",
- "utility/delay_estimator_wrapper.h",
- "vad/common.h",
- "vad/gmm.cc",
- "vad/gmm.h",
- "vad/noise_gmm_tables.h",
- "vad/pitch_based_vad.cc",
- "vad/pitch_based_vad.h",
- "vad/pitch_internal.cc",
- "vad/pitch_internal.h",
- "vad/pole_zero_filter.cc",
- "vad/pole_zero_filter.h",
- "vad/standalone_vad.cc",
- "vad/standalone_vad.h",
- "vad/vad_audio_proc.cc",
- "vad/vad_audio_proc.h",
- "vad/vad_audio_proc_internal.h",
- "vad/vad_circular_buffer.cc",
- "vad/vad_circular_buffer.h",
- "vad/voice_activity_detector.cc",
- "vad/voice_activity_detector.h",
- "vad/voice_gmm_tables.h",
- "voice_detection_impl.cc",
- "voice_detection_impl.h",
]
- configs += [ "../..:common_config" ]
- public_configs = [ "../..:common_inherited_config" ]
-
defines = []
deps = [
- "../..:webrtc_common",
- "../audio_coding:isac",
+ ":aec_dump_interface",
+ ":api",
+ ":apm_logging",
+ ":audio_buffer",
+ ":audio_frame_proxies",
+ ":audio_frame_view",
+ ":audio_processing_statistics",
+ ":config",
+ ":high_pass_filter",
+ ":optionally_built_submodule_creators",
+ ":rms_level",
+ ":voice_detection",
+ "../../api:array_view",
+ "../../api:function_view",
+ "../../api/audio:aec3_config",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio:echo_control",
+ "../../audio/utility:audio_frame_operations",
+ "../../common_audio:common_audio_c",
+ "../../common_audio/third_party/ooura:fft_size_256",
+ "../../rtc_base:checks",
+ "../../rtc_base:deprecation",
+ "../../rtc_base:gtest_prod",
+ "../../rtc_base:ignore_wundef",
+ "../../rtc_base:refcount",
+ "../../rtc_base:safe_minmax",
+ "../../rtc_base:sanitizer",
+ "../../rtc_base/synchronization:mutex",
+ "../../rtc_base/system:rtc_export",
+ "../../system_wrappers",
+ "../../system_wrappers:field_trial",
+ "../../system_wrappers:metrics",
+ "aec3",
+ "aec_dump:aec_dump",
+ "aecm:aecm_core",
+ "agc",
+ "agc:gain_control_interface",
+ "agc:legacy_agc",
+ "agc2:adaptive_digital",
+ "agc2:fixed_digital",
+ "agc2:gain_applier",
+ "ns",
+ "transient:transient_suppressor_api",
+ "vad",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
- if (aec_debug_dump) {
- defines += [ "WEBRTC_AEC_DEBUG_DUMP" ]
- }
-
- if (aec_untrusted_delay_for_testing) {
- defines += [ "WEBRTC_UNTRUSTED_DELAY" ]
- }
+ deps += [
+ "../../common_audio",
+ "../../common_audio:fir_filter",
+ "../../common_audio:fir_filter_factory",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers",
+ ]
if (rtc_enable_protobuf) {
- defines += [ "WEBRTC_AUDIOPROC_DEBUG_DUMP" ]
- deps += [ ":audioproc_debug_proto" ]
- }
-
- if (rtc_prefer_fixed_point) {
- defines += [ "WEBRTC_NS_FIXED" ]
- sources += [
- "ns/include/noise_suppression_x.h",
- "ns/noise_suppression_x.c",
- "ns/nsx_core.c",
- "ns/nsx_core.h",
- "ns/nsx_defines.h",
- ]
- if (current_cpu == "mipsel") {
- sources += [ "ns/nsx_core_mips.c" ]
- } else {
- sources += [ "ns/nsx_core_c.c" ]
- }
+ deps += [ "aec_dump:aec_dump_impl" ]
} else {
- defines += [ "WEBRTC_NS_FLOAT" ]
- sources += [
- "ns/defines.h",
- "ns/include/noise_suppression.h",
- "ns/noise_suppression.c",
- "ns/ns_core.c",
- "ns/ns_core.h",
- "ns/windows_private.h",
- ]
+ deps += [ "aec_dump:null_aec_dump_factory" ]
}
+}
- if (current_cpu == "x86" || current_cpu == "x64") {
- deps += [ ":audio_processing_sse2" ]
- }
+rtc_library("voice_detection") {
+ sources = [
+ "voice_detection.cc",
+ "voice_detection.h",
+ ]
+ deps = [
+ ":api",
+ ":audio_buffer",
+ "../../api/audio:audio_frame_api",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base:checks",
+ ]
+}
- if (rtc_build_with_neon) {
- deps += [ ":audio_processing_neon" ]
- }
+rtc_library("optionally_built_submodule_creators") {
+ sources = [
+ "optionally_built_submodule_creators.cc",
+ "optionally_built_submodule_creators.h",
+ ]
+ deps = [
+ "transient:transient_suppressor_api",
+ "transient:transient_suppressor_impl",
+ ]
+}
- if (current_cpu == "mipsel") {
- sources += [ "aecm/aecm_core_mips.c" ]
- if (mips_float_abi == "hard") {
- sources += [
- "aec/aec_core_mips.c",
- "aec/aec_rdft_mips.c",
- ]
- }
- } else {
- sources += [ "aecm/aecm_core_c.c" ]
- }
+rtc_source_set("rms_level") {
+ visibility = [ "*" ]
+ sources = [
+ "rms_level.cc",
+ "rms_level.h",
+ ]
+ deps = [
+ "../../api:array_view",
+ "../../rtc_base:checks",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
- if (is_win) {
- cflags = [
- # TODO(jschuh): Bug 1348: fix this warning.
- "/wd4267", # size_t to int truncations
- ]
- }
+rtc_library("audio_processing_statistics") {
+ visibility = [ "*" ]
+ sources = [
+ "include/audio_processing_statistics.cc",
+ "include/audio_processing_statistics.h",
+ ]
+ deps = [ "../../rtc_base/system:rtc_export" ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_source_set("audio_frame_view") {
+ sources = [ "include/audio_frame_view.h" ]
+ deps = [ "../../api:array_view" ]
+}
+
+if (rtc_enable_protobuf) {
+ proto_library("audioproc_debug_proto") {
+ sources = [ "debug.proto" ]
- if (is_clang) {
- # Suppress warnings from Chrome's Clang plugins.
- # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
- configs -= [ "//build/config/clang:find_bad_constructs" ]
+ proto_out_dir = "modules/audio_processing"
}
+}
- deps += [
- "../../base:rtc_base_approved",
+rtc_library("apm_logging") {
+ configs += [ ":apm_debug_dump" ]
+ sources = [
+ "logging/apm_data_dumper.cc",
+ "logging/apm_data_dumper.h",
+ ]
+ deps = [
+ "../../api:array_view",
"../../common_audio",
- "../../system_wrappers",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
]
+ defines = []
}
-if (rtc_enable_protobuf) {
- proto_library("audioproc_debug_proto") {
- sources = [
- "debug.proto",
+if (rtc_include_tests) {
+ rtc_source_set("mocks") {
+ testonly = true
+ sources = [ "include/mock_audio_processing.h" ]
+ deps = [
+ ":aec_dump_interface",
+ ":api",
+ ":audio_buffer",
+ ":audio_processing",
+ ":audio_processing_statistics",
+ "../../test:test_support",
]
-
- proto_out_dir = "webrtc/audio_processing"
}
-}
-if (current_cpu == "x86" || current_cpu == "x64") {
- source_set("audio_processing_sse2") {
- sources = [
- "aec/aec_core_sse2.c",
- "aec/aec_rdft_sse2.c",
+ group("audio_processing_tests") {
+ testonly = true
+ deps = [
+ ":audioproc_test_utils",
+ "transient:click_annotate",
+ "transient:transient_suppression_test",
]
- if (is_posix) {
- cflags = [ "-msse2" ]
+ if (rtc_enable_protobuf) {
+ deps += [
+ ":audioproc_unittest_proto",
+ "aec_dump:aec_dump_unittests",
+ "test/conversational_speech",
+ "test/py_quality_assessment",
+ ]
}
-
- configs += [ "../..:common_config" ]
- public_configs = [ "../..:common_inherited_config" ]
}
-}
-if (rtc_build_with_neon) {
- source_set("audio_processing_neon") {
+ rtc_library("audio_processing_unittests") {
+ testonly = true
+
+ configs += [ ":apm_debug_dump" ]
sources = [
- "aec/aec_core_neon.c",
- "aec/aec_rdft_neon.c",
- "aecm/aecm_core_neon.c",
- "ns/nsx_core_neon.c",
+ "audio_buffer_unittest.cc",
+ "audio_frame_view_unittest.cc",
+ "config_unittest.cc",
+ "echo_control_mobile_unittest.cc",
+ "gain_controller2_unittest.cc",
+ "splitting_filter_unittest.cc",
+ "test/fake_recording_device_unittest.cc",
+ ]
+
+ deps = [
+ ":analog_mic_simulation",
+ ":api",
+ ":apm_logging",
+ ":audio_buffer",
+ ":audio_frame_view",
+ ":audio_processing",
+ ":audioproc_test_utils",
+ ":config",
+ ":high_pass_filter",
+ ":mocks",
+ ":voice_detection",
+ "../../api:array_view",
+ "../../api:scoped_refptr",
+ "../../api/audio:aec3_config",
+ "../../api/audio:aec3_factory",
+ "../../common_audio",
+ "../../common_audio:common_audio_c",
+ "../../rtc_base",
+ "../../rtc_base:checks",
+ "../../rtc_base:gtest_prod",
+ "../../rtc_base:ignore_wundef",
+ "../../rtc_base:protobuf_utils",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:rtc_base_tests_utils",
+ "../../rtc_base:safe_minmax",
+ "../../rtc_base:task_queue_for_test",
+ "../../rtc_base/synchronization:mutex",
+ "../../rtc_base/system:arch",
+ "../../rtc_base/system:file_wrapper",
+ "../../system_wrappers",
+ "../../test:fileutils",
+ "../../test:rtc_expect_death",
+ "../../test:test_support",
+ "../audio_coding:neteq_input_audio_tools",
+ "aec_dump:mock_aec_dump_unittests",
+ "agc:agc_unittests",
+ "agc2:adaptive_digital_unittests",
+ "agc2:biquad_filter_unittests",
+ "agc2:fixed_digital_unittests",
+ "agc2:noise_estimator_unittests",
+ "agc2:rnn_vad_with_level_unittests",
+ "agc2:test_utils",
+ "agc2/rnn_vad:unittests",
+ "test/conversational_speech:unittest",
+ "transient:transient_suppression_unittests",
+ "utility:legacy_delay_estimator_unittest",
+ "utility:pffft_wrapper_unittest",
+ "vad:vad_unittests",
+ "//testing/gtest",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+
+ defines = []
- if (current_cpu != "arm64") {
- # Enable compilation for the NEON instruction set. This is needed
- # since //build/config/arm.gni only enables NEON for iOS, not Android.
- # This provides the same functionality as webrtc/build/arm_neon.gypi.
- configs -= [ "//build/config/compiler:compiler_arm_fpu" ]
- cflags = [ "-mfpu=neon" ]
+ if (rtc_prefer_fixed_point) {
+ defines += [ "WEBRTC_AUDIOPROC_FIXED_PROFILE" ]
+ } else {
+ defines += [ "WEBRTC_AUDIOPROC_FLOAT_PROFILE" ]
}
- # Disable LTO on NEON targets due to compiler bug.
- # TODO(fdegans): Enable this. See crbug.com/408997.
- if (rtc_use_lto) {
- cflags -= [
- "-flto",
- "-ffat-lto-objects",
+ if (rtc_enable_protobuf) {
+ defines += [ "WEBRTC_AUDIOPROC_DEBUG_DUMP" ]
+ deps += [
+ ":audioproc_debug_proto",
+ ":audioproc_protobuf_utils",
+ ":audioproc_test_utils",
+ ":audioproc_unittest_proto",
+ ":optionally_built_submodule_creators",
+ ":rms_level",
+ ":runtime_settings_protobuf_utils",
+ "../../api/audio:audio_frame_api",
+ "../../api/audio:echo_control",
+ "../../rtc_base:rtc_base_tests_utils",
+ "../../rtc_base:rtc_task_queue",
+ "aec_dump",
+ "aec_dump:aec_dump_unittests",
+ ]
+ absl_deps += [ "//third_party/abseil-cpp/absl/flags:flag" ]
+ sources += [
+ "audio_processing_impl_locking_unittest.cc",
+ "audio_processing_impl_unittest.cc",
+ "audio_processing_unittest.cc",
+ "echo_control_mobile_bit_exact_unittest.cc",
+ "echo_detector/circular_buffer_unittest.cc",
+ "echo_detector/mean_variance_estimator_unittest.cc",
+ "echo_detector/moving_max_unittest.cc",
+ "echo_detector/normalized_covariance_estimator_unittest.cc",
+ "gain_control_unittest.cc",
+ "high_pass_filter_unittest.cc",
+ "level_estimator_unittest.cc",
+ "residual_echo_detector_unittest.cc",
+ "rms_level_unittest.cc",
+ "test/debug_dump_replayer.cc",
+ "test/debug_dump_replayer.h",
+ "test/debug_dump_test.cc",
+ "test/echo_canceller_test_tools.cc",
+ "test/echo_canceller_test_tools.h",
+ "test/echo_canceller_test_tools_unittest.cc",
+ "test/echo_control_mock.h",
+ "test/test_utils.h",
+ "voice_detection_unittest.cc",
]
}
+ }
+
+ rtc_library("audio_processing_perf_tests") {
+ testonly = true
+ configs += [ ":apm_debug_dump" ]
- configs += [ "../..:common_config" ]
- public_configs = [ "../..:common_inherited_config" ]
+ sources = [ "audio_processing_performance_unittest.cc" ]
+ deps = [
+ ":audio_processing",
+ ":audioproc_test_utils",
+ "../../api:array_view",
+ "../../rtc_base:protobuf_utils",
+ "../../rtc_base:rtc_base_approved",
+ "../../system_wrappers",
+ "../../test:perf_test",
+ "../../test:test_support",
+ ]
+ }
+ rtc_library("analog_mic_simulation") {
+ sources = [
+ "test/fake_recording_device.cc",
+ "test/fake_recording_device.h",
+ ]
deps = [
+ "../../api:array_view",
+ "../../api/audio:audio_frame_api",
"../../common_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:safe_minmax",
+ "agc:gain_map",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ }
+
+ if (rtc_enable_protobuf) {
+ rtc_library("audioproc_f_impl") {
+ testonly = true
+ configs += [ ":apm_debug_dump" ]
+ sources = [
+ "test/aec_dump_based_simulator.cc",
+ "test/aec_dump_based_simulator.h",
+ "test/api_call_statistics.cc",
+ "test/api_call_statistics.h",
+ "test/audio_processing_simulator.cc",
+ "test/audio_processing_simulator.h",
+ "test/audioproc_float_impl.cc",
+ "test/audioproc_float_impl.h",
+ "test/wav_based_simulator.cc",
+ "test/wav_based_simulator.h",
+ ]
+
+ deps = [
+ ":analog_mic_simulation",
+ ":api",
+ ":apm_logging",
+ ":audio_processing",
+ ":audioproc_debug_proto",
+ ":audioproc_protobuf_utils",
+ ":audioproc_test_utils",
+ ":runtime_settings_protobuf_utils",
+ "../../api/audio:aec3_config_json",
+ "../../api/audio:aec3_factory",
+ "../../common_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:ignore_wundef",
+ "../../rtc_base:protobuf_utils",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base:rtc_json",
+ "../../rtc_base:task_queue_for_test",
+ "../../rtc_base/system:file_wrapper",
+ "../../system_wrappers",
+ "../../system_wrappers:field_trial",
+ "../../test:test_support",
+ "aec_dump",
+ "aec_dump:aec_dump_impl",
+ "//testing/gtest",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ } # audioproc_f_impl
+ }
+
+ if (rtc_enable_protobuf) {
+ proto_library("audioproc_unittest_proto") {
+ sources = [ "test/unittest.proto" ]
+ proto_out_dir = "modules/audio_processing/test"
+ }
+
+ rtc_library("audioproc_protobuf_utils") {
+ sources = [
+ "test/protobuf_utils.cc",
+ "test/protobuf_utils.h",
+ ]
+
+ deps = [
+ ":audioproc_debug_proto",
+ "../../rtc_base:checks",
+ "../../rtc_base:ignore_wundef",
+ "../../rtc_base:protobuf_utils",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base/system:arch",
+ ]
+ }
+
+ rtc_library("runtime_settings_protobuf_utils") {
+ testonly = true
+ sources = [
+ "test/runtime_setting_util.cc",
+ "test/runtime_setting_util.h",
+ ]
+
+ deps = [
+ ":api",
+ ":audioproc_debug_proto",
+ ":audioproc_protobuf_utils",
+ "../../rtc_base:checks",
+ ]
+ }
}
}
+
+rtc_library("audioproc_test_utils") {
+ visibility = [ "*" ]
+ testonly = true
+ sources = [
+ "test/audio_buffer_tools.cc",
+ "test/audio_buffer_tools.h",
+ "test/audio_processing_builder_for_testing.cc",
+ "test/audio_processing_builder_for_testing.h",
+ "test/bitexactness_tools.cc",
+ "test/bitexactness_tools.h",
+ "test/performance_timer.cc",
+ "test/performance_timer.h",
+ "test/simulator_buffers.cc",
+ "test/simulator_buffers.h",
+ "test/test_utils.cc",
+ "test/test_utils.h",
+ ]
+
+ configs += [ ":apm_debug_dump" ]
+
+ deps = [
+ ":api",
+ ":audio_buffer",
+ ":audio_processing",
+ "../../api:array_view",
+ "../../api/audio:audio_frame_api",
+ "../../common_audio",
+ "../../rtc_base:checks",
+ "../../rtc_base:rtc_base_approved",
+ "../../rtc_base/system:arch",
+ "../../system_wrappers",
+ "../../test:fileutils",
+ "../../test:test_support",
+ "../audio_coding:neteq_input_audio_tools",
+ "//testing/gtest",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
diff --git a/webrtc/modules/audio_processing/aec/aec_common.h b/webrtc/modules/audio_processing/aec/aec_common.h
deleted file mode 100644
index 1e24ca9..0000000
--- a/webrtc/modules/audio_processing/aec/aec_common.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
-
-#include "webrtc/typedefs.h"
-
-#ifdef _MSC_VER /* visual c++ */
-#define ALIGN16_BEG __declspec(align(16))
-#define ALIGN16_END
-#else /* gcc or icc */
-#define ALIGN16_BEG
-#define ALIGN16_END __attribute__((aligned(16)))
-#endif
-
-extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65];
-extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_weightCurve[65];
-extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65];
-extern const float WebRtcAec_kExtendedSmoothingCoefficients[2][2];
-extern const float WebRtcAec_kNormalSmoothingCoefficients[2][2];
-extern const float WebRtcAec_kMinFarendPSD;
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
-
diff --git a/webrtc/modules/audio_processing/aec/aec_core.c b/webrtc/modules/audio_processing/aec/aec_core.c
deleted file mode 100644
index f8eed32..0000000
--- a/webrtc/modules/audio_processing/aec/aec_core.c
+++ /dev/null
@@ -1,1929 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * The core AEC algorithm, which is presented with time-aligned signals.
- */
-
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-#include <stdio.h>
-#endif
-
-#include <assert.h>
-#include <math.h>
-#include <stddef.h> // size_t
-#include <stdlib.h>
-#include <string.h>
-
-#include "webrtc/common_audio/ring_buffer.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/aec/aec_common.h"
-#include "webrtc/modules/audio_processing/aec/aec_core_internal.h"
-#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
-#include "webrtc/modules/audio_processing/logging/aec_logging.h"
-#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
-#include "webrtc/typedefs.h"
-
-
-// Buffer size (samples)
-static const size_t kBufSizePartitions = 250; // 1 second of audio in 16 kHz.
-
-// Metrics
-static const int subCountLen = 4;
-static const int countLen = 50;
-static const int kDelayMetricsAggregationWindow = 1250; // 5 seconds at 16 kHz.
-
-// Quantities to control H band scaling for SWB input
-static const int flagHbandCn = 1; // flag for adding comfort noise in H band
-static const float cnScaleHband =
- (float)0.4; // scale for comfort noise in H band
-// Initial bin for averaging nlp gain in low band
-static const int freqAvgIc = PART_LEN / 2;
-
-// Matlab code to produce table:
-// win = sqrt(hanning(63)); win = [0 ; win(1:32)];
-// fprintf(1, '\t%.14f, %.14f, %.14f,\n', win);
-ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65] = {
- 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
- 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
- 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
- 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
- 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
- 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
- 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
- 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
- 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
- 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
- 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
- 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
- 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
- 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
- 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
- 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
- 1.00000000000000f};
-
-// Matlab code to produce table:
-// weightCurve = [0 ; 0.3 * sqrt(linspace(0,1,64))' + 0.1];
-// fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', weightCurve);
-ALIGN16_BEG const float ALIGN16_END WebRtcAec_weightCurve[65] = {
- 0.0000f, 0.1000f, 0.1378f, 0.1535f, 0.1655f, 0.1756f, 0.1845f, 0.1926f,
- 0.2000f, 0.2069f, 0.2134f, 0.2195f, 0.2254f, 0.2309f, 0.2363f, 0.2414f,
- 0.2464f, 0.2512f, 0.2558f, 0.2604f, 0.2648f, 0.2690f, 0.2732f, 0.2773f,
- 0.2813f, 0.2852f, 0.2890f, 0.2927f, 0.2964f, 0.3000f, 0.3035f, 0.3070f,
- 0.3104f, 0.3138f, 0.3171f, 0.3204f, 0.3236f, 0.3268f, 0.3299f, 0.3330f,
- 0.3360f, 0.3390f, 0.3420f, 0.3449f, 0.3478f, 0.3507f, 0.3535f, 0.3563f,
- 0.3591f, 0.3619f, 0.3646f, 0.3673f, 0.3699f, 0.3726f, 0.3752f, 0.3777f,
- 0.3803f, 0.3828f, 0.3854f, 0.3878f, 0.3903f, 0.3928f, 0.3952f, 0.3976f,
- 0.4000f};
-
-// Matlab code to produce table:
-// overDriveCurve = [sqrt(linspace(0,1,65))' + 1];
-// fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', overDriveCurve);
-ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65] = {
- 1.0000f, 1.1250f, 1.1768f, 1.2165f, 1.2500f, 1.2795f, 1.3062f, 1.3307f,
- 1.3536f, 1.3750f, 1.3953f, 1.4146f, 1.4330f, 1.4507f, 1.4677f, 1.4841f,
- 1.5000f, 1.5154f, 1.5303f, 1.5449f, 1.5590f, 1.5728f, 1.5863f, 1.5995f,
- 1.6124f, 1.6250f, 1.6374f, 1.6495f, 1.6614f, 1.6731f, 1.6847f, 1.6960f,
- 1.7071f, 1.7181f, 1.7289f, 1.7395f, 1.7500f, 1.7603f, 1.7706f, 1.7806f,
- 1.7906f, 1.8004f, 1.8101f, 1.8197f, 1.8292f, 1.8385f, 1.8478f, 1.8570f,
- 1.8660f, 1.8750f, 1.8839f, 1.8927f, 1.9014f, 1.9100f, 1.9186f, 1.9270f,
- 1.9354f, 1.9437f, 1.9520f, 1.9601f, 1.9682f, 1.9763f, 1.9843f, 1.9922f,
- 2.0000f};
-
-// Delay Agnostic AEC parameters, still under development and may change.
-static const float kDelayQualityThresholdMax = 0.07f;
-static const float kDelayQualityThresholdMin = 0.01f;
-static const int kInitialShiftOffset = 5;
-#if !defined(WEBRTC_ANDROID)
-static const int kDelayCorrectionStart = 1500; // 10 ms chunks
-#endif
-
-// Target suppression levels for nlp modes.
-// log{0.001, 0.00001, 0.00000001}
-static const float kTargetSupp[3] = {-6.9f, -11.5f, -18.4f};
-
-// Two sets of parameters, one for the extended filter mode.
-static const float kExtendedMinOverDrive[3] = {3.0f, 6.0f, 15.0f};
-static const float kNormalMinOverDrive[3] = {1.0f, 2.0f, 5.0f};
-const float WebRtcAec_kExtendedSmoothingCoefficients[2][2] = {{0.9f, 0.1f},
- {0.92f, 0.08f}};
-const float WebRtcAec_kNormalSmoothingCoefficients[2][2] = {{0.9f, 0.1f},
- {0.93f, 0.07f}};
-
-// Number of partitions forming the NLP's "preferred" bands.
-enum {
- kPrefBandSize = 24
-};
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-extern int webrtc_aec_instance_count;
-#endif
-
-WebRtcAecFilterFar WebRtcAec_FilterFar;
-WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;
-WebRtcAecFilterAdaptation WebRtcAec_FilterAdaptation;
-WebRtcAecOverdriveAndSuppress WebRtcAec_OverdriveAndSuppress;
-WebRtcAecComfortNoise WebRtcAec_ComfortNoise;
-WebRtcAecSubBandCoherence WebRtcAec_SubbandCoherence;
-
-__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bRe - aIm * bIm;
-}
-
-__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bIm + aIm * bRe;
-}
-
-static int CmpFloat(const void* a, const void* b) {
- const float* da = (const float*)a;
- const float* db = (const float*)b;
-
- return (*da > *db) - (*da < *db);
-}
-
-static void FilterFar(AecCore* aec, float yf[2][PART_LEN1]) {
- int i;
- for (i = 0; i < aec->num_partitions; i++) {
- int j;
- int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + aec->xfBufBlockPos >= aec->num_partitions) {
- xPos -= aec->num_partitions * (PART_LEN1);
- }
-
- for (j = 0; j < PART_LEN1; j++) {
- yf[0][j] += MulRe(aec->xfBuf[0][xPos + j],
- aec->xfBuf[1][xPos + j],
- aec->wfBuf[0][pos + j],
- aec->wfBuf[1][pos + j]);
- yf[1][j] += MulIm(aec->xfBuf[0][xPos + j],
- aec->xfBuf[1][xPos + j],
- aec->wfBuf[0][pos + j],
- aec->wfBuf[1][pos + j]);
- }
- }
-}
-
-static void ScaleErrorSignal(AecCore* aec, float ef[2][PART_LEN1]) {
- const float mu = aec->extended_filter_enabled ? kExtendedMu : aec->normal_mu;
- const float error_threshold = aec->extended_filter_enabled
- ? kExtendedErrorThreshold
- : aec->normal_error_threshold;
- int i;
- float abs_ef;
- for (i = 0; i < (PART_LEN1); i++) {
- ef[0][i] /= (aec->xPow[i] + 1e-10f);
- ef[1][i] /= (aec->xPow[i] + 1e-10f);
- abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
-
- if (abs_ef > error_threshold) {
- abs_ef = error_threshold / (abs_ef + 1e-10f);
- ef[0][i] *= abs_ef;
- ef[1][i] *= abs_ef;
- }
-
- // Stepsize factor
- ef[0][i] *= mu;
- ef[1][i] *= mu;
- }
-}
-
-// Time-unconstrined filter adaptation.
-// TODO(andrew): consider for a low-complexity mode.
-// static void FilterAdaptationUnconstrained(AecCore* aec, float *fft,
-// float ef[2][PART_LEN1]) {
-// int i, j;
-// for (i = 0; i < aec->num_partitions; i++) {
-// int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1);
-// int pos;
-// // Check for wrap
-// if (i + aec->xfBufBlockPos >= aec->num_partitions) {
-// xPos -= aec->num_partitions * PART_LEN1;
-// }
-//
-// pos = i * PART_LEN1;
-//
-// for (j = 0; j < PART_LEN1; j++) {
-// aec->wfBuf[0][pos + j] += MulRe(aec->xfBuf[0][xPos + j],
-// -aec->xfBuf[1][xPos + j],
-// ef[0][j], ef[1][j]);
-// aec->wfBuf[1][pos + j] += MulIm(aec->xfBuf[0][xPos + j],
-// -aec->xfBuf[1][xPos + j],
-// ef[0][j], ef[1][j]);
-// }
-// }
-//}
-
-static void FilterAdaptation(AecCore* aec, float* fft, float ef[2][PART_LEN1]) {
- int i, j;
- for (i = 0; i < aec->num_partitions; i++) {
- int xPos = (i + aec->xfBufBlockPos) * (PART_LEN1);
- int pos;
- // Check for wrap
- if (i + aec->xfBufBlockPos >= aec->num_partitions) {
- xPos -= aec->num_partitions * PART_LEN1;
- }
-
- pos = i * PART_LEN1;
-
- for (j = 0; j < PART_LEN; j++) {
-
- fft[2 * j] = MulRe(aec->xfBuf[0][xPos + j],
- -aec->xfBuf[1][xPos + j],
- ef[0][j],
- ef[1][j]);
- fft[2 * j + 1] = MulIm(aec->xfBuf[0][xPos + j],
- -aec->xfBuf[1][xPos + j],
- ef[0][j],
- ef[1][j]);
- }
- fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN],
- -aec->xfBuf[1][xPos + PART_LEN],
- ef[0][PART_LEN],
- ef[1][PART_LEN]);
-
- aec_rdft_inverse_128(fft);
- memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
-
- // fft scaling
- {
- float scale = 2.0f / PART_LEN2;
- for (j = 0; j < PART_LEN; j++) {
- fft[j] *= scale;
- }
- }
- aec_rdft_forward_128(fft);
-
- aec->wfBuf[0][pos] += fft[0];
- aec->wfBuf[0][pos + PART_LEN] += fft[1];
-
- for (j = 1; j < PART_LEN; j++) {
- aec->wfBuf[0][pos + j] += fft[2 * j];
- aec->wfBuf[1][pos + j] += fft[2 * j + 1];
- }
- }
-}
-
-static void OverdriveAndSuppress(AecCore* aec,
- float hNl[PART_LEN1],
- const float hNlFb,
- float efw[2][PART_LEN1]) {
- int i;
- for (i = 0; i < PART_LEN1; i++) {
- // Weight subbands
- if (hNl[i] > hNlFb) {
- hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
- (1 - WebRtcAec_weightCurve[i]) * hNl[i];
- }
- hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
-
- // Suppress error signal
- efw[0][i] *= hNl[i];
- efw[1][i] *= hNl[i];
-
- // Ooura fft returns incorrect sign on imaginary component. It matters here
- // because we are making an additive change with comfort noise.
- efw[1][i] *= -1;
- }
-}
-
-static int PartitionDelay(const AecCore* aec) {
- // Measures the energy in each filter partition and returns the partition with
- // highest energy.
- // TODO(bjornv): Spread computational cost by computing one partition per
- // block?
- float wfEnMax = 0;
- int i;
- int delay = 0;
-
- for (i = 0; i < aec->num_partitions; i++) {
- int j;
- int pos = i * PART_LEN1;
- float wfEn = 0;
- for (j = 0; j < PART_LEN1; j++) {
- wfEn += aec->wfBuf[0][pos + j] * aec->wfBuf[0][pos + j] +
- aec->wfBuf[1][pos + j] * aec->wfBuf[1][pos + j];
- }
-
- if (wfEn > wfEnMax) {
- wfEnMax = wfEn;
- delay = i;
- }
- }
- return delay;
-}
-
-// Threshold to protect against the ill-effects of a zero far-end.
-const float WebRtcAec_kMinFarendPSD = 15;
-
-// Updates the following smoothed Power Spectral Densities (PSD):
-// - sd : near-end
-// - se : residual echo
-// - sx : far-end
-// - sde : cross-PSD of near-end and residual echo
-// - sxd : cross-PSD of near-end and far-end
-//
-// In addition to updating the PSDs, also the filter diverge state is determined
-// upon actions are taken.
-static void SmoothedPSD(AecCore* aec,
- float efw[2][PART_LEN1],
- float dfw[2][PART_LEN1],
- float xfw[2][PART_LEN1]) {
- // Power estimate smoothing coefficients.
- const float* ptrGCoh = aec->extended_filter_enabled
- ? WebRtcAec_kExtendedSmoothingCoefficients[aec->mult - 1]
- : WebRtcAec_kNormalSmoothingCoefficients[aec->mult - 1];
- int i;
- float sdSum = 0, seSum = 0;
-
- for (i = 0; i < PART_LEN1; i++) {
- aec->sd[i] = ptrGCoh[0] * aec->sd[i] +
- ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
- aec->se[i] = ptrGCoh[0] * aec->se[i] +
- ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
- // We threshold here to protect against the ill-effects of a zero farend.
- // The threshold is not arbitrarily chosen, but balances protection and
- // adverse interaction with the algorithm's tuning.
- // TODO(bjornv): investigate further why this is so sensitive.
- aec->sx[i] =
- ptrGCoh[0] * aec->sx[i] +
- ptrGCoh[1] * WEBRTC_SPL_MAX(
- xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
- WebRtcAec_kMinFarendPSD);
-
- aec->sde[i][0] =
- ptrGCoh[0] * aec->sde[i][0] +
- ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
- aec->sde[i][1] =
- ptrGCoh[0] * aec->sde[i][1] +
- ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
-
- aec->sxd[i][0] =
- ptrGCoh[0] * aec->sxd[i][0] +
- ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
- aec->sxd[i][1] =
- ptrGCoh[0] * aec->sxd[i][1] +
- ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
-
- sdSum += aec->sd[i];
- seSum += aec->se[i];
- }
-
- // Divergent filter safeguard.
- aec->divergeState = (aec->divergeState ? 1.05f : 1.0f) * seSum > sdSum;
-
- if (aec->divergeState)
- memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
-
- // Reset if error is significantly larger than nearend (13 dB).
- if (!aec->extended_filter_enabled && seSum > (19.95f * sdSum))
- memset(aec->wfBuf, 0, sizeof(aec->wfBuf));
-}
-
-// Window time domain data to be used by the fft.
-__inline static void WindowData(float* x_windowed, const float* x) {
- int i;
- for (i = 0; i < PART_LEN; i++) {
- x_windowed[i] = x[i] * WebRtcAec_sqrtHanning[i];
- x_windowed[PART_LEN + i] =
- x[PART_LEN + i] * WebRtcAec_sqrtHanning[PART_LEN - i];
- }
-}
-
-// Puts fft output data into a complex valued array.
-__inline static void StoreAsComplex(const float* data,
- float data_complex[2][PART_LEN1]) {
- int i;
- data_complex[0][0] = data[0];
- data_complex[1][0] = 0;
- for (i = 1; i < PART_LEN; i++) {
- data_complex[0][i] = data[2 * i];
- data_complex[1][i] = data[2 * i + 1];
- }
- data_complex[0][PART_LEN] = data[1];
- data_complex[1][PART_LEN] = 0;
-}
-
-static void SubbandCoherence(AecCore* aec,
- float efw[2][PART_LEN1],
- float xfw[2][PART_LEN1],
- float* fft,
- float* cohde,
- float* cohxd) {
- float dfw[2][PART_LEN1];
- int i;
-
- if (aec->delayEstCtr == 0)
- aec->delayIdx = PartitionDelay(aec);
-
- // Use delayed far.
- memcpy(xfw,
- aec->xfwBuf + aec->delayIdx * PART_LEN1,
- sizeof(xfw[0][0]) * 2 * PART_LEN1);
-
- // Windowed near fft
- WindowData(fft, aec->dBuf);
- aec_rdft_forward_128(fft);
- StoreAsComplex(fft, dfw);
-
- // Windowed error fft
- WindowData(fft, aec->eBuf);
- aec_rdft_forward_128(fft);
- StoreAsComplex(fft, efw);
-
- SmoothedPSD(aec, efw, dfw, xfw);
-
- // Subband coherence
- for (i = 0; i < PART_LEN1; i++) {
- cohde[i] =
- (aec->sde[i][0] * aec->sde[i][0] + aec->sde[i][1] * aec->sde[i][1]) /
- (aec->sd[i] * aec->se[i] + 1e-10f);
- cohxd[i] =
- (aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) /
- (aec->sx[i] * aec->sd[i] + 1e-10f);
- }
-}
-
-static void GetHighbandGain(const float* lambda, float* nlpGainHband) {
- int i;
-
- nlpGainHband[0] = (float)0.0;
- for (i = freqAvgIc; i < PART_LEN1 - 1; i++) {
- nlpGainHband[0] += lambda[i];
- }
- nlpGainHband[0] /= (float)(PART_LEN1 - 1 - freqAvgIc);
-}
-
-static void ComfortNoise(AecCore* aec,
- float efw[2][PART_LEN1],
- complex_t* comfortNoiseHband,
- const float* noisePow,
- const float* lambda) {
- int i, num;
- float rand[PART_LEN];
- float noise, noiseAvg, tmp, tmpAvg;
- int16_t randW16[PART_LEN];
- complex_t u[PART_LEN1];
-
- const float pi2 = 6.28318530717959f;
-
- // Generate a uniform random array on [0 1]
- WebRtcSpl_RandUArray(randW16, PART_LEN, &aec->seed);
- for (i = 0; i < PART_LEN; i++) {
- rand[i] = ((float)randW16[i]) / 32768;
- }
-
- // Reject LF noise
- u[0][0] = 0;
- u[0][1] = 0;
- for (i = 1; i < PART_LEN1; i++) {
- tmp = pi2 * rand[i - 1];
-
- noise = sqrtf(noisePow[i]);
- u[i][0] = noise * cosf(tmp);
- u[i][1] = -noise * sinf(tmp);
- }
- u[PART_LEN][1] = 0;
-
- for (i = 0; i < PART_LEN1; i++) {
- // This is the proper weighting to match the background noise power
- tmp = sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0));
- // tmp = 1 - lambda[i];
- efw[0][i] += tmp * u[i][0];
- efw[1][i] += tmp * u[i][1];
- }
-
- // For H band comfort noise
- // TODO: don't compute noise and "tmp" twice. Use the previous results.
- noiseAvg = 0.0;
- tmpAvg = 0.0;
- num = 0;
- if (aec->num_bands > 1 && flagHbandCn == 1) {
-
- // average noise scale
- // average over second half of freq spectrum (i.e., 4->8khz)
- // TODO: we shouldn't need num. We know how many elements we're summing.
- for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) {
- num++;
- noiseAvg += sqrtf(noisePow[i]);
- }
- noiseAvg /= (float)num;
-
- // average nlp scale
- // average over second half of freq spectrum (i.e., 4->8khz)
- // TODO: we shouldn't need num. We know how many elements we're summing.
- num = 0;
- for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) {
- num++;
- tmpAvg += sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0));
- }
- tmpAvg /= (float)num;
-
- // Use average noise for H band
- // TODO: we should probably have a new random vector here.
- // Reject LF noise
- u[0][0] = 0;
- u[0][1] = 0;
- for (i = 1; i < PART_LEN1; i++) {
- tmp = pi2 * rand[i - 1];
-
- // Use average noise for H band
- u[i][0] = noiseAvg * (float)cos(tmp);
- u[i][1] = -noiseAvg * (float)sin(tmp);
- }
- u[PART_LEN][1] = 0;
-
- for (i = 0; i < PART_LEN1; i++) {
- // Use average NLP weight for H band
- comfortNoiseHband[i][0] = tmpAvg * u[i][0];
- comfortNoiseHband[i][1] = tmpAvg * u[i][1];
- }
- }
-}
-
-static void InitLevel(PowerLevel* level) {
- const float kBigFloat = 1E17f;
-
- level->averagelevel = 0;
- level->framelevel = 0;
- level->minlevel = kBigFloat;
- level->frsum = 0;
- level->sfrsum = 0;
- level->frcounter = 0;
- level->sfrcounter = 0;
-}
-
-static void InitStats(Stats* stats) {
- stats->instant = kOffsetLevel;
- stats->average = kOffsetLevel;
- stats->max = kOffsetLevel;
- stats->min = kOffsetLevel * (-1);
- stats->sum = 0;
- stats->hisum = 0;
- stats->himean = kOffsetLevel;
- stats->counter = 0;
- stats->hicounter = 0;
-}
-
-static void InitMetrics(AecCore* self) {
- self->stateCounter = 0;
- InitLevel(&self->farlevel);
- InitLevel(&self->nearlevel);
- InitLevel(&self->linoutlevel);
- InitLevel(&self->nlpoutlevel);
-
- InitStats(&self->erl);
- InitStats(&self->erle);
- InitStats(&self->aNlp);
- InitStats(&self->rerl);
-}
-
-static void UpdateLevel(PowerLevel* level, float in[2][PART_LEN1]) {
- // Do the energy calculation in the frequency domain. The FFT is performed on
- // a segment of PART_LEN2 samples due to overlap, but we only want the energy
- // of half that data (the last PART_LEN samples). Parseval's relation states
- // that the energy is preserved according to
- //
- // \sum_{n=0}^{N-1} |x(n)|^2 = 1/N * \sum_{n=0}^{N-1} |X(n)|^2
- // = ENERGY,
- //
- // where N = PART_LEN2. Since we are only interested in calculating the energy
- // for the last PART_LEN samples we approximate by calculating ENERGY and
- // divide by 2,
- //
- // \sum_{n=N/2}^{N-1} |x(n)|^2 ~= ENERGY / 2
- //
- // Since we deal with real valued time domain signals we only store frequency
- // bins [0, PART_LEN], which is what |in| consists of. To calculate ENERGY we
- // need to add the contribution from the missing part in
- // [PART_LEN+1, PART_LEN2-1]. These values are, up to a phase shift, identical
- // with the values in [1, PART_LEN-1], hence multiply those values by 2. This
- // is the values in the for loop below, but multiplication by 2 and division
- // by 2 cancel.
-
- // TODO(bjornv): Investigate reusing energy calculations performed at other
- // places in the code.
- int k = 1;
- // Imaginary parts are zero at end points and left out of the calculation.
- float energy = (in[0][0] * in[0][0]) / 2;
- energy += (in[0][PART_LEN] * in[0][PART_LEN]) / 2;
-
- for (k = 1; k < PART_LEN; k++) {
- energy += (in[0][k] * in[0][k] + in[1][k] * in[1][k]);
- }
- energy /= PART_LEN2;
-
- level->sfrsum += energy;
- level->sfrcounter++;
-
- if (level->sfrcounter > subCountLen) {
- level->framelevel = level->sfrsum / (subCountLen * PART_LEN);
- level->sfrsum = 0;
- level->sfrcounter = 0;
- if (level->framelevel > 0) {
- if (level->framelevel < level->minlevel) {
- level->minlevel = level->framelevel; // New minimum.
- } else {
- level->minlevel *= (1 + 0.001f); // Small increase.
- }
- }
- level->frcounter++;
- level->frsum += level->framelevel;
- if (level->frcounter > countLen) {
- level->averagelevel = level->frsum / countLen;
- level->frsum = 0;
- level->frcounter = 0;
- }
- }
-}
-
-static void UpdateMetrics(AecCore* aec) {
- float dtmp, dtmp2;
-
- const float actThresholdNoisy = 8.0f;
- const float actThresholdClean = 40.0f;
- const float safety = 0.99995f;
- const float noisyPower = 300000.0f;
-
- float actThreshold;
- float echo, suppressedEcho;
-
- if (aec->echoState) { // Check if echo is likely present
- aec->stateCounter++;
- }
-
- if (aec->farlevel.frcounter == 0) {
-
- if (aec->farlevel.minlevel < noisyPower) {
- actThreshold = actThresholdClean;
- } else {
- actThreshold = actThresholdNoisy;
- }
-
- if ((aec->stateCounter > (0.5f * countLen * subCountLen)) &&
- (aec->farlevel.sfrcounter == 0)
-
- // Estimate in active far-end segments only
- &&
- (aec->farlevel.averagelevel >
- (actThreshold * aec->farlevel.minlevel))) {
-
- // Subtract noise power
- echo = aec->nearlevel.averagelevel - safety * aec->nearlevel.minlevel;
-
- // ERL
- dtmp = 10 * (float)log10(aec->farlevel.averagelevel /
- aec->nearlevel.averagelevel +
- 1e-10f);
- dtmp2 = 10 * (float)log10(aec->farlevel.averagelevel / echo + 1e-10f);
-
- aec->erl.instant = dtmp;
- if (dtmp > aec->erl.max) {
- aec->erl.max = dtmp;
- }
-
- if (dtmp < aec->erl.min) {
- aec->erl.min = dtmp;
- }
-
- aec->erl.counter++;
- aec->erl.sum += dtmp;
- aec->erl.average = aec->erl.sum / aec->erl.counter;
-
- // Upper mean
- if (dtmp > aec->erl.average) {
- aec->erl.hicounter++;
- aec->erl.hisum += dtmp;
- aec->erl.himean = aec->erl.hisum / aec->erl.hicounter;
- }
-
- // A_NLP
- dtmp = 10 * (float)log10(aec->nearlevel.averagelevel /
- (2 * aec->linoutlevel.averagelevel) +
- 1e-10f);
-
- // subtract noise power
- suppressedEcho = 2 * (aec->linoutlevel.averagelevel -
- safety * aec->linoutlevel.minlevel);
-
- dtmp2 = 10 * (float)log10(echo / suppressedEcho + 1e-10f);
-
- aec->aNlp.instant = dtmp2;
- if (dtmp > aec->aNlp.max) {
- aec->aNlp.max = dtmp;
- }
-
- if (dtmp < aec->aNlp.min) {
- aec->aNlp.min = dtmp;
- }
-
- aec->aNlp.counter++;
- aec->aNlp.sum += dtmp;
- aec->aNlp.average = aec->aNlp.sum / aec->aNlp.counter;
-
- // Upper mean
- if (dtmp > aec->aNlp.average) {
- aec->aNlp.hicounter++;
- aec->aNlp.hisum += dtmp;
- aec->aNlp.himean = aec->aNlp.hisum / aec->aNlp.hicounter;
- }
-
- // ERLE
-
- // subtract noise power
- suppressedEcho = 2 * (aec->nlpoutlevel.averagelevel -
- safety * aec->nlpoutlevel.minlevel);
-
- dtmp = 10 * (float)log10(aec->nearlevel.averagelevel /
- (2 * aec->nlpoutlevel.averagelevel) +
- 1e-10f);
- dtmp2 = 10 * (float)log10(echo / suppressedEcho + 1e-10f);
-
- dtmp = dtmp2;
- aec->erle.instant = dtmp;
- if (dtmp > aec->erle.max) {
- aec->erle.max = dtmp;
- }
-
- if (dtmp < aec->erle.min) {
- aec->erle.min = dtmp;
- }
-
- aec->erle.counter++;
- aec->erle.sum += dtmp;
- aec->erle.average = aec->erle.sum / aec->erle.counter;
-
- // Upper mean
- if (dtmp > aec->erle.average) {
- aec->erle.hicounter++;
- aec->erle.hisum += dtmp;
- aec->erle.himean = aec->erle.hisum / aec->erle.hicounter;
- }
- }
-
- aec->stateCounter = 0;
- }
-}
-
-static void UpdateDelayMetrics(AecCore* self) {
- int i = 0;
- int delay_values = 0;
- int median = 0;
- int lookahead = WebRtc_lookahead(self->delay_estimator);
- const int kMsPerBlock = PART_LEN / (self->mult * 8);
- int64_t l1_norm = 0;
-
- if (self->num_delay_values == 0) {
- // We have no new delay value data. Even though -1 is a valid |median| in
- // the sense that we allow negative values, it will practically never be
- // used since multiples of |kMsPerBlock| will always be returned.
- // We therefore use -1 to indicate in the logs that the delay estimator was
- // not able to estimate the delay.
- self->delay_median = -1;
- self->delay_std = -1;
- self->fraction_poor_delays = -1;
- return;
- }
-
- // Start value for median count down.
- delay_values = self->num_delay_values >> 1;
- // Get median of delay values since last update.
- for (i = 0; i < kHistorySizeBlocks; i++) {
- delay_values -= self->delay_histogram[i];
- if (delay_values < 0) {
- median = i;
- break;
- }
- }
- // Account for lookahead.
- self->delay_median = (median - lookahead) * kMsPerBlock;
-
- // Calculate the L1 norm, with median value as central moment.
- for (i = 0; i < kHistorySizeBlocks; i++) {
- l1_norm += abs(i - median) * self->delay_histogram[i];
- }
- self->delay_std = (int)((l1_norm + self->num_delay_values / 2) /
- self->num_delay_values) * kMsPerBlock;
-
- // Determine fraction of delays that are out of bounds, that is, either
- // negative (anti-causal system) or larger than the AEC filter length.
- {
- int num_delays_out_of_bounds = self->num_delay_values;
- const int histogram_length = sizeof(self->delay_histogram) /
- sizeof(self->delay_histogram[0]);
- for (i = lookahead; i < lookahead + self->num_partitions; ++i) {
- if (i < histogram_length)
- num_delays_out_of_bounds -= self->delay_histogram[i];
- }
- self->fraction_poor_delays = (float)num_delays_out_of_bounds /
- self->num_delay_values;
- }
-
- // Reset histogram.
- memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
- self->num_delay_values = 0;
-
- return;
-}
-
-static void TimeToFrequency(float time_data[PART_LEN2],
- float freq_data[2][PART_LEN1],
- int window) {
- int i = 0;
-
- // TODO(bjornv): Should we have a different function/wrapper for windowed FFT?
- if (window) {
- for (i = 0; i < PART_LEN; i++) {
- time_data[i] *= WebRtcAec_sqrtHanning[i];
- time_data[PART_LEN + i] *= WebRtcAec_sqrtHanning[PART_LEN - i];
- }
- }
-
- aec_rdft_forward_128(time_data);
- // Reorder.
- freq_data[1][0] = 0;
- freq_data[1][PART_LEN] = 0;
- freq_data[0][0] = time_data[0];
- freq_data[0][PART_LEN] = time_data[1];
- for (i = 1; i < PART_LEN; i++) {
- freq_data[0][i] = time_data[2 * i];
- freq_data[1][i] = time_data[2 * i + 1];
- }
-}
-
-static int MoveFarReadPtrWithoutSystemDelayUpdate(AecCore* self, int elements) {
- WebRtc_MoveReadPtr(self->far_buf_windowed, elements);
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- WebRtc_MoveReadPtr(self->far_time_buf, elements);
-#endif
- return WebRtc_MoveReadPtr(self->far_buf, elements);
-}
-
-static int SignalBasedDelayCorrection(AecCore* self) {
- int delay_correction = 0;
- int last_delay = -2;
- assert(self != NULL);
-#if !defined(WEBRTC_ANDROID)
- // On desktops, turn on correction after |kDelayCorrectionStart| frames. This
- // is to let the delay estimation get a chance to converge. Also, if the
- // playout audio volume is low (or even muted) the delay estimation can return
- // a very large delay, which will break the AEC if it is applied.
- if (self->frame_count < kDelayCorrectionStart) {
- return 0;
- }
-#endif
-
- // 1. Check for non-negative delay estimate. Note that the estimates we get
- // from the delay estimation are not compensated for lookahead. Hence, a
- // negative |last_delay| is an invalid one.
- // 2. Verify that there is a delay change. In addition, only allow a change
- // if the delay is outside a certain region taking the AEC filter length
- // into account.
- // TODO(bjornv): Investigate if we can remove the non-zero delay change check.
- // 3. Only allow delay correction if the delay estimation quality exceeds
- // |delay_quality_threshold|.
- // 4. Finally, verify that the proposed |delay_correction| is feasible by
- // comparing with the size of the far-end buffer.
- last_delay = WebRtc_last_delay(self->delay_estimator);
- if ((last_delay >= 0) &&
- (last_delay != self->previous_delay) &&
- (WebRtc_last_delay_quality(self->delay_estimator) >
- self->delay_quality_threshold)) {
- int delay = last_delay - WebRtc_lookahead(self->delay_estimator);
- // Allow for a slack in the actual delay, defined by a |lower_bound| and an
- // |upper_bound|. The adaptive echo cancellation filter is currently
- // |num_partitions| (of 64 samples) long. If the delay estimate is negative
- // or at least 3/4 of the filter length we open up for correction.
- const int lower_bound = 0;
- const int upper_bound = self->num_partitions * 3 / 4;
- const int do_correction = delay <= lower_bound || delay > upper_bound;
- if (do_correction == 1) {
- int available_read = (int)WebRtc_available_read(self->far_buf);
- // With |shift_offset| we gradually rely on the delay estimates. For
- // positive delays we reduce the correction by |shift_offset| to lower the
- // risk of pushing the AEC into a non causal state. For negative delays
- // we rely on the values up to a rounding error, hence compensate by 1
- // element to make sure to push the delay into the causal region.
- delay_correction = -delay;
- delay_correction += delay > self->shift_offset ? self->shift_offset : 1;
- self->shift_offset--;
- self->shift_offset = (self->shift_offset <= 1 ? 1 : self->shift_offset);
- if (delay_correction > available_read - self->mult - 1) {
- // There is not enough data in the buffer to perform this shift. Hence,
- // we do not rely on the delay estimate and do nothing.
- delay_correction = 0;
- } else {
- self->previous_delay = last_delay;
- ++self->delay_correction_count;
- }
- }
- }
- // Update the |delay_quality_threshold| once we have our first delay
- // correction.
- if (self->delay_correction_count > 0) {
- float delay_quality = WebRtc_last_delay_quality(self->delay_estimator);
- delay_quality = (delay_quality > kDelayQualityThresholdMax ?
- kDelayQualityThresholdMax : delay_quality);
- self->delay_quality_threshold =
- (delay_quality > self->delay_quality_threshold ? delay_quality :
- self->delay_quality_threshold);
- }
- return delay_correction;
-}
-
-static void NonLinearProcessing(AecCore* aec,
- float* output,
- float* const* outputH) {
- float efw[2][PART_LEN1], xfw[2][PART_LEN1];
- complex_t comfortNoiseHband[PART_LEN1];
- float fft[PART_LEN2];
- float scale, dtmp;
- float nlpGainHband;
- int i;
- size_t j;
-
- // Coherence and non-linear filter
- float cohde[PART_LEN1], cohxd[PART_LEN1];
- float hNlDeAvg, hNlXdAvg;
- float hNl[PART_LEN1];
- float hNlPref[kPrefBandSize];
- float hNlFb = 0, hNlFbLow = 0;
- const float prefBandQuant = 0.75f, prefBandQuantLow = 0.5f;
- const int prefBandSize = kPrefBandSize / aec->mult;
- const int minPrefBand = 4 / aec->mult;
- // Power estimate smoothing coefficients.
- const float* min_overdrive = aec->extended_filter_enabled
- ? kExtendedMinOverDrive
- : kNormalMinOverDrive;
-
- // Filter energy
- const int delayEstInterval = 10 * aec->mult;
-
- float* xfw_ptr = NULL;
-
- aec->delayEstCtr++;
- if (aec->delayEstCtr == delayEstInterval) {
- aec->delayEstCtr = 0;
- }
-
- // initialize comfort noise for H band
- memset(comfortNoiseHband, 0, sizeof(comfortNoiseHband));
- nlpGainHband = (float)0.0;
- dtmp = (float)0.0;
-
- // We should always have at least one element stored in |far_buf|.
- assert(WebRtc_available_read(aec->far_buf_windowed) > 0);
- // NLP
- WebRtc_ReadBuffer(aec->far_buf_windowed, (void**)&xfw_ptr, &xfw[0][0], 1);
-
- // TODO(bjornv): Investigate if we can reuse |far_buf_windowed| instead of
- // |xfwBuf|.
- // Buffer far.
- memcpy(aec->xfwBuf, xfw_ptr, sizeof(float) * 2 * PART_LEN1);
-
- WebRtcAec_SubbandCoherence(aec, efw, xfw, fft, cohde, cohxd);
-
- hNlXdAvg = 0;
- for (i = minPrefBand; i < prefBandSize + minPrefBand; i++) {
- hNlXdAvg += cohxd[i];
- }
- hNlXdAvg /= prefBandSize;
- hNlXdAvg = 1 - hNlXdAvg;
-
- hNlDeAvg = 0;
- for (i = minPrefBand; i < prefBandSize + minPrefBand; i++) {
- hNlDeAvg += cohde[i];
- }
- hNlDeAvg /= prefBandSize;
-
- if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) {
- aec->hNlXdAvgMin = hNlXdAvg;
- }
-
- if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) {
- aec->stNearState = 1;
- } else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) {
- aec->stNearState = 0;
- }
-
- if (aec->hNlXdAvgMin == 1) {
- aec->echoState = 0;
- aec->overDrive = min_overdrive[aec->nlp_mode];
-
- if (aec->stNearState == 1) {
- memcpy(hNl, cohde, sizeof(hNl));
- hNlFb = hNlDeAvg;
- hNlFbLow = hNlDeAvg;
- } else {
- for (i = 0; i < PART_LEN1; i++) {
- hNl[i] = 1 - cohxd[i];
- }
- hNlFb = hNlXdAvg;
- hNlFbLow = hNlXdAvg;
- }
- } else {
-
- if (aec->stNearState == 1) {
- aec->echoState = 0;
- memcpy(hNl, cohde, sizeof(hNl));
- hNlFb = hNlDeAvg;
- hNlFbLow = hNlDeAvg;
- } else {
- aec->echoState = 1;
- for (i = 0; i < PART_LEN1; i++) {
- hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]);
- }
-
- // Select an order statistic from the preferred bands.
- // TODO: Using quicksort now, but a selection algorithm may be preferred.
- memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize);
- qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat);
- hNlFb = hNlPref[(int)floor(prefBandQuant * (prefBandSize - 1))];
- hNlFbLow = hNlPref[(int)floor(prefBandQuantLow * (prefBandSize - 1))];
- }
- }
-
- // Track the local filter minimum to determine suppression overdrive.
- if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) {
- aec->hNlFbLocalMin = hNlFbLow;
- aec->hNlFbMin = hNlFbLow;
- aec->hNlNewMin = 1;
- aec->hNlMinCtr = 0;
- }
- aec->hNlFbLocalMin =
- WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1);
- aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1);
-
- if (aec->hNlNewMin == 1) {
- aec->hNlMinCtr++;
- }
- if (aec->hNlMinCtr == 2) {
- aec->hNlNewMin = 0;
- aec->hNlMinCtr = 0;
- aec->overDrive =
- WEBRTC_SPL_MAX(kTargetSupp[aec->nlp_mode] /
- ((float)log(aec->hNlFbMin + 1e-10f) + 1e-10f),
- min_overdrive[aec->nlp_mode]);
- }
-
- // Smooth the overdrive.
- if (aec->overDrive < aec->overDriveSm) {
- aec->overDriveSm = 0.99f * aec->overDriveSm + 0.01f * aec->overDrive;
- } else {
- aec->overDriveSm = 0.9f * aec->overDriveSm + 0.1f * aec->overDrive;
- }
-
- WebRtcAec_OverdriveAndSuppress(aec, hNl, hNlFb, efw);
-
- // Add comfort noise.
- WebRtcAec_ComfortNoise(aec, efw, comfortNoiseHband, aec->noisePow, hNl);
-
- // TODO(bjornv): Investigate how to take the windowing below into account if
- // needed.
- if (aec->metricsMode == 1) {
- // Note that we have a scaling by two in the time domain |eBuf|.
- // In addition the time domain signal is windowed before transformation,
- // losing half the energy on the average. We take care of the first
- // scaling only in UpdateMetrics().
- UpdateLevel(&aec->nlpoutlevel, efw);
- }
- // Inverse error fft.
- fft[0] = efw[0][0];
- fft[1] = efw[0][PART_LEN];
- for (i = 1; i < PART_LEN; i++) {
- fft[2 * i] = efw[0][i];
- // Sign change required by Ooura fft.
- fft[2 * i + 1] = -efw[1][i];
- }
- aec_rdft_inverse_128(fft);
-
- // Overlap and add to obtain output.
- scale = 2.0f / PART_LEN2;
- for (i = 0; i < PART_LEN; i++) {
- fft[i] *= scale; // fft scaling
- fft[i] = fft[i] * WebRtcAec_sqrtHanning[i] + aec->outBuf[i];
-
- fft[PART_LEN + i] *= scale; // fft scaling
- aec->outBuf[i] = fft[PART_LEN + i] * WebRtcAec_sqrtHanning[PART_LEN - i];
-
- // Saturate output to keep it in the allowed range.
- output[i] = WEBRTC_SPL_SAT(
- WEBRTC_SPL_WORD16_MAX, fft[i], WEBRTC_SPL_WORD16_MIN);
- }
-
- // For H band
- if (aec->num_bands > 1) {
-
- // H band gain
- // average nlp over low band: average over second half of freq spectrum
- // (4->8khz)
- GetHighbandGain(hNl, &nlpGainHband);
-
- // Inverse comfort_noise
- if (flagHbandCn == 1) {
- fft[0] = comfortNoiseHband[0][0];
- fft[1] = comfortNoiseHband[PART_LEN][0];
- for (i = 1; i < PART_LEN; i++) {
- fft[2 * i] = comfortNoiseHband[i][0];
- fft[2 * i + 1] = comfortNoiseHband[i][1];
- }
- aec_rdft_inverse_128(fft);
- scale = 2.0f / PART_LEN2;
- }
-
- // compute gain factor
- for (j = 0; j < aec->num_bands - 1; ++j) {
- for (i = 0; i < PART_LEN; i++) {
- dtmp = aec->dBufH[j][i];
- dtmp = dtmp * nlpGainHband; // for variable gain
-
- // add some comfort noise where Hband is attenuated
- if (flagHbandCn == 1 && j == 0) {
- fft[i] *= scale; // fft scaling
- dtmp += cnScaleHband * fft[i];
- }
-
- // Saturate output to keep it in the allowed range.
- outputH[j][i] = WEBRTC_SPL_SAT(
- WEBRTC_SPL_WORD16_MAX, dtmp, WEBRTC_SPL_WORD16_MIN);
- }
- }
- }
-
- // Copy the current block to the old position.
- memcpy(aec->dBuf, aec->dBuf + PART_LEN, sizeof(float) * PART_LEN);
- memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN);
-
- // Copy the current block to the old position for H band
- for (j = 0; j < aec->num_bands - 1; ++j) {
- memcpy(aec->dBufH[j], aec->dBufH[j] + PART_LEN, sizeof(float) * PART_LEN);
- }
-
- memmove(aec->xfwBuf + PART_LEN1,
- aec->xfwBuf,
- sizeof(aec->xfwBuf) - sizeof(complex_t) * PART_LEN1);
-}
-
-static void ProcessBlock(AecCore* aec) {
- size_t i;
- float y[PART_LEN], e[PART_LEN];
- float scale;
-
- float fft[PART_LEN2];
- float xf[2][PART_LEN1], yf[2][PART_LEN1], ef[2][PART_LEN1];
- float df[2][PART_LEN1];
- float far_spectrum = 0.0f;
- float near_spectrum = 0.0f;
- float abs_far_spectrum[PART_LEN1];
- float abs_near_spectrum[PART_LEN1];
-
- const float gPow[2] = {0.9f, 0.1f};
-
- // Noise estimate constants.
- const int noiseInitBlocks = 500 * aec->mult;
- const float step = 0.1f;
- const float ramp = 1.0002f;
- const float gInitNoise[2] = {0.999f, 0.001f};
-
- float nearend[PART_LEN];
- float* nearend_ptr = NULL;
- float output[PART_LEN];
- float outputH[NUM_HIGH_BANDS_MAX][PART_LEN];
- float* outputH_ptr[NUM_HIGH_BANDS_MAX];
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) {
- outputH_ptr[i] = outputH[i];
- }
-
- float* xf_ptr = NULL;
-
- // Concatenate old and new nearend blocks.
- for (i = 0; i < aec->num_bands - 1; ++i) {
- WebRtc_ReadBuffer(aec->nearFrBufH[i],
- (void**)&nearend_ptr,
- nearend,
- PART_LEN);
- memcpy(aec->dBufH[i] + PART_LEN, nearend_ptr, sizeof(nearend));
- }
- WebRtc_ReadBuffer(aec->nearFrBuf, (void**)&nearend_ptr, nearend, PART_LEN);
- memcpy(aec->dBuf + PART_LEN, nearend_ptr, sizeof(nearend));
-
- // ---------- Ooura fft ----------
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- {
- float farend[PART_LEN];
- float* farend_ptr = NULL;
- WebRtc_ReadBuffer(aec->far_time_buf, (void**)&farend_ptr, farend, 1);
- RTC_AEC_DEBUG_WAV_WRITE(aec->farFile, farend_ptr, PART_LEN);
- RTC_AEC_DEBUG_WAV_WRITE(aec->nearFile, nearend_ptr, PART_LEN);
- }
-#endif
-
- // We should always have at least one element stored in |far_buf|.
- assert(WebRtc_available_read(aec->far_buf) > 0);
- WebRtc_ReadBuffer(aec->far_buf, (void**)&xf_ptr, &xf[0][0], 1);
-
- // Near fft
- memcpy(fft, aec->dBuf, sizeof(float) * PART_LEN2);
- TimeToFrequency(fft, df, 0);
-
- // Power smoothing
- for (i = 0; i < PART_LEN1; i++) {
- far_spectrum = (xf_ptr[i] * xf_ptr[i]) +
- (xf_ptr[PART_LEN1 + i] * xf_ptr[PART_LEN1 + i]);
- aec->xPow[i] =
- gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
- // Calculate absolute spectra
- abs_far_spectrum[i] = sqrtf(far_spectrum);
-
- near_spectrum = df[0][i] * df[0][i] + df[1][i] * df[1][i];
- aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum;
- // Calculate absolute spectra
- abs_near_spectrum[i] = sqrtf(near_spectrum);
- }
-
- // Estimate noise power. Wait until dPow is more stable.
- if (aec->noiseEstCtr > 50) {
- for (i = 0; i < PART_LEN1; i++) {
- if (aec->dPow[i] < aec->dMinPow[i]) {
- aec->dMinPow[i] =
- (aec->dPow[i] + step * (aec->dMinPow[i] - aec->dPow[i])) * ramp;
- } else {
- aec->dMinPow[i] *= ramp;
- }
- }
- }
-
- // Smooth increasing noise power from zero at the start,
- // to avoid a sudden burst of comfort noise.
- if (aec->noiseEstCtr < noiseInitBlocks) {
- aec->noiseEstCtr++;
- for (i = 0; i < PART_LEN1; i++) {
- if (aec->dMinPow[i] > aec->dInitMinPow[i]) {
- aec->dInitMinPow[i] = gInitNoise[0] * aec->dInitMinPow[i] +
- gInitNoise[1] * aec->dMinPow[i];
- } else {
- aec->dInitMinPow[i] = aec->dMinPow[i];
- }
- }
- aec->noisePow = aec->dInitMinPow;
- } else {
- aec->noisePow = aec->dMinPow;
- }
-
- // Block wise delay estimation used for logging
- if (aec->delay_logging_enabled) {
- if (WebRtc_AddFarSpectrumFloat(
- aec->delay_estimator_farend, abs_far_spectrum, PART_LEN1) == 0) {
- int delay_estimate = WebRtc_DelayEstimatorProcessFloat(
- aec->delay_estimator, abs_near_spectrum, PART_LEN1);
- if (delay_estimate >= 0) {
- // Update delay estimate buffer.
- aec->delay_histogram[delay_estimate]++;
- aec->num_delay_values++;
- }
- if (aec->delay_metrics_delivered == 1 &&
- aec->num_delay_values >= kDelayMetricsAggregationWindow) {
- UpdateDelayMetrics(aec);
- }
- }
- }
-
- // Update the xfBuf block position.
- aec->xfBufBlockPos--;
- if (aec->xfBufBlockPos == -1) {
- aec->xfBufBlockPos = aec->num_partitions - 1;
- }
-
- // Buffer xf
- memcpy(aec->xfBuf[0] + aec->xfBufBlockPos * PART_LEN1,
- xf_ptr,
- sizeof(float) * PART_LEN1);
- memcpy(aec->xfBuf[1] + aec->xfBufBlockPos * PART_LEN1,
- &xf_ptr[PART_LEN1],
- sizeof(float) * PART_LEN1);
-
- memset(yf, 0, sizeof(yf));
-
- // Filter far
- WebRtcAec_FilterFar(aec, yf);
-
- // Inverse fft to obtain echo estimate and error.
- fft[0] = yf[0][0];
- fft[1] = yf[0][PART_LEN];
- for (i = 1; i < PART_LEN; i++) {
- fft[2 * i] = yf[0][i];
- fft[2 * i + 1] = yf[1][i];
- }
- aec_rdft_inverse_128(fft);
-
- scale = 2.0f / PART_LEN2;
- for (i = 0; i < PART_LEN; i++) {
- y[i] = fft[PART_LEN + i] * scale; // fft scaling
- }
-
- for (i = 0; i < PART_LEN; i++) {
- e[i] = nearend_ptr[i] - y[i];
- }
-
- // Error fft
- memcpy(aec->eBuf + PART_LEN, e, sizeof(float) * PART_LEN);
- memset(fft, 0, sizeof(float) * PART_LEN);
- memcpy(fft + PART_LEN, e, sizeof(float) * PART_LEN);
- // TODO(bjornv): Change to use TimeToFrequency().
- aec_rdft_forward_128(fft);
-
- ef[1][0] = 0;
- ef[1][PART_LEN] = 0;
- ef[0][0] = fft[0];
- ef[0][PART_LEN] = fft[1];
- for (i = 1; i < PART_LEN; i++) {
- ef[0][i] = fft[2 * i];
- ef[1][i] = fft[2 * i + 1];
- }
-
- RTC_AEC_DEBUG_RAW_WRITE(aec->e_fft_file,
- &ef[0][0],
- sizeof(ef[0][0]) * PART_LEN1 * 2);
-
- if (aec->metricsMode == 1) {
- // Note that the first PART_LEN samples in fft (before transformation) are
- // zero. Hence, the scaling by two in UpdateLevel() should not be
- // performed. That scaling is taken care of in UpdateMetrics() instead.
- UpdateLevel(&aec->linoutlevel, ef);
- }
-
- // Scale error signal inversely with far power.
- WebRtcAec_ScaleErrorSignal(aec, ef);
- WebRtcAec_FilterAdaptation(aec, fft, ef);
- NonLinearProcessing(aec, output, outputH_ptr);
-
- if (aec->metricsMode == 1) {
- // Update power levels and echo metrics
- UpdateLevel(&aec->farlevel, (float(*)[PART_LEN1])xf_ptr);
- UpdateLevel(&aec->nearlevel, df);
- UpdateMetrics(aec);
- }
-
- // Store the output block.
- WebRtc_WriteBuffer(aec->outFrBuf, output, PART_LEN);
- // For high bands
- for (i = 0; i < aec->num_bands - 1; ++i) {
- WebRtc_WriteBuffer(aec->outFrBufH[i], outputH[i], PART_LEN);
- }
-
- RTC_AEC_DEBUG_WAV_WRITE(aec->outLinearFile, e, PART_LEN);
- RTC_AEC_DEBUG_WAV_WRITE(aec->outFile, output, PART_LEN);
-}
-
-AecCore* WebRtcAec_CreateAec() {
- int i;
- AecCore* aec = malloc(sizeof(AecCore));
- if (!aec) {
- return NULL;
- }
-
- aec->nearFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float));
- if (!aec->nearFrBuf) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
-
- aec->outFrBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(float));
- if (!aec->outFrBuf) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
-
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) {
- aec->nearFrBufH[i] = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
- sizeof(float));
- if (!aec->nearFrBufH[i]) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
- aec->outFrBufH[i] = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
- sizeof(float));
- if (!aec->outFrBufH[i]) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
- }
-
- // Create far-end buffers.
- aec->far_buf =
- WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * 2 * PART_LEN1);
- if (!aec->far_buf) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
- aec->far_buf_windowed =
- WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * 2 * PART_LEN1);
- if (!aec->far_buf_windowed) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- aec->instance_index = webrtc_aec_instance_count;
- aec->far_time_buf =
- WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * PART_LEN);
- if (!aec->far_time_buf) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
- aec->farFile = aec->nearFile = aec->outFile = aec->outLinearFile = NULL;
- aec->debug_dump_count = 0;
-#endif
- aec->delay_estimator_farend =
- WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks);
- if (aec->delay_estimator_farend == NULL) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
- // We create the delay_estimator with the same amount of maximum lookahead as
- // the delay history size (kHistorySizeBlocks) for symmetry reasons.
- aec->delay_estimator = WebRtc_CreateDelayEstimator(
- aec->delay_estimator_farend, kHistorySizeBlocks);
- if (aec->delay_estimator == NULL) {
- WebRtcAec_FreeAec(aec);
- return NULL;
- }
-#ifdef WEBRTC_ANDROID
- aec->delay_agnostic_enabled = 1; // DA-AEC enabled by default.
- // DA-AEC assumes the system is causal from the beginning and will self adjust
- // the lookahead when shifting is required.
- WebRtc_set_lookahead(aec->delay_estimator, 0);
-#else
- aec->delay_agnostic_enabled = 0;
- WebRtc_set_lookahead(aec->delay_estimator, kLookaheadBlocks);
-#endif
- aec->extended_filter_enabled = 0;
-
- // Assembly optimization
- WebRtcAec_FilterFar = FilterFar;
- WebRtcAec_ScaleErrorSignal = ScaleErrorSignal;
- WebRtcAec_FilterAdaptation = FilterAdaptation;
- WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppress;
- WebRtcAec_ComfortNoise = ComfortNoise;
- WebRtcAec_SubbandCoherence = SubbandCoherence;
-
-#if defined(WEBRTC_ARCH_X86_FAMILY)
- if (WebRtc_GetCPUInfo(kSSE2)) {
- WebRtcAec_InitAec_SSE2();
- }
-#endif
-
-#if defined(MIPS_FPU_LE)
- WebRtcAec_InitAec_mips();
-#endif
-
-#if defined(WEBRTC_HAS_NEON)
- WebRtcAec_InitAec_neon();
-#elif defined(WEBRTC_DETECT_NEON)
- if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
- WebRtcAec_InitAec_neon();
- }
-#endif
-
- aec_rdft_init();
-
- return aec;
-}
-
-void WebRtcAec_FreeAec(AecCore* aec) {
- int i;
- if (aec == NULL) {
- return;
- }
-
- WebRtc_FreeBuffer(aec->nearFrBuf);
- WebRtc_FreeBuffer(aec->outFrBuf);
-
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) {
- WebRtc_FreeBuffer(aec->nearFrBufH[i]);
- WebRtc_FreeBuffer(aec->outFrBufH[i]);
- }
-
- WebRtc_FreeBuffer(aec->far_buf);
- WebRtc_FreeBuffer(aec->far_buf_windowed);
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- WebRtc_FreeBuffer(aec->far_time_buf);
-#endif
- RTC_AEC_DEBUG_WAV_CLOSE(aec->farFile);
- RTC_AEC_DEBUG_WAV_CLOSE(aec->nearFile);
- RTC_AEC_DEBUG_WAV_CLOSE(aec->outFile);
- RTC_AEC_DEBUG_WAV_CLOSE(aec->outLinearFile);
- RTC_AEC_DEBUG_RAW_CLOSE(aec->e_fft_file);
-
- WebRtc_FreeDelayEstimator(aec->delay_estimator);
- WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend);
-
- free(aec);
-}
-
-int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
- int i;
-
- aec->sampFreq = sampFreq;
-
- if (sampFreq == 8000) {
- aec->normal_mu = 0.6f;
- aec->normal_error_threshold = 2e-6f;
- aec->num_bands = 1;
- } else {
- aec->normal_mu = 0.5f;
- aec->normal_error_threshold = 1.5e-6f;
- aec->num_bands = (size_t)(sampFreq / 16000);
- }
-
- WebRtc_InitBuffer(aec->nearFrBuf);
- WebRtc_InitBuffer(aec->outFrBuf);
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) {
- WebRtc_InitBuffer(aec->nearFrBufH[i]);
- WebRtc_InitBuffer(aec->outFrBufH[i]);
- }
-
- // Initialize far-end buffers.
- WebRtc_InitBuffer(aec->far_buf);
- WebRtc_InitBuffer(aec->far_buf_windowed);
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- WebRtc_InitBuffer(aec->far_time_buf);
- {
- int process_rate = sampFreq > 16000 ? 16000 : sampFreq;
- RTC_AEC_DEBUG_WAV_REOPEN("aec_far", aec->instance_index,
- aec->debug_dump_count, process_rate,
- &aec->farFile );
- RTC_AEC_DEBUG_WAV_REOPEN("aec_near", aec->instance_index,
- aec->debug_dump_count, process_rate,
- &aec->nearFile);
- RTC_AEC_DEBUG_WAV_REOPEN("aec_out", aec->instance_index,
- aec->debug_dump_count, process_rate,
- &aec->outFile );
- RTC_AEC_DEBUG_WAV_REOPEN("aec_out_linear", aec->instance_index,
- aec->debug_dump_count, process_rate,
- &aec->outLinearFile);
- }
-
- RTC_AEC_DEBUG_RAW_OPEN("aec_e_fft",
- aec->debug_dump_count,
- &aec->e_fft_file);
-
- ++aec->debug_dump_count;
-#endif
- aec->system_delay = 0;
-
- if (WebRtc_InitDelayEstimatorFarend(aec->delay_estimator_farend) != 0) {
- return -1;
- }
- if (WebRtc_InitDelayEstimator(aec->delay_estimator) != 0) {
- return -1;
- }
- aec->delay_logging_enabled = 0;
- aec->delay_metrics_delivered = 0;
- memset(aec->delay_histogram, 0, sizeof(aec->delay_histogram));
- aec->num_delay_values = 0;
- aec->delay_median = -1;
- aec->delay_std = -1;
- aec->fraction_poor_delays = -1.0f;
-
- aec->signal_delay_correction = 0;
- aec->previous_delay = -2; // (-2): Uninitialized.
- aec->delay_correction_count = 0;
- aec->shift_offset = kInitialShiftOffset;
- aec->delay_quality_threshold = kDelayQualityThresholdMin;
-
- aec->num_partitions = kNormalNumPartitions;
-
- // Update the delay estimator with filter length. We use half the
- // |num_partitions| to take the echo path into account. In practice we say
- // that the echo has a duration of maximum half |num_partitions|, which is not
- // true, but serves as a crude measure.
- WebRtc_set_allowed_offset(aec->delay_estimator, aec->num_partitions / 2);
- // TODO(bjornv): I currently hard coded the enable. Once we've established
- // that AECM has no performance regression, robust_validation will be enabled
- // all the time and the APIs to turn it on/off will be removed. Hence, remove
- // this line then.
- WebRtc_enable_robust_validation(aec->delay_estimator, 1);
- aec->frame_count = 0;
-
- // Default target suppression mode.
- aec->nlp_mode = 1;
-
- // Sampling frequency multiplier w.r.t. 8 kHz.
- // In case of multiple bands we process the lower band in 16 kHz, hence the
- // multiplier is always 2.
- if (aec->num_bands > 1) {
- aec->mult = 2;
- } else {
- aec->mult = (short)aec->sampFreq / 8000;
- }
-
- aec->farBufWritePos = 0;
- aec->farBufReadPos = 0;
-
- aec->inSamples = 0;
- aec->outSamples = 0;
- aec->knownDelay = 0;
-
- // Initialize buffers
- memset(aec->dBuf, 0, sizeof(aec->dBuf));
- memset(aec->eBuf, 0, sizeof(aec->eBuf));
- // For H bands
- for (i = 0; i < NUM_HIGH_BANDS_MAX; ++i) {
- memset(aec->dBufH[i], 0, sizeof(aec->dBufH[i]));
- }
-
- memset(aec->xPow, 0, sizeof(aec->xPow));
- memset(aec->dPow, 0, sizeof(aec->dPow));
- memset(aec->dInitMinPow, 0, sizeof(aec->dInitMinPow));
- aec->noisePow = aec->dInitMinPow;
- aec->noiseEstCtr = 0;
-
- // Initial comfort noise power
- for (i = 0; i < PART_LEN1; i++) {
- aec->dMinPow[i] = 1.0e6f;
- }
-
- // Holds the last block written to
- aec->xfBufBlockPos = 0;
- // TODO: Investigate need for these initializations. Deleting them doesn't
- // change the output at all and yields 0.4% overall speedup.
- memset(aec->xfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
- memset(aec->wfBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
- memset(aec->sde, 0, sizeof(complex_t) * PART_LEN1);
- memset(aec->sxd, 0, sizeof(complex_t) * PART_LEN1);
- memset(
- aec->xfwBuf, 0, sizeof(complex_t) * kExtendedNumPartitions * PART_LEN1);
- memset(aec->se, 0, sizeof(float) * PART_LEN1);
-
- // To prevent numerical instability in the first block.
- for (i = 0; i < PART_LEN1; i++) {
- aec->sd[i] = 1;
- }
- for (i = 0; i < PART_LEN1; i++) {
- aec->sx[i] = 1;
- }
-
- memset(aec->hNs, 0, sizeof(aec->hNs));
- memset(aec->outBuf, 0, sizeof(float) * PART_LEN);
-
- aec->hNlFbMin = 1;
- aec->hNlFbLocalMin = 1;
- aec->hNlXdAvgMin = 1;
- aec->hNlNewMin = 0;
- aec->hNlMinCtr = 0;
- aec->overDrive = 2;
- aec->overDriveSm = 2;
- aec->delayIdx = 0;
- aec->stNearState = 0;
- aec->echoState = 0;
- aec->divergeState = 0;
-
- aec->seed = 777;
- aec->delayEstCtr = 0;
-
- // Metrics disabled by default
- aec->metricsMode = 0;
- InitMetrics(aec);
-
- return 0;
-}
-
-void WebRtcAec_BufferFarendPartition(AecCore* aec, const float* farend) {
- float fft[PART_LEN2];
- float xf[2][PART_LEN1];
-
- // Check if the buffer is full, and in that case flush the oldest data.
- if (WebRtc_available_write(aec->far_buf) < 1) {
- WebRtcAec_MoveFarReadPtr(aec, 1);
- }
- // Convert far-end partition to the frequency domain without windowing.
- memcpy(fft, farend, sizeof(float) * PART_LEN2);
- TimeToFrequency(fft, xf, 0);
- WebRtc_WriteBuffer(aec->far_buf, &xf[0][0], 1);
-
- // Convert far-end partition to the frequency domain with windowing.
- memcpy(fft, farend, sizeof(float) * PART_LEN2);
- TimeToFrequency(fft, xf, 1);
- WebRtc_WriteBuffer(aec->far_buf_windowed, &xf[0][0], 1);
-}
-
-int WebRtcAec_MoveFarReadPtr(AecCore* aec, int elements) {
- int elements_moved = MoveFarReadPtrWithoutSystemDelayUpdate(aec, elements);
- aec->system_delay -= elements_moved * PART_LEN;
- return elements_moved;
-}
-
-void WebRtcAec_ProcessFrames(AecCore* aec,
- const float* const* nearend,
- size_t num_bands,
- size_t num_samples,
- int knownDelay,
- float* const* out) {
- size_t i, j;
- int out_elements = 0;
-
- aec->frame_count++;
- // For each frame the process is as follows:
- // 1) If the system_delay indicates on being too small for processing a
- // frame we stuff the buffer with enough data for 10 ms.
- // 2 a) Adjust the buffer to the system delay, by moving the read pointer.
- // b) Apply signal based delay correction, if we have detected poor AEC
- // performance.
- // 3) TODO(bjornv): Investigate if we need to add this:
- // If we can't move read pointer due to buffer size limitations we
- // flush/stuff the buffer.
- // 4) Process as many partitions as possible.
- // 5) Update the |system_delay| with respect to a full frame of FRAME_LEN
- // samples. Even though we will have data left to process (we work with
- // partitions) we consider updating a whole frame, since that's the
- // amount of data we input and output in audio_processing.
- // 6) Update the outputs.
-
- // The AEC has two different delay estimation algorithms built in. The
- // first relies on delay input values from the user and the amount of
- // shifted buffer elements is controlled by |knownDelay|. This delay will
- // give a guess on how much we need to shift far-end buffers to align with
- // the near-end signal. The other delay estimation algorithm uses the
- // far- and near-end signals to find the offset between them. This one
- // (called "signal delay") is then used to fine tune the alignment, or
- // simply compensate for errors in the system based one.
- // Note that the two algorithms operate independently. Currently, we only
- // allow one algorithm to be turned on.
-
- assert(aec->num_bands == num_bands);
-
- for (j = 0; j < num_samples; j+= FRAME_LEN) {
- // TODO(bjornv): Change the near-end buffer handling to be the same as for
- // far-end, that is, with a near_pre_buf.
- // Buffer the near-end frame.
- WebRtc_WriteBuffer(aec->nearFrBuf, &nearend[0][j], FRAME_LEN);
- // For H band
- for (i = 1; i < num_bands; ++i) {
- WebRtc_WriteBuffer(aec->nearFrBufH[i - 1], &nearend[i][j], FRAME_LEN);
- }
-
- // 1) At most we process |aec->mult|+1 partitions in 10 ms. Make sure we
- // have enough far-end data for that by stuffing the buffer if the
- // |system_delay| indicates others.
- if (aec->system_delay < FRAME_LEN) {
- // We don't have enough data so we rewind 10 ms.
- WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1));
- }
-
- if (!aec->delay_agnostic_enabled) {
- // 2 a) Compensate for a possible change in the system delay.
-
- // TODO(bjornv): Investigate how we should round the delay difference;
- // right now we know that incoming |knownDelay| is underestimated when
- // it's less than |aec->knownDelay|. We therefore, round (-32) in that
- // direction. In the other direction, we don't have this situation, but
- // might flush one partition too little. This can cause non-causality,
- // which should be investigated. Maybe, allow for a non-symmetric
- // rounding, like -16.
- int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN;
- int moved_elements =
- MoveFarReadPtrWithoutSystemDelayUpdate(aec, move_elements);
- aec->knownDelay -= moved_elements * PART_LEN;
- } else {
- // 2 b) Apply signal based delay correction.
- int move_elements = SignalBasedDelayCorrection(aec);
- int moved_elements =
- MoveFarReadPtrWithoutSystemDelayUpdate(aec, move_elements);
- int far_near_buffer_diff = WebRtc_available_read(aec->far_buf) -
- WebRtc_available_read(aec->nearFrBuf) / PART_LEN;
- WebRtc_SoftResetDelayEstimator(aec->delay_estimator, moved_elements);
- WebRtc_SoftResetDelayEstimatorFarend(aec->delay_estimator_farend,
- moved_elements);
- aec->signal_delay_correction += moved_elements;
- // If we rely on reported system delay values only, a buffer underrun here
- // can never occur since we've taken care of that in 1) above. Here, we
- // apply signal based delay correction and can therefore end up with
- // buffer underruns since the delay estimation can be wrong. We therefore
- // stuff the buffer with enough elements if needed.
- if (far_near_buffer_diff < 0) {
- WebRtcAec_MoveFarReadPtr(aec, far_near_buffer_diff);
- }
- }
-
- // 4) Process as many blocks as possible.
- while (WebRtc_available_read(aec->nearFrBuf) >= PART_LEN) {
- ProcessBlock(aec);
- }
-
- // 5) Update system delay with respect to the entire frame.
- aec->system_delay -= FRAME_LEN;
-
- // 6) Update output frame.
- // Stuff the out buffer if we have less than a frame to output.
- // This should only happen for the first frame.
- out_elements = (int)WebRtc_available_read(aec->outFrBuf);
- if (out_elements < FRAME_LEN) {
- WebRtc_MoveReadPtr(aec->outFrBuf, out_elements - FRAME_LEN);
- for (i = 0; i < num_bands - 1; ++i) {
- WebRtc_MoveReadPtr(aec->outFrBufH[i], out_elements - FRAME_LEN);
- }
- }
- // Obtain an output frame.
- WebRtc_ReadBuffer(aec->outFrBuf, NULL, &out[0][j], FRAME_LEN);
- // For H bands.
- for (i = 1; i < num_bands; ++i) {
- WebRtc_ReadBuffer(aec->outFrBufH[i - 1], NULL, &out[i][j], FRAME_LEN);
- }
- }
-}
-
-int WebRtcAec_GetDelayMetricsCore(AecCore* self, int* median, int* std,
- float* fraction_poor_delays) {
- assert(self != NULL);
- assert(median != NULL);
- assert(std != NULL);
-
- if (self->delay_logging_enabled == 0) {
- // Logging disabled.
- return -1;
- }
-
- if (self->delay_metrics_delivered == 0) {
- UpdateDelayMetrics(self);
- self->delay_metrics_delivered = 1;
- }
- *median = self->delay_median;
- *std = self->delay_std;
- *fraction_poor_delays = self->fraction_poor_delays;
-
- return 0;
-}
-
-int WebRtcAec_echo_state(AecCore* self) { return self->echoState; }
-
-void WebRtcAec_GetEchoStats(AecCore* self,
- Stats* erl,
- Stats* erle,
- Stats* a_nlp) {
- assert(erl != NULL);
- assert(erle != NULL);
- assert(a_nlp != NULL);
- *erl = self->erl;
- *erle = self->erle;
- *a_nlp = self->aNlp;
-}
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-void* WebRtcAec_far_time_buf(AecCore* self) { return self->far_time_buf; }
-#endif
-
-void WebRtcAec_SetConfigCore(AecCore* self,
- int nlp_mode,
- int metrics_mode,
- int delay_logging) {
- assert(nlp_mode >= 0 && nlp_mode < 3);
- self->nlp_mode = nlp_mode;
- self->metricsMode = metrics_mode;
- if (self->metricsMode) {
- InitMetrics(self);
- }
- // Turn on delay logging if it is either set explicitly or if delay agnostic
- // AEC is enabled (which requires delay estimates).
- self->delay_logging_enabled = delay_logging || self->delay_agnostic_enabled;
- if (self->delay_logging_enabled) {
- memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
- }
-}
-
-void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable) {
- self->delay_agnostic_enabled = enable;
-}
-
-int WebRtcAec_delay_agnostic_enabled(AecCore* self) {
- return self->delay_agnostic_enabled;
-}
-
-void WebRtcAec_enable_extended_filter(AecCore* self, int enable) {
- self->extended_filter_enabled = enable;
- self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions;
- // Update the delay estimator with filter length. See InitAEC() for details.
- WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2);
-}
-
-int WebRtcAec_extended_filter_enabled(AecCore* self) {
- return self->extended_filter_enabled;
-}
-
-int WebRtcAec_system_delay(AecCore* self) { return self->system_delay; }
-
-void WebRtcAec_SetSystemDelay(AecCore* self, int delay) {
- assert(delay >= 0);
- self->system_delay = delay;
-}
diff --git a/webrtc/modules/audio_processing/aec/aec_core.h b/webrtc/modules/audio_processing/aec/aec_core.h
deleted file mode 100644
index 241f077..0000000
--- a/webrtc/modules/audio_processing/aec/aec_core.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * Specifies the interface for the AEC core.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
-
-#include <stddef.h>
-
-#include "webrtc/typedefs.h"
-
-#define FRAME_LEN 80
-#define PART_LEN 64 // Length of partition
-#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients
-#define PART_LEN2 (PART_LEN * 2) // Length of partition * 2
-#define NUM_HIGH_BANDS_MAX 2 // Max number of high bands
-
-typedef float complex_t[2];
-// For performance reasons, some arrays of complex numbers are replaced by twice
-// as long arrays of float, all the real parts followed by all the imaginary
-// ones (complex_t[SIZE] -> float[2][SIZE]). This allows SIMD optimizations and
-// is better than two arrays (one for the real parts and one for the imaginary
-// parts) as this other way would require two pointers instead of one and cause
-// extra register spilling. This also allows the offsets to be calculated at
-// compile time.
-
-// Metrics
-enum {
- kOffsetLevel = -100
-};
-
-typedef struct Stats {
- float instant;
- float average;
- float min;
- float max;
- float sum;
- float hisum;
- float himean;
- int counter;
- int hicounter;
-} Stats;
-
-typedef struct AecCore AecCore;
-
-AecCore* WebRtcAec_CreateAec(); // Returns NULL on error.
-void WebRtcAec_FreeAec(AecCore* aec);
-int WebRtcAec_InitAec(AecCore* aec, int sampFreq);
-void WebRtcAec_InitAec_SSE2(void);
-#if defined(MIPS_FPU_LE)
-void WebRtcAec_InitAec_mips(void);
-#endif
-#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
-void WebRtcAec_InitAec_neon(void);
-#endif
-
-void WebRtcAec_BufferFarendPartition(AecCore* aec, const float* farend);
-void WebRtcAec_ProcessFrames(AecCore* aec,
- const float* const* nearend,
- size_t num_bands,
- size_t num_samples,
- int knownDelay,
- float* const* out);
-
-// A helper function to call WebRtc_MoveReadPtr() for all far-end buffers.
-// Returns the number of elements moved, and adjusts |system_delay| by the
-// corresponding amount in ms.
-int WebRtcAec_MoveFarReadPtr(AecCore* aec, int elements);
-
-// Calculates the median, standard deviation and amount of poor values among the
-// delay estimates aggregated up to the first call to the function. After that
-// first call the metrics are aggregated and updated every second. With poor
-// values we mean values that most likely will cause the AEC to perform poorly.
-// TODO(bjornv): Consider changing tests and tools to handle constant
-// constant aggregation window throughout the session instead.
-int WebRtcAec_GetDelayMetricsCore(AecCore* self, int* median, int* std,
- float* fraction_poor_delays);
-
-// Returns the echo state (1: echo, 0: no echo).
-int WebRtcAec_echo_state(AecCore* self);
-
-// Gets statistics of the echo metrics ERL, ERLE, A_NLP.
-void WebRtcAec_GetEchoStats(AecCore* self,
- Stats* erl,
- Stats* erle,
- Stats* a_nlp);
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-void* WebRtcAec_far_time_buf(AecCore* self);
-#endif
-
-// Sets local configuration modes.
-void WebRtcAec_SetConfigCore(AecCore* self,
- int nlp_mode,
- int metrics_mode,
- int delay_logging);
-
-// Non-zero enables, zero disables.
-void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable);
-
-// Returns non-zero if delay agnostic (i.e., signal based delay estimation) is
-// enabled and zero if disabled.
-int WebRtcAec_delay_agnostic_enabled(AecCore* self);
-
-// Enables or disables extended filter mode. Non-zero enables, zero disables.
-void WebRtcAec_enable_extended_filter(AecCore* self, int enable);
-
-// Returns non-zero if extended filter mode is enabled and zero if disabled.
-int WebRtcAec_extended_filter_enabled(AecCore* self);
-
-// Returns the current |system_delay|, i.e., the buffered difference between
-// far-end and near-end.
-int WebRtcAec_system_delay(AecCore* self);
-
-// Sets the |system_delay| to |value|. Note that if the value is changed
-// improperly, there can be a performance regression. So it should be used with
-// care.
-void WebRtcAec_SetSystemDelay(AecCore* self, int delay);
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
diff --git a/webrtc/modules/audio_processing/aec/aec_core_internal.h b/webrtc/modules/audio_processing/aec/aec_core_internal.h
deleted file mode 100644
index 2de0283..0000000
--- a/webrtc/modules/audio_processing/aec/aec_core_internal.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
-
-#include "webrtc/common_audio/ring_buffer.h"
-#include "webrtc/common_audio/wav_file.h"
-#include "webrtc/modules/audio_processing/aec/aec_common.h"
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-#include "webrtc/typedefs.h"
-
-// Number of partitions for the extended filter mode. The first one is an enum
-// to be used in array declarations, as it represents the maximum filter length.
-enum {
- kExtendedNumPartitions = 32
-};
-static const int kNormalNumPartitions = 12;
-
-// Delay estimator constants, used for logging and delay compensation if
-// if reported delays are disabled.
-enum {
- kLookaheadBlocks = 15
-};
-enum {
- // 500 ms for 16 kHz which is equivalent with the limit of reported delays.
- kHistorySizeBlocks = 125
-};
-
-// Extended filter adaptation parameters.
-// TODO(ajm): No narrowband tuning yet.
-static const float kExtendedMu = 0.4f;
-static const float kExtendedErrorThreshold = 1.0e-6f;
-
-typedef struct PowerLevel {
- float sfrsum;
- int sfrcounter;
- float framelevel;
- float frsum;
- int frcounter;
- float minlevel;
- float averagelevel;
-} PowerLevel;
-
-struct AecCore {
- int farBufWritePos, farBufReadPos;
-
- int knownDelay;
- int inSamples, outSamples;
- int delayEstCtr;
-
- RingBuffer* nearFrBuf;
- RingBuffer* outFrBuf;
-
- RingBuffer* nearFrBufH[NUM_HIGH_BANDS_MAX];
- RingBuffer* outFrBufH[NUM_HIGH_BANDS_MAX];
-
- float dBuf[PART_LEN2]; // nearend
- float eBuf[PART_LEN2]; // error
-
- float dBufH[NUM_HIGH_BANDS_MAX][PART_LEN2]; // nearend
-
- float xPow[PART_LEN1];
- float dPow[PART_LEN1];
- float dMinPow[PART_LEN1];
- float dInitMinPow[PART_LEN1];
- float* noisePow;
-
- float xfBuf[2][kExtendedNumPartitions * PART_LEN1]; // farend fft buffer
- float wfBuf[2][kExtendedNumPartitions * PART_LEN1]; // filter fft
- complex_t sde[PART_LEN1]; // cross-psd of nearend and error
- complex_t sxd[PART_LEN1]; // cross-psd of farend and nearend
- // Farend windowed fft buffer.
- complex_t xfwBuf[kExtendedNumPartitions * PART_LEN1];
-
- float sx[PART_LEN1], sd[PART_LEN1], se[PART_LEN1]; // far, near, error psd
- float hNs[PART_LEN1];
- float hNlFbMin, hNlFbLocalMin;
- float hNlXdAvgMin;
- int hNlNewMin, hNlMinCtr;
- float overDrive, overDriveSm;
- int nlp_mode;
- float outBuf[PART_LEN];
- int delayIdx;
-
- short stNearState, echoState;
- short divergeState;
-
- int xfBufBlockPos;
-
- RingBuffer* far_buf;
- RingBuffer* far_buf_windowed;
- int system_delay; // Current system delay buffered in AEC.
-
- int mult; // sampling frequency multiple
- int sampFreq;
- size_t num_bands;
- uint32_t seed;
-
- float normal_mu; // stepsize
- float normal_error_threshold; // error threshold
-
- int noiseEstCtr;
-
- PowerLevel farlevel;
- PowerLevel nearlevel;
- PowerLevel linoutlevel;
- PowerLevel nlpoutlevel;
-
- int metricsMode;
- int stateCounter;
- Stats erl;
- Stats erle;
- Stats aNlp;
- Stats rerl;
-
- // Quantities to control H band scaling for SWB input
- int freq_avg_ic; // initial bin for averaging nlp gain
- int flag_Hband_cn; // for comfort noise
- float cn_scale_Hband; // scale for comfort noise in H band
-
- int delay_metrics_delivered;
- int delay_histogram[kHistorySizeBlocks];
- int num_delay_values;
- int delay_median;
- int delay_std;
- float fraction_poor_delays;
- int delay_logging_enabled;
- void* delay_estimator_farend;
- void* delay_estimator;
- // Variables associated with delay correction through signal based delay
- // estimation feedback.
- int signal_delay_correction;
- int previous_delay;
- int delay_correction_count;
- int shift_offset;
- float delay_quality_threshold;
- int frame_count;
-
- // 0 = delay agnostic mode (signal based delay correction) disabled.
- // Otherwise enabled.
- int delay_agnostic_enabled;
- // 1 = extended filter mode enabled, 0 = disabled.
- int extended_filter_enabled;
- // Runtime selection of number of filter partitions.
- int num_partitions;
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- // Sequence number of this AEC instance, so that different instances can
- // choose different dump file names.
- int instance_index;
-
- // Number of times we've restarted dumping; used to pick new dump file names
- // each time.
- int debug_dump_count;
-
- RingBuffer* far_time_buf;
- rtc_WavWriter* farFile;
- rtc_WavWriter* nearFile;
- rtc_WavWriter* outFile;
- rtc_WavWriter* outLinearFile;
- FILE* e_fft_file;
-#endif
-};
-
-typedef void (*WebRtcAecFilterFar)(AecCore* aec, float yf[2][PART_LEN1]);
-extern WebRtcAecFilterFar WebRtcAec_FilterFar;
-typedef void (*WebRtcAecScaleErrorSignal)(AecCore* aec, float ef[2][PART_LEN1]);
-extern WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;
-typedef void (*WebRtcAecFilterAdaptation)(AecCore* aec,
- float* fft,
- float ef[2][PART_LEN1]);
-extern WebRtcAecFilterAdaptation WebRtcAec_FilterAdaptation;
-typedef void (*WebRtcAecOverdriveAndSuppress)(AecCore* aec,
- float hNl[PART_LEN1],
- const float hNlFb,
- float efw[2][PART_LEN1]);
-extern WebRtcAecOverdriveAndSuppress WebRtcAec_OverdriveAndSuppress;
-
-typedef void (*WebRtcAecComfortNoise)(AecCore* aec,
- float efw[2][PART_LEN1],
- complex_t* comfortNoiseHband,
- const float* noisePow,
- const float* lambda);
-extern WebRtcAecComfortNoise WebRtcAec_ComfortNoise;
-
-typedef void (*WebRtcAecSubBandCoherence)(AecCore* aec,
- float efw[2][PART_LEN1],
- float xfw[2][PART_LEN1],
- float* fft,
- float* cohde,
- float* cohxd);
-extern WebRtcAecSubBandCoherence WebRtcAec_SubbandCoherence;
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
diff --git a/webrtc/modules/audio_processing/aec/aec_core_mips.c b/webrtc/modules/audio_processing/aec/aec_core_mips.c
deleted file mode 100644
index bb33087..0000000
--- a/webrtc/modules/audio_processing/aec/aec_core_mips.c
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * The core AEC algorithm, which is presented with time-aligned signals.
- */
-
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-
-#include <math.h>
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/aec/aec_core_internal.h"
-#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
-
-static const int flagHbandCn = 1; // flag for adding comfort noise in H band
-extern const float WebRtcAec_weightCurve[65];
-extern const float WebRtcAec_overDriveCurve[65];
-
-void WebRtcAec_ComfortNoise_mips(AecCore* aec,
- float efw[2][PART_LEN1],
- complex_t* comfortNoiseHband,
- const float* noisePow,
- const float* lambda) {
- int i, num;
- float rand[PART_LEN];
- float noise, noiseAvg, tmp, tmpAvg;
- int16_t randW16[PART_LEN];
- complex_t u[PART_LEN1];
-
- const float pi2 = 6.28318530717959f;
- const float pi2t = pi2 / 32768;
-
- // Generate a uniform random array on [0 1]
- WebRtcSpl_RandUArray(randW16, PART_LEN, &aec->seed);
-
- int16_t* randWptr = randW16;
- float randTemp, randTemp2, randTemp3, randTemp4;
- int32_t tmp1s, tmp2s, tmp3s, tmp4s;
-
- for (i = 0; i < PART_LEN; i+=4) {
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "lh %[tmp1s], 0(%[randWptr]) \n\t"
- "lh %[tmp2s], 2(%[randWptr]) \n\t"
- "lh %[tmp3s], 4(%[randWptr]) \n\t"
- "lh %[tmp4s], 6(%[randWptr]) \n\t"
- "mtc1 %[tmp1s], %[randTemp] \n\t"
- "mtc1 %[tmp2s], %[randTemp2] \n\t"
- "mtc1 %[tmp3s], %[randTemp3] \n\t"
- "mtc1 %[tmp4s], %[randTemp4] \n\t"
- "cvt.s.w %[randTemp], %[randTemp] \n\t"
- "cvt.s.w %[randTemp2], %[randTemp2] \n\t"
- "cvt.s.w %[randTemp3], %[randTemp3] \n\t"
- "cvt.s.w %[randTemp4], %[randTemp4] \n\t"
- "addiu %[randWptr], %[randWptr], 8 \n\t"
- "mul.s %[randTemp], %[randTemp], %[pi2t] \n\t"
- "mul.s %[randTemp2], %[randTemp2], %[pi2t] \n\t"
- "mul.s %[randTemp3], %[randTemp3], %[pi2t] \n\t"
- "mul.s %[randTemp4], %[randTemp4], %[pi2t] \n\t"
- ".set pop \n\t"
- : [randWptr] "+r" (randWptr), [randTemp] "=&f" (randTemp),
- [randTemp2] "=&f" (randTemp2), [randTemp3] "=&f" (randTemp3),
- [randTemp4] "=&f" (randTemp4), [tmp1s] "=&r" (tmp1s),
- [tmp2s] "=&r" (tmp2s), [tmp3s] "=&r" (tmp3s),
- [tmp4s] "=&r" (tmp4s)
- : [pi2t] "f" (pi2t)
- : "memory"
- );
-
- u[i+1][0] = cosf(randTemp);
- u[i+1][1] = sinf(randTemp);
- u[i+2][0] = cosf(randTemp2);
- u[i+2][1] = sinf(randTemp2);
- u[i+3][0] = cosf(randTemp3);
- u[i+3][1] = sinf(randTemp3);
- u[i+4][0] = cosf(randTemp4);
- u[i+4][1] = sinf(randTemp4);
- }
-
- // Reject LF noise
- float* u_ptr = &u[1][0];
- float noise2, noise3, noise4;
- float tmp1f, tmp2f, tmp3f, tmp4f, tmp5f, tmp6f, tmp7f, tmp8f;
-
- u[0][0] = 0;
- u[0][1] = 0;
- for (i = 1; i < PART_LEN1; i+=4) {
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "lwc1 %[noise], 4(%[noisePow]) \n\t"
- "lwc1 %[noise2], 8(%[noisePow]) \n\t"
- "lwc1 %[noise3], 12(%[noisePow]) \n\t"
- "lwc1 %[noise4], 16(%[noisePow]) \n\t"
- "sqrt.s %[noise], %[noise] \n\t"
- "sqrt.s %[noise2], %[noise2] \n\t"
- "sqrt.s %[noise3], %[noise3] \n\t"
- "sqrt.s %[noise4], %[noise4] \n\t"
- "lwc1 %[tmp1f], 0(%[u_ptr]) \n\t"
- "lwc1 %[tmp2f], 4(%[u_ptr]) \n\t"
- "lwc1 %[tmp3f], 8(%[u_ptr]) \n\t"
- "lwc1 %[tmp4f], 12(%[u_ptr]) \n\t"
- "lwc1 %[tmp5f], 16(%[u_ptr]) \n\t"
- "lwc1 %[tmp6f], 20(%[u_ptr]) \n\t"
- "lwc1 %[tmp7f], 24(%[u_ptr]) \n\t"
- "lwc1 %[tmp8f], 28(%[u_ptr]) \n\t"
- "addiu %[noisePow], %[noisePow], 16 \n\t"
- "mul.s %[tmp1f], %[tmp1f], %[noise] \n\t"
- "mul.s %[tmp2f], %[tmp2f], %[noise] \n\t"
- "mul.s %[tmp3f], %[tmp3f], %[noise2] \n\t"
- "mul.s %[tmp4f], %[tmp4f], %[noise2] \n\t"
- "mul.s %[tmp5f], %[tmp5f], %[noise3] \n\t"
- "mul.s %[tmp6f], %[tmp6f], %[noise3] \n\t"
- "swc1 %[tmp1f], 0(%[u_ptr]) \n\t"
- "swc1 %[tmp3f], 8(%[u_ptr]) \n\t"
- "mul.s %[tmp8f], %[tmp8f], %[noise4] \n\t"
- "mul.s %[tmp7f], %[tmp7f], %[noise4] \n\t"
- "neg.s %[tmp2f] \n\t"
- "neg.s %[tmp4f] \n\t"
- "neg.s %[tmp6f] \n\t"
- "neg.s %[tmp8f] \n\t"
- "swc1 %[tmp5f], 16(%[u_ptr]) \n\t"
- "swc1 %[tmp7f], 24(%[u_ptr]) \n\t"
- "swc1 %[tmp2f], 4(%[u_ptr]) \n\t"
- "swc1 %[tmp4f], 12(%[u_ptr]) \n\t"
- "swc1 %[tmp6f], 20(%[u_ptr]) \n\t"
- "swc1 %[tmp8f], 28(%[u_ptr]) \n\t"
- "addiu %[u_ptr], %[u_ptr], 32 \n\t"
- ".set pop \n\t"
- : [u_ptr] "+r" (u_ptr), [noisePow] "+r" (noisePow),
- [noise] "=&f" (noise), [noise2] "=&f" (noise2),
- [noise3] "=&f" (noise3), [noise4] "=&f" (noise4),
- [tmp1f] "=&f" (tmp1f), [tmp2f] "=&f" (tmp2f),
- [tmp3f] "=&f" (tmp3f), [tmp4f] "=&f" (tmp4f),
- [tmp5f] "=&f" (tmp5f), [tmp6f] "=&f" (tmp6f),
- [tmp7f] "=&f" (tmp7f), [tmp8f] "=&f" (tmp8f)
- :
- : "memory"
- );
- }
- u[PART_LEN][1] = 0;
- noisePow -= PART_LEN;
-
- u_ptr = &u[0][0];
- float* u_ptr_end = &u[PART_LEN][0];
- float* efw_ptr_0 = &efw[0][0];
- float* efw_ptr_1 = &efw[1][0];
- float tmp9f, tmp10f;
- const float tmp1c = 1.0;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "1: \n\t"
- "lwc1 %[tmp1f], 0(%[lambda]) \n\t"
- "lwc1 %[tmp6f], 4(%[lambda]) \n\t"
- "addiu %[lambda], %[lambda], 8 \n\t"
- "c.lt.s %[tmp1f], %[tmp1c] \n\t"
- "bc1f 4f \n\t"
- " nop \n\t"
- "c.lt.s %[tmp6f], %[tmp1c] \n\t"
- "bc1f 3f \n\t"
- " nop \n\t"
- "2: \n\t"
- "mul.s %[tmp1f], %[tmp1f], %[tmp1f] \n\t"
- "mul.s %[tmp6f], %[tmp6f], %[tmp6f] \n\t"
- "sub.s %[tmp1f], %[tmp1c], %[tmp1f] \n\t"
- "sub.s %[tmp6f], %[tmp1c], %[tmp6f] \n\t"
- "sqrt.s %[tmp1f], %[tmp1f] \n\t"
- "sqrt.s %[tmp6f], %[tmp6f] \n\t"
- "lwc1 %[tmp2f], 0(%[efw_ptr_0]) \n\t"
- "lwc1 %[tmp3f], 0(%[u_ptr]) \n\t"
- "lwc1 %[tmp7f], 4(%[efw_ptr_0]) \n\t"
- "lwc1 %[tmp8f], 8(%[u_ptr]) \n\t"
- "lwc1 %[tmp4f], 0(%[efw_ptr_1]) \n\t"
- "lwc1 %[tmp5f], 4(%[u_ptr]) \n\t"
- "lwc1 %[tmp9f], 4(%[efw_ptr_1]) \n\t"
- "lwc1 %[tmp10f], 12(%[u_ptr]) \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[tmp3f], %[tmp1f], %[tmp3f] \n\t"
- "add.s %[tmp2f], %[tmp2f], %[tmp3f] \n\t"
- "mul.s %[tmp3f], %[tmp1f], %[tmp5f] \n\t"
- "add.s %[tmp4f], %[tmp4f], %[tmp3f] \n\t"
- "mul.s %[tmp3f], %[tmp6f], %[tmp8f] \n\t"
- "add.s %[tmp7f], %[tmp7f], %[tmp3f] \n\t"
- "mul.s %[tmp3f], %[tmp6f], %[tmp10f] \n\t"
- "add.s %[tmp9f], %[tmp9f], %[tmp3f] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "madd.s %[tmp2f], %[tmp2f], %[tmp1f], %[tmp3f] \n\t"
- "madd.s %[tmp4f], %[tmp4f], %[tmp1f], %[tmp5f] \n\t"
- "madd.s %[tmp7f], %[tmp7f], %[tmp6f], %[tmp8f] \n\t"
- "madd.s %[tmp9f], %[tmp9f], %[tmp6f], %[tmp10f] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[tmp2f], 0(%[efw_ptr_0]) \n\t"
- "swc1 %[tmp4f], 0(%[efw_ptr_1]) \n\t"
- "swc1 %[tmp7f], 4(%[efw_ptr_0]) \n\t"
- "b 5f \n\t"
- " swc1 %[tmp9f], 4(%[efw_ptr_1]) \n\t"
- "3: \n\t"
- "mul.s %[tmp1f], %[tmp1f], %[tmp1f] \n\t"
- "sub.s %[tmp1f], %[tmp1c], %[tmp1f] \n\t"
- "sqrt.s %[tmp1f], %[tmp1f] \n\t"
- "lwc1 %[tmp2f], 0(%[efw_ptr_0]) \n\t"
- "lwc1 %[tmp3f], 0(%[u_ptr]) \n\t"
- "lwc1 %[tmp4f], 0(%[efw_ptr_1]) \n\t"
- "lwc1 %[tmp5f], 4(%[u_ptr]) \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[tmp3f], %[tmp1f], %[tmp3f] \n\t"
- "add.s %[tmp2f], %[tmp2f], %[tmp3f] \n\t"
- "mul.s %[tmp3f], %[tmp1f], %[tmp5f] \n\t"
- "add.s %[tmp4f], %[tmp4f], %[tmp3f] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "madd.s %[tmp2f], %[tmp2f], %[tmp1f], %[tmp3f] \n\t"
- "madd.s %[tmp4f], %[tmp4f], %[tmp1f], %[tmp5f] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[tmp2f], 0(%[efw_ptr_0]) \n\t"
- "b 5f \n\t"
- " swc1 %[tmp4f], 0(%[efw_ptr_1]) \n\t"
- "4: \n\t"
- "c.lt.s %[tmp6f], %[tmp1c] \n\t"
- "bc1f 5f \n\t"
- " nop \n\t"
- "mul.s %[tmp6f], %[tmp6f], %[tmp6f] \n\t"
- "sub.s %[tmp6f], %[tmp1c], %[tmp6f] \n\t"
- "sqrt.s %[tmp6f], %[tmp6f] \n\t"
- "lwc1 %[tmp7f], 4(%[efw_ptr_0]) \n\t"
- "lwc1 %[tmp8f], 8(%[u_ptr]) \n\t"
- "lwc1 %[tmp9f], 4(%[efw_ptr_1]) \n\t"
- "lwc1 %[tmp10f], 12(%[u_ptr]) \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[tmp3f], %[tmp6f], %[tmp8f] \n\t"
- "add.s %[tmp7f], %[tmp7f], %[tmp3f] \n\t"
- "mul.s %[tmp3f], %[tmp6f], %[tmp10f] \n\t"
- "add.s %[tmp9f], %[tmp9f], %[tmp3f] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "madd.s %[tmp7f], %[tmp7f], %[tmp6f], %[tmp8f] \n\t"
- "madd.s %[tmp9f], %[tmp9f], %[tmp6f], %[tmp10f] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[tmp7f], 4(%[efw_ptr_0]) \n\t"
- "swc1 %[tmp9f], 4(%[efw_ptr_1]) \n\t"
- "5: \n\t"
- "addiu %[u_ptr], %[u_ptr], 16 \n\t"
- "addiu %[efw_ptr_0], %[efw_ptr_0], 8 \n\t"
- "bne %[u_ptr], %[u_ptr_end], 1b \n\t"
- " addiu %[efw_ptr_1], %[efw_ptr_1], 8 \n\t"
- ".set pop \n\t"
- : [lambda] "+r" (lambda), [u_ptr] "+r" (u_ptr),
- [efw_ptr_0] "+r" (efw_ptr_0), [efw_ptr_1] "+r" (efw_ptr_1),
- [tmp1f] "=&f" (tmp1f), [tmp2f] "=&f" (tmp2f), [tmp3f] "=&f" (tmp3f),
- [tmp4f] "=&f" (tmp4f), [tmp5f] "=&f" (tmp5f),
- [tmp6f] "=&f" (tmp6f), [tmp7f] "=&f" (tmp7f), [tmp8f] "=&f" (tmp8f),
- [tmp9f] "=&f" (tmp9f), [tmp10f] "=&f" (tmp10f)
- : [tmp1c] "f" (tmp1c), [u_ptr_end] "r" (u_ptr_end)
- : "memory"
- );
-
- lambda -= PART_LEN;
- tmp = sqrtf(WEBRTC_SPL_MAX(1 - lambda[PART_LEN] * lambda[PART_LEN], 0));
- //tmp = 1 - lambda[i];
- efw[0][PART_LEN] += tmp * u[PART_LEN][0];
- efw[1][PART_LEN] += tmp * u[PART_LEN][1];
-
- // For H band comfort noise
- // TODO: don't compute noise and "tmp" twice. Use the previous results.
- noiseAvg = 0.0;
- tmpAvg = 0.0;
- num = 0;
- if ((aec->sampFreq == 32000 || aec->sampFreq == 48000) && flagHbandCn == 1) {
- for (i = 0; i < PART_LEN; i++) {
- rand[i] = ((float)randW16[i]) / 32768;
- }
-
- // average noise scale
- // average over second half of freq spectrum (i.e., 4->8khz)
- // TODO: we shouldn't need num. We know how many elements we're summing.
- for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) {
- num++;
- noiseAvg += sqrtf(noisePow[i]);
- }
- noiseAvg /= (float)num;
-
- // average nlp scale
- // average over second half of freq spectrum (i.e., 4->8khz)
- // TODO: we shouldn't need num. We know how many elements we're summing.
- num = 0;
- for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) {
- num++;
- tmpAvg += sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0));
- }
- tmpAvg /= (float)num;
-
- // Use average noise for H band
- // TODO: we should probably have a new random vector here.
- // Reject LF noise
- u[0][0] = 0;
- u[0][1] = 0;
- for (i = 1; i < PART_LEN1; i++) {
- tmp = pi2 * rand[i - 1];
-
- // Use average noise for H band
- u[i][0] = noiseAvg * (float)cos(tmp);
- u[i][1] = -noiseAvg * (float)sin(tmp);
- }
- u[PART_LEN][1] = 0;
-
- for (i = 0; i < PART_LEN1; i++) {
- // Use average NLP weight for H band
- comfortNoiseHband[i][0] = tmpAvg * u[i][0];
- comfortNoiseHband[i][1] = tmpAvg * u[i][1];
- }
- }
-}
-
-void WebRtcAec_FilterFar_mips(AecCore* aec, float yf[2][PART_LEN1]) {
- int i;
- for (i = 0; i < aec->num_partitions; i++) {
- int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + aec->xfBufBlockPos >= aec->num_partitions) {
- xPos -= aec->num_partitions * (PART_LEN1);
- }
- float* yf0 = yf[0];
- float* yf1 = yf[1];
- float* aRe = aec->xfBuf[0] + xPos;
- float* aIm = aec->xfBuf[1] + xPos;
- float* bRe = aec->wfBuf[0] + pos;
- float* bIm = aec->wfBuf[1] + pos;
- float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13;
- int len = PART_LEN1 >> 1;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "1: \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[bRe]) \n\t"
- "lwc1 %[f2], 0(%[bIm]) \n\t"
- "lwc1 %[f3], 0(%[aIm]) \n\t"
- "lwc1 %[f4], 4(%[aRe]) \n\t"
- "lwc1 %[f5], 4(%[bRe]) \n\t"
- "lwc1 %[f6], 4(%[bIm]) \n\t"
- "mul.s %[f8], %[f0], %[f1] \n\t"
- "mul.s %[f0], %[f0], %[f2] \n\t"
- "mul.s %[f9], %[f4], %[f5] \n\t"
- "mul.s %[f4], %[f4], %[f6] \n\t"
- "lwc1 %[f7], 4(%[aIm]) \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f12], %[f2], %[f3] \n\t"
- "mul.s %[f1], %[f3], %[f1] \n\t"
- "mul.s %[f11], %[f6], %[f7] \n\t"
- "addiu %[aRe], %[aRe], 8 \n\t"
- "addiu %[aIm], %[aIm], 8 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "sub.s %[f8], %[f8], %[f12] \n\t"
- "mul.s %[f12], %[f7], %[f5] \n\t"
- "lwc1 %[f2], 0(%[yf0]) \n\t"
- "add.s %[f1], %[f0], %[f1] \n\t"
- "lwc1 %[f3], 0(%[yf1]) \n\t"
- "sub.s %[f9], %[f9], %[f11] \n\t"
- "lwc1 %[f6], 4(%[yf0]) \n\t"
- "add.s %[f4], %[f4], %[f12] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "addiu %[aRe], %[aRe], 8 \n\t"
- "addiu %[aIm], %[aIm], 8 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "nmsub.s %[f8], %[f8], %[f2], %[f3] \n\t"
- "lwc1 %[f2], 0(%[yf0]) \n\t"
- "madd.s %[f1], %[f0], %[f3], %[f1] \n\t"
- "lwc1 %[f3], 0(%[yf1]) \n\t"
- "nmsub.s %[f9], %[f9], %[f6], %[f7] \n\t"
- "lwc1 %[f6], 4(%[yf0]) \n\t"
- "madd.s %[f4], %[f4], %[f7], %[f5] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "lwc1 %[f5], 4(%[yf1]) \n\t"
- "add.s %[f2], %[f2], %[f8] \n\t"
- "addiu %[bRe], %[bRe], 8 \n\t"
- "addiu %[bIm], %[bIm], 8 \n\t"
- "add.s %[f3], %[f3], %[f1] \n\t"
- "add.s %[f6], %[f6], %[f9] \n\t"
- "add.s %[f5], %[f5], %[f4] \n\t"
- "swc1 %[f2], 0(%[yf0]) \n\t"
- "swc1 %[f3], 0(%[yf1]) \n\t"
- "swc1 %[f6], 4(%[yf0]) \n\t"
- "swc1 %[f5], 4(%[yf1]) \n\t"
- "addiu %[yf0], %[yf0], 8 \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[yf1], %[yf1], 8 \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[bRe]) \n\t"
- "lwc1 %[f2], 0(%[bIm]) \n\t"
- "lwc1 %[f3], 0(%[aIm]) \n\t"
- "mul.s %[f8], %[f0], %[f1] \n\t"
- "mul.s %[f0], %[f0], %[f2] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f12], %[f2], %[f3] \n\t"
- "mul.s %[f1], %[f3], %[f1] \n\t"
- "sub.s %[f8], %[f8], %[f12] \n\t"
- "lwc1 %[f2], 0(%[yf0]) \n\t"
- "add.s %[f1], %[f0], %[f1] \n\t"
- "lwc1 %[f3], 0(%[yf1]) \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "nmsub.s %[f8], %[f8], %[f2], %[f3] \n\t"
- "lwc1 %[f2], 0(%[yf0]) \n\t"
- "madd.s %[f1], %[f0], %[f3], %[f1] \n\t"
- "lwc1 %[f3], 0(%[yf1]) \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "add.s %[f2], %[f2], %[f8] \n\t"
- "add.s %[f3], %[f3], %[f1] \n\t"
- "swc1 %[f2], 0(%[yf0]) \n\t"
- "swc1 %[f3], 0(%[yf1]) \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
- [f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
- [f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
- [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11),
- [f12] "=&f" (f12), [f13] "=&f" (f13), [aRe] "+r" (aRe),
- [aIm] "+r" (aIm), [bRe] "+r" (bRe), [bIm] "+r" (bIm),
- [yf0] "+r" (yf0), [yf1] "+r" (yf1), [len] "+r" (len)
- :
- : "memory"
- );
- }
-}
-
-void WebRtcAec_FilterAdaptation_mips(AecCore* aec,
- float* fft,
- float ef[2][PART_LEN1]) {
- int i;
- for (i = 0; i < aec->num_partitions; i++) {
- int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1);
- int pos;
- // Check for wrap
- if (i + aec->xfBufBlockPos >= aec->num_partitions) {
- xPos -= aec->num_partitions * PART_LEN1;
- }
-
- pos = i * PART_LEN1;
- float* aRe = aec->xfBuf[0] + xPos;
- float* aIm = aec->xfBuf[1] + xPos;
- float* bRe = ef[0];
- float* bIm = ef[1];
- float* fft_tmp;
-
- float f0, f1, f2, f3, f4, f5, f6 ,f7, f8, f9, f10, f11, f12;
- int len = PART_LEN >> 1;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[fft_tmp], %[fft], 0 \n\t"
- "1: \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[bRe]) \n\t"
- "lwc1 %[f2], 0(%[bIm]) \n\t"
- "lwc1 %[f4], 4(%[aRe]) \n\t"
- "lwc1 %[f5], 4(%[bRe]) \n\t"
- "lwc1 %[f6], 4(%[bIm]) \n\t"
- "addiu %[aRe], %[aRe], 8 \n\t"
- "addiu %[bRe], %[bRe], 8 \n\t"
- "mul.s %[f8], %[f0], %[f1] \n\t"
- "mul.s %[f0], %[f0], %[f2] \n\t"
- "lwc1 %[f3], 0(%[aIm]) \n\t"
- "mul.s %[f9], %[f4], %[f5] \n\t"
- "lwc1 %[f7], 4(%[aIm]) \n\t"
- "mul.s %[f4], %[f4], %[f6] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f10], %[f3], %[f2] \n\t"
- "mul.s %[f1], %[f3], %[f1] \n\t"
- "mul.s %[f11], %[f7], %[f6] \n\t"
- "mul.s %[f5], %[f7], %[f5] \n\t"
- "addiu %[aIm], %[aIm], 8 \n\t"
- "addiu %[bIm], %[bIm], 8 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "add.s %[f8], %[f8], %[f10] \n\t"
- "sub.s %[f1], %[f0], %[f1] \n\t"
- "add.s %[f9], %[f9], %[f11] \n\t"
- "sub.s %[f5], %[f4], %[f5] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "addiu %[aIm], %[aIm], 8 \n\t"
- "addiu %[bIm], %[bIm], 8 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "madd.s %[f8], %[f8], %[f3], %[f2] \n\t"
- "nmsub.s %[f1], %[f0], %[f3], %[f1] \n\t"
- "madd.s %[f9], %[f9], %[f7], %[f6] \n\t"
- "nmsub.s %[f5], %[f4], %[f7], %[f5] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[f8], 0(%[fft_tmp]) \n\t"
- "swc1 %[f1], 4(%[fft_tmp]) \n\t"
- "swc1 %[f9], 8(%[fft_tmp]) \n\t"
- "swc1 %[f5], 12(%[fft_tmp]) \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[bRe]) \n\t"
- "lwc1 %[f2], 0(%[bIm]) \n\t"
- "lwc1 %[f3], 0(%[aIm]) \n\t"
- "mul.s %[f8], %[f0], %[f1] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f10], %[f3], %[f2] \n\t"
- "add.s %[f8], %[f8], %[f10] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "madd.s %[f8], %[f8], %[f3], %[f2] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[f8], 4(%[fft]) \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
- [f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
- [f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
- [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11),
- [f12] "=&f" (f12), [aRe] "+r" (aRe), [aIm] "+r" (aIm),
- [bRe] "+r" (bRe), [bIm] "+r" (bIm), [fft_tmp] "=&r" (fft_tmp),
- [len] "+r" (len)
- : [fft] "r" (fft)
- : "memory"
- );
-
- aec_rdft_inverse_128(fft);
- memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
-
- // fft scaling
- {
- float scale = 2.0f / PART_LEN2;
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[fft_tmp], %[fft], 0 \n\t"
- "addiu %[len], $zero, 8 \n\t"
- "1: \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "lwc1 %[f0], 0(%[fft_tmp]) \n\t"
- "lwc1 %[f1], 4(%[fft_tmp]) \n\t"
- "lwc1 %[f2], 8(%[fft_tmp]) \n\t"
- "lwc1 %[f3], 12(%[fft_tmp]) \n\t"
- "mul.s %[f0], %[f0], %[scale] \n\t"
- "mul.s %[f1], %[f1], %[scale] \n\t"
- "mul.s %[f2], %[f2], %[scale] \n\t"
- "mul.s %[f3], %[f3], %[scale] \n\t"
- "lwc1 %[f4], 16(%[fft_tmp]) \n\t"
- "lwc1 %[f5], 20(%[fft_tmp]) \n\t"
- "lwc1 %[f6], 24(%[fft_tmp]) \n\t"
- "lwc1 %[f7], 28(%[fft_tmp]) \n\t"
- "mul.s %[f4], %[f4], %[scale] \n\t"
- "mul.s %[f5], %[f5], %[scale] \n\t"
- "mul.s %[f6], %[f6], %[scale] \n\t"
- "mul.s %[f7], %[f7], %[scale] \n\t"
- "swc1 %[f0], 0(%[fft_tmp]) \n\t"
- "swc1 %[f1], 4(%[fft_tmp]) \n\t"
- "swc1 %[f2], 8(%[fft_tmp]) \n\t"
- "swc1 %[f3], 12(%[fft_tmp]) \n\t"
- "swc1 %[f4], 16(%[fft_tmp]) \n\t"
- "swc1 %[f5], 20(%[fft_tmp]) \n\t"
- "swc1 %[f6], 24(%[fft_tmp]) \n\t"
- "swc1 %[f7], 28(%[fft_tmp]) \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[fft_tmp], %[fft_tmp], 32 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
- [f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
- [f6] "=&f" (f6), [f7] "=&f" (f7), [len] "=&r" (len),
- [fft_tmp] "=&r" (fft_tmp)
- : [scale] "f" (scale), [fft] "r" (fft)
- : "memory"
- );
- }
- aec_rdft_forward_128(fft);
- aRe = aec->wfBuf[0] + pos;
- aIm = aec->wfBuf[1] + pos;
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[fft_tmp], %[fft], 0 \n\t"
- "addiu %[len], $zero, 31 \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[fft_tmp]) \n\t"
- "lwc1 %[f2], 256(%[aRe]) \n\t"
- "lwc1 %[f3], 4(%[fft_tmp]) \n\t"
- "lwc1 %[f4], 4(%[aRe]) \n\t"
- "lwc1 %[f5], 8(%[fft_tmp]) \n\t"
- "lwc1 %[f6], 4(%[aIm]) \n\t"
- "lwc1 %[f7], 12(%[fft_tmp]) \n\t"
- "add.s %[f0], %[f0], %[f1] \n\t"
- "add.s %[f2], %[f2], %[f3] \n\t"
- "add.s %[f4], %[f4], %[f5] \n\t"
- "add.s %[f6], %[f6], %[f7] \n\t"
- "addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
- "swc1 %[f0], 0(%[aRe]) \n\t"
- "swc1 %[f2], 256(%[aRe]) \n\t"
- "swc1 %[f4], 4(%[aRe]) \n\t"
- "addiu %[aRe], %[aRe], 8 \n\t"
- "swc1 %[f6], 4(%[aIm]) \n\t"
- "addiu %[aIm], %[aIm], 8 \n\t"
- "1: \n\t"
- "lwc1 %[f0], 0(%[aRe]) \n\t"
- "lwc1 %[f1], 0(%[fft_tmp]) \n\t"
- "lwc1 %[f2], 0(%[aIm]) \n\t"
- "lwc1 %[f3], 4(%[fft_tmp]) \n\t"
- "lwc1 %[f4], 4(%[aRe]) \n\t"
- "lwc1 %[f5], 8(%[fft_tmp]) \n\t"
- "lwc1 %[f6], 4(%[aIm]) \n\t"
- "lwc1 %[f7], 12(%[fft_tmp]) \n\t"
- "add.s %[f0], %[f0], %[f1] \n\t"
- "add.s %[f2], %[f2], %[f3] \n\t"
- "add.s %[f4], %[f4], %[f5] \n\t"
- "add.s %[f6], %[f6], %[f7] \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
- "swc1 %[f0], 0(%[aRe]) \n\t"
- "swc1 %[f2], 0(%[aIm]) \n\t"
- "swc1 %[f4], 4(%[aRe]) \n\t"
- "addiu %[aRe], %[aRe], 8 \n\t"
- "swc1 %[f6], 4(%[aIm]) \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[aIm], %[aIm], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
- [f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
- [f6] "=&f" (f6), [f7] "=&f" (f7), [len] "=&r" (len),
- [fft_tmp] "=&r" (fft_tmp), [aRe] "+r" (aRe), [aIm] "+r" (aIm)
- : [fft] "r" (fft)
- : "memory"
- );
- }
-}
-
-void WebRtcAec_OverdriveAndSuppress_mips(AecCore* aec,
- float hNl[PART_LEN1],
- const float hNlFb,
- float efw[2][PART_LEN1]) {
- int i;
- const float one = 1.0;
- float* p_hNl;
- float* p_efw0;
- float* p_efw1;
- float* p_WebRtcAec_wC;
- float temp1, temp2, temp3, temp4;
-
- p_hNl = &hNl[0];
- p_efw0 = &efw[0][0];
- p_efw1 = &efw[1][0];
- p_WebRtcAec_wC = (float*)&WebRtcAec_weightCurve[0];
-
- for (i = 0; i < PART_LEN1; i++) {
- // Weight subbands
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "lwc1 %[temp1], 0(%[p_hNl]) \n\t"
- "lwc1 %[temp2], 0(%[p_wC]) \n\t"
- "c.lt.s %[hNlFb], %[temp1] \n\t"
- "bc1f 1f \n\t"
- " mul.s %[temp3], %[temp2], %[hNlFb] \n\t"
- "sub.s %[temp4], %[one], %[temp2] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[temp1], %[temp1], %[temp4] \n\t"
- "add.s %[temp1], %[temp3], %[temp1] \n\t"
-#else // #if !defined(MIPS32_R2_LE)
- "madd.s %[temp1], %[temp3], %[temp1], %[temp4] \n\t"
-#endif // #if !defined(MIPS32_R2_LE)
- "swc1 %[temp1], 0(%[p_hNl]) \n\t"
- "1: \n\t"
- "addiu %[p_wC], %[p_wC], 4 \n\t"
- ".set pop \n\t"
- : [temp1] "=&f" (temp1), [temp2] "=&f" (temp2), [temp3] "=&f" (temp3),
- [temp4] "=&f" (temp4), [p_wC] "+r" (p_WebRtcAec_wC)
- : [hNlFb] "f" (hNlFb), [one] "f" (one), [p_hNl] "r" (p_hNl)
- : "memory"
- );
-
- hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
-
- __asm __volatile (
- "lwc1 %[temp1], 0(%[p_hNl]) \n\t"
- "lwc1 %[temp3], 0(%[p_efw1]) \n\t"
- "lwc1 %[temp2], 0(%[p_efw0]) \n\t"
- "addiu %[p_hNl], %[p_hNl], 4 \n\t"
- "mul.s %[temp3], %[temp3], %[temp1] \n\t"
- "mul.s %[temp2], %[temp2], %[temp1] \n\t"
- "addiu %[p_efw0], %[p_efw0], 4 \n\t"
- "addiu %[p_efw1], %[p_efw1], 4 \n\t"
- "neg.s %[temp4], %[temp3] \n\t"
- "swc1 %[temp2], -4(%[p_efw0]) \n\t"
- "swc1 %[temp4], -4(%[p_efw1]) \n\t"
- : [temp1] "=&f" (temp1), [temp2] "=&f" (temp2), [temp3] "=&f" (temp3),
- [temp4] "=&f" (temp4), [p_efw0] "+r" (p_efw0), [p_efw1] "+r" (p_efw1),
- [p_hNl] "+r" (p_hNl)
- :
- : "memory"
- );
- }
-}
-
-void WebRtcAec_ScaleErrorSignal_mips(AecCore* aec, float ef[2][PART_LEN1]) {
- const float mu = aec->extended_filter_enabled ? kExtendedMu : aec->normal_mu;
- const float error_threshold = aec->extended_filter_enabled
- ? kExtendedErrorThreshold
- : aec->normal_error_threshold;
- int len = (PART_LEN1);
- float* ef0 = ef[0];
- float* ef1 = ef[1];
- float* xPow = aec->xPow;
- float fac1 = 1e-10f;
- float err_th2 = error_threshold * error_threshold;
- float f0, f1, f2;
-#if !defined(MIPS32_R2_LE)
- float f3;
-#endif
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "1: \n\t"
- "lwc1 %[f0], 0(%[xPow]) \n\t"
- "lwc1 %[f1], 0(%[ef0]) \n\t"
- "lwc1 %[f2], 0(%[ef1]) \n\t"
- "add.s %[f0], %[f0], %[fac1] \n\t"
- "div.s %[f1], %[f1], %[f0] \n\t"
- "div.s %[f2], %[f2], %[f0] \n\t"
- "mul.s %[f0], %[f1], %[f1] \n\t"
-#if defined(MIPS32_R2_LE)
- "madd.s %[f0], %[f0], %[f2], %[f2] \n\t"
-#else
- "mul.s %[f3], %[f2], %[f2] \n\t"
- "add.s %[f0], %[f0], %[f3] \n\t"
-#endif
- "c.le.s %[f0], %[err_th2] \n\t"
- "nop \n\t"
- "bc1t 2f \n\t"
- " nop \n\t"
- "sqrt.s %[f0], %[f0] \n\t"
- "add.s %[f0], %[f0], %[fac1] \n\t"
- "div.s %[f0], %[err_th], %[f0] \n\t"
- "mul.s %[f1], %[f1], %[f0] \n\t"
- "mul.s %[f2], %[f2], %[f0] \n\t"
- "2: \n\t"
- "mul.s %[f1], %[f1], %[mu] \n\t"
- "mul.s %[f2], %[f2], %[mu] \n\t"
- "swc1 %[f1], 0(%[ef0]) \n\t"
- "swc1 %[f2], 0(%[ef1]) \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "addiu %[xPow], %[xPow], 4 \n\t"
- "addiu %[ef0], %[ef0], 4 \n\t"
- "bgtz %[len], 1b \n\t"
- " addiu %[ef1], %[ef1], 4 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
-#if !defined(MIPS32_R2_LE)
- [f3] "=&f" (f3),
-#endif
- [xPow] "+r" (xPow), [ef0] "+r" (ef0), [ef1] "+r" (ef1),
- [len] "+r" (len)
- : [fac1] "f" (fac1), [err_th2] "f" (err_th2), [mu] "f" (mu),
- [err_th] "f" (error_threshold)
- : "memory"
- );
-}
-
-void WebRtcAec_InitAec_mips(void) {
- WebRtcAec_FilterFar = WebRtcAec_FilterFar_mips;
- WebRtcAec_FilterAdaptation = WebRtcAec_FilterAdaptation_mips;
- WebRtcAec_ScaleErrorSignal = WebRtcAec_ScaleErrorSignal_mips;
- WebRtcAec_ComfortNoise = WebRtcAec_ComfortNoise_mips;
- WebRtcAec_OverdriveAndSuppress = WebRtcAec_OverdriveAndSuppress_mips;
-}
-
diff --git a/webrtc/modules/audio_processing/aec/aec_core_neon.c b/webrtc/modules/audio_processing/aec/aec_core_neon.c
deleted file mode 100644
index 9a677aa..0000000
--- a/webrtc/modules/audio_processing/aec/aec_core_neon.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * The core AEC algorithm, neon version of speed-critical functions.
- *
- * Based on aec_core_sse2.c.
- */
-
-#include <arm_neon.h>
-#include <math.h>
-#include <string.h> // memset
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/aec/aec_common.h"
-#include "webrtc/modules/audio_processing/aec/aec_core_internal.h"
-#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
-
-enum { kShiftExponentIntoTopMantissa = 8 };
-enum { kFloatExponentShift = 23 };
-
-__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bRe - aIm * bIm;
-}
-
-__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bIm + aIm * bRe;
-}
-
-static void FilterFarNEON(AecCore* aec, float yf[2][PART_LEN1]) {
- int i;
- const int num_partitions = aec->num_partitions;
- for (i = 0; i < num_partitions; i++) {
- int j;
- int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + aec->xfBufBlockPos >= num_partitions) {
- xPos -= num_partitions * PART_LEN1;
- }
-
- // vectorized code (four at once)
- for (j = 0; j + 3 < PART_LEN1; j += 4) {
- const float32x4_t xfBuf_re = vld1q_f32(&aec->xfBuf[0][xPos + j]);
- const float32x4_t xfBuf_im = vld1q_f32(&aec->xfBuf[1][xPos + j]);
- const float32x4_t wfBuf_re = vld1q_f32(&aec->wfBuf[0][pos + j]);
- const float32x4_t wfBuf_im = vld1q_f32(&aec->wfBuf[1][pos + j]);
- const float32x4_t yf_re = vld1q_f32(&yf[0][j]);
- const float32x4_t yf_im = vld1q_f32(&yf[1][j]);
- const float32x4_t a = vmulq_f32(xfBuf_re, wfBuf_re);
- const float32x4_t e = vmlsq_f32(a, xfBuf_im, wfBuf_im);
- const float32x4_t c = vmulq_f32(xfBuf_re, wfBuf_im);
- const float32x4_t f = vmlaq_f32(c, xfBuf_im, wfBuf_re);
- const float32x4_t g = vaddq_f32(yf_re, e);
- const float32x4_t h = vaddq_f32(yf_im, f);
- vst1q_f32(&yf[0][j], g);
- vst1q_f32(&yf[1][j], h);
- }
- // scalar code for the remaining items.
- for (; j < PART_LEN1; j++) {
- yf[0][j] += MulRe(aec->xfBuf[0][xPos + j],
- aec->xfBuf[1][xPos + j],
- aec->wfBuf[0][pos + j],
- aec->wfBuf[1][pos + j]);
- yf[1][j] += MulIm(aec->xfBuf[0][xPos + j],
- aec->xfBuf[1][xPos + j],
- aec->wfBuf[0][pos + j],
- aec->wfBuf[1][pos + j]);
- }
- }
-}
-
-// ARM64's arm_neon.h has already defined vdivq_f32 vsqrtq_f32.
-#if !defined (WEBRTC_ARCH_ARM64)
-static float32x4_t vdivq_f32(float32x4_t a, float32x4_t b) {
- int i;
- float32x4_t x = vrecpeq_f32(b);
- // from arm documentation
- // The Newton-Raphson iteration:
- // x[n+1] = x[n] * (2 - d * x[n])
- // converges to (1/d) if x0 is the result of VRECPE applied to d.
- //
- // Note: The precision did not improve after 2 iterations.
- for (i = 0; i < 2; i++) {
- x = vmulq_f32(vrecpsq_f32(b, x), x);
- }
- // a/b = a*(1/b)
- return vmulq_f32(a, x);
-}
-
-static float32x4_t vsqrtq_f32(float32x4_t s) {
- int i;
- float32x4_t x = vrsqrteq_f32(s);
-
- // Code to handle sqrt(0).
- // If the input to sqrtf() is zero, a zero will be returned.
- // If the input to vrsqrteq_f32() is zero, positive infinity is returned.
- const uint32x4_t vec_p_inf = vdupq_n_u32(0x7F800000);
- // check for divide by zero
- const uint32x4_t div_by_zero = vceqq_u32(vec_p_inf, vreinterpretq_u32_f32(x));
- // zero out the positive infinity results
- x = vreinterpretq_f32_u32(vandq_u32(vmvnq_u32(div_by_zero),
- vreinterpretq_u32_f32(x)));
- // from arm documentation
- // The Newton-Raphson iteration:
- // x[n+1] = x[n] * (3 - d * (x[n] * x[n])) / 2)
- // converges to (1/√d) if x0 is the result of VRSQRTE applied to d.
- //
- // Note: The precision did not improve after 2 iterations.
- for (i = 0; i < 2; i++) {
- x = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x, x), s), x);
- }
- // sqrt(s) = s * 1/sqrt(s)
- return vmulq_f32(s, x);;
-}
-#endif // WEBRTC_ARCH_ARM64
-
-static void ScaleErrorSignalNEON(AecCore* aec, float ef[2][PART_LEN1]) {
- const float mu = aec->extended_filter_enabled ? kExtendedMu : aec->normal_mu;
- const float error_threshold = aec->extended_filter_enabled ?
- kExtendedErrorThreshold : aec->normal_error_threshold;
- const float32x4_t k1e_10f = vdupq_n_f32(1e-10f);
- const float32x4_t kMu = vmovq_n_f32(mu);
- const float32x4_t kThresh = vmovq_n_f32(error_threshold);
- int i;
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const float32x4_t xPow = vld1q_f32(&aec->xPow[i]);
- const float32x4_t ef_re_base = vld1q_f32(&ef[0][i]);
- const float32x4_t ef_im_base = vld1q_f32(&ef[1][i]);
- const float32x4_t xPowPlus = vaddq_f32(xPow, k1e_10f);
- float32x4_t ef_re = vdivq_f32(ef_re_base, xPowPlus);
- float32x4_t ef_im = vdivq_f32(ef_im_base, xPowPlus);
- const float32x4_t ef_re2 = vmulq_f32(ef_re, ef_re);
- const float32x4_t ef_sum2 = vmlaq_f32(ef_re2, ef_im, ef_im);
- const float32x4_t absEf = vsqrtq_f32(ef_sum2);
- const uint32x4_t bigger = vcgtq_f32(absEf, kThresh);
- const float32x4_t absEfPlus = vaddq_f32(absEf, k1e_10f);
- const float32x4_t absEfInv = vdivq_f32(kThresh, absEfPlus);
- uint32x4_t ef_re_if = vreinterpretq_u32_f32(vmulq_f32(ef_re, absEfInv));
- uint32x4_t ef_im_if = vreinterpretq_u32_f32(vmulq_f32(ef_im, absEfInv));
- uint32x4_t ef_re_u32 = vandq_u32(vmvnq_u32(bigger),
- vreinterpretq_u32_f32(ef_re));
- uint32x4_t ef_im_u32 = vandq_u32(vmvnq_u32(bigger),
- vreinterpretq_u32_f32(ef_im));
- ef_re_if = vandq_u32(bigger, ef_re_if);
- ef_im_if = vandq_u32(bigger, ef_im_if);
- ef_re_u32 = vorrq_u32(ef_re_u32, ef_re_if);
- ef_im_u32 = vorrq_u32(ef_im_u32, ef_im_if);
- ef_re = vmulq_f32(vreinterpretq_f32_u32(ef_re_u32), kMu);
- ef_im = vmulq_f32(vreinterpretq_f32_u32(ef_im_u32), kMu);
- vst1q_f32(&ef[0][i], ef_re);
- vst1q_f32(&ef[1][i], ef_im);
- }
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- float abs_ef;
- ef[0][i] /= (aec->xPow[i] + 1e-10f);
- ef[1][i] /= (aec->xPow[i] + 1e-10f);
- abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
-
- if (abs_ef > error_threshold) {
- abs_ef = error_threshold / (abs_ef + 1e-10f);
- ef[0][i] *= abs_ef;
- ef[1][i] *= abs_ef;
- }
-
- // Stepsize factor
- ef[0][i] *= mu;
- ef[1][i] *= mu;
- }
-}
-
-static void FilterAdaptationNEON(AecCore* aec,
- float* fft,
- float ef[2][PART_LEN1]) {
- int i;
- const int num_partitions = aec->num_partitions;
- for (i = 0; i < num_partitions; i++) {
- int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
- int pos = i * PART_LEN1;
- int j;
- // Check for wrap
- if (i + aec->xfBufBlockPos >= num_partitions) {
- xPos -= num_partitions * PART_LEN1;
- }
-
- // Process the whole array...
- for (j = 0; j < PART_LEN; j += 4) {
- // Load xfBuf and ef.
- const float32x4_t xfBuf_re = vld1q_f32(&aec->xfBuf[0][xPos + j]);
- const float32x4_t xfBuf_im = vld1q_f32(&aec->xfBuf[1][xPos + j]);
- const float32x4_t ef_re = vld1q_f32(&ef[0][j]);
- const float32x4_t ef_im = vld1q_f32(&ef[1][j]);
- // Calculate the product of conjugate(xfBuf) by ef.
- // re(conjugate(a) * b) = aRe * bRe + aIm * bIm
- // im(conjugate(a) * b)= aRe * bIm - aIm * bRe
- const float32x4_t a = vmulq_f32(xfBuf_re, ef_re);
- const float32x4_t e = vmlaq_f32(a, xfBuf_im, ef_im);
- const float32x4_t c = vmulq_f32(xfBuf_re, ef_im);
- const float32x4_t f = vmlsq_f32(c, xfBuf_im, ef_re);
- // Interleave real and imaginary parts.
- const float32x4x2_t g_n_h = vzipq_f32(e, f);
- // Store
- vst1q_f32(&fft[2 * j + 0], g_n_h.val[0]);
- vst1q_f32(&fft[2 * j + 4], g_n_h.val[1]);
- }
- // ... and fixup the first imaginary entry.
- fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN],
- -aec->xfBuf[1][xPos + PART_LEN],
- ef[0][PART_LEN],
- ef[1][PART_LEN]);
-
- aec_rdft_inverse_128(fft);
- memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
-
- // fft scaling
- {
- const float scale = 2.0f / PART_LEN2;
- const float32x4_t scale_ps = vmovq_n_f32(scale);
- for (j = 0; j < PART_LEN; j += 4) {
- const float32x4_t fft_ps = vld1q_f32(&fft[j]);
- const float32x4_t fft_scale = vmulq_f32(fft_ps, scale_ps);
- vst1q_f32(&fft[j], fft_scale);
- }
- }
- aec_rdft_forward_128(fft);
-
- {
- const float wt1 = aec->wfBuf[1][pos];
- aec->wfBuf[0][pos + PART_LEN] += fft[1];
- for (j = 0; j < PART_LEN; j += 4) {
- float32x4_t wtBuf_re = vld1q_f32(&aec->wfBuf[0][pos + j]);
- float32x4_t wtBuf_im = vld1q_f32(&aec->wfBuf[1][pos + j]);
- const float32x4_t fft0 = vld1q_f32(&fft[2 * j + 0]);
- const float32x4_t fft4 = vld1q_f32(&fft[2 * j + 4]);
- const float32x4x2_t fft_re_im = vuzpq_f32(fft0, fft4);
- wtBuf_re = vaddq_f32(wtBuf_re, fft_re_im.val[0]);
- wtBuf_im = vaddq_f32(wtBuf_im, fft_re_im.val[1]);
-
- vst1q_f32(&aec->wfBuf[0][pos + j], wtBuf_re);
- vst1q_f32(&aec->wfBuf[1][pos + j], wtBuf_im);
- }
- aec->wfBuf[1][pos] = wt1;
- }
- }
-}
-
-static float32x4_t vpowq_f32(float32x4_t a, float32x4_t b) {
- // a^b = exp2(b * log2(a))
- // exp2(x) and log2(x) are calculated using polynomial approximations.
- float32x4_t log2_a, b_log2_a, a_exp_b;
-
- // Calculate log2(x), x = a.
- {
- // To calculate log2(x), we decompose x like this:
- // x = y * 2^n
- // n is an integer
- // y is in the [1.0, 2.0) range
- //
- // log2(x) = log2(y) + n
- // n can be evaluated by playing with float representation.
- // log2(y) in a small range can be approximated, this code uses an order
- // five polynomial approximation. The coefficients have been
- // estimated with the Remez algorithm and the resulting
- // polynomial has a maximum relative error of 0.00086%.
-
- // Compute n.
- // This is done by masking the exponent, shifting it into the top bit of
- // the mantissa, putting eight into the biased exponent (to shift/
- // compensate the fact that the exponent has been shifted in the top/
- // fractional part and finally getting rid of the implicit leading one
- // from the mantissa by substracting it out.
- const uint32x4_t vec_float_exponent_mask = vdupq_n_u32(0x7F800000);
- const uint32x4_t vec_eight_biased_exponent = vdupq_n_u32(0x43800000);
- const uint32x4_t vec_implicit_leading_one = vdupq_n_u32(0x43BF8000);
- const uint32x4_t two_n = vandq_u32(vreinterpretq_u32_f32(a),
- vec_float_exponent_mask);
- const uint32x4_t n_1 = vshrq_n_u32(two_n, kShiftExponentIntoTopMantissa);
- const uint32x4_t n_0 = vorrq_u32(n_1, vec_eight_biased_exponent);
- const float32x4_t n =
- vsubq_f32(vreinterpretq_f32_u32(n_0),
- vreinterpretq_f32_u32(vec_implicit_leading_one));
- // Compute y.
- const uint32x4_t vec_mantissa_mask = vdupq_n_u32(0x007FFFFF);
- const uint32x4_t vec_zero_biased_exponent_is_one = vdupq_n_u32(0x3F800000);
- const uint32x4_t mantissa = vandq_u32(vreinterpretq_u32_f32(a),
- vec_mantissa_mask);
- const float32x4_t y =
- vreinterpretq_f32_u32(vorrq_u32(mantissa,
- vec_zero_biased_exponent_is_one));
- // Approximate log2(y) ~= (y - 1) * pol5(y).
- // pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0
- const float32x4_t C5 = vdupq_n_f32(-3.4436006e-2f);
- const float32x4_t C4 = vdupq_n_f32(3.1821337e-1f);
- const float32x4_t C3 = vdupq_n_f32(-1.2315303f);
- const float32x4_t C2 = vdupq_n_f32(2.5988452f);
- const float32x4_t C1 = vdupq_n_f32(-3.3241990f);
- const float32x4_t C0 = vdupq_n_f32(3.1157899f);
- float32x4_t pol5_y = C5;
- pol5_y = vmlaq_f32(C4, y, pol5_y);
- pol5_y = vmlaq_f32(C3, y, pol5_y);
- pol5_y = vmlaq_f32(C2, y, pol5_y);
- pol5_y = vmlaq_f32(C1, y, pol5_y);
- pol5_y = vmlaq_f32(C0, y, pol5_y);
- const float32x4_t y_minus_one =
- vsubq_f32(y, vreinterpretq_f32_u32(vec_zero_biased_exponent_is_one));
- const float32x4_t log2_y = vmulq_f32(y_minus_one, pol5_y);
-
- // Combine parts.
- log2_a = vaddq_f32(n, log2_y);
- }
-
- // b * log2(a)
- b_log2_a = vmulq_f32(b, log2_a);
-
- // Calculate exp2(x), x = b * log2(a).
- {
- // To calculate 2^x, we decompose x like this:
- // x = n + y
- // n is an integer, the value of x - 0.5 rounded down, therefore
- // y is in the [0.5, 1.5) range
- //
- // 2^x = 2^n * 2^y
- // 2^n can be evaluated by playing with float representation.
- // 2^y in a small range can be approximated, this code uses an order two
- // polynomial approximation. The coefficients have been estimated
- // with the Remez algorithm and the resulting polynomial has a
- // maximum relative error of 0.17%.
- // To avoid over/underflow, we reduce the range of input to ]-127, 129].
- const float32x4_t max_input = vdupq_n_f32(129.f);
- const float32x4_t min_input = vdupq_n_f32(-126.99999f);
- const float32x4_t x_min = vminq_f32(b_log2_a, max_input);
- const float32x4_t x_max = vmaxq_f32(x_min, min_input);
- // Compute n.
- const float32x4_t half = vdupq_n_f32(0.5f);
- const float32x4_t x_minus_half = vsubq_f32(x_max, half);
- const int32x4_t x_minus_half_floor = vcvtq_s32_f32(x_minus_half);
-
- // Compute 2^n.
- const int32x4_t float_exponent_bias = vdupq_n_s32(127);
- const int32x4_t two_n_exponent =
- vaddq_s32(x_minus_half_floor, float_exponent_bias);
- const float32x4_t two_n =
- vreinterpretq_f32_s32(vshlq_n_s32(two_n_exponent, kFloatExponentShift));
- // Compute y.
- const float32x4_t y = vsubq_f32(x_max, vcvtq_f32_s32(x_minus_half_floor));
-
- // Approximate 2^y ~= C2 * y^2 + C1 * y + C0.
- const float32x4_t C2 = vdupq_n_f32(3.3718944e-1f);
- const float32x4_t C1 = vdupq_n_f32(6.5763628e-1f);
- const float32x4_t C0 = vdupq_n_f32(1.0017247f);
- float32x4_t exp2_y = C2;
- exp2_y = vmlaq_f32(C1, y, exp2_y);
- exp2_y = vmlaq_f32(C0, y, exp2_y);
-
- // Combine parts.
- a_exp_b = vmulq_f32(exp2_y, two_n);
- }
-
- return a_exp_b;
-}
-
-static void OverdriveAndSuppressNEON(AecCore* aec,
- float hNl[PART_LEN1],
- const float hNlFb,
- float efw[2][PART_LEN1]) {
- int i;
- const float32x4_t vec_hNlFb = vmovq_n_f32(hNlFb);
- const float32x4_t vec_one = vdupq_n_f32(1.0f);
- const float32x4_t vec_minus_one = vdupq_n_f32(-1.0f);
- const float32x4_t vec_overDriveSm = vmovq_n_f32(aec->overDriveSm);
-
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- // Weight subbands
- float32x4_t vec_hNl = vld1q_f32(&hNl[i]);
- const float32x4_t vec_weightCurve = vld1q_f32(&WebRtcAec_weightCurve[i]);
- const uint32x4_t bigger = vcgtq_f32(vec_hNl, vec_hNlFb);
- const float32x4_t vec_weightCurve_hNlFb = vmulq_f32(vec_weightCurve,
- vec_hNlFb);
- const float32x4_t vec_one_weightCurve = vsubq_f32(vec_one, vec_weightCurve);
- const float32x4_t vec_one_weightCurve_hNl = vmulq_f32(vec_one_weightCurve,
- vec_hNl);
- const uint32x4_t vec_if0 = vandq_u32(vmvnq_u32(bigger),
- vreinterpretq_u32_f32(vec_hNl));
- const float32x4_t vec_one_weightCurve_add =
- vaddq_f32(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl);
- const uint32x4_t vec_if1 =
- vandq_u32(bigger, vreinterpretq_u32_f32(vec_one_weightCurve_add));
-
- vec_hNl = vreinterpretq_f32_u32(vorrq_u32(vec_if0, vec_if1));
-
- {
- const float32x4_t vec_overDriveCurve =
- vld1q_f32(&WebRtcAec_overDriveCurve[i]);
- const float32x4_t vec_overDriveSm_overDriveCurve =
- vmulq_f32(vec_overDriveSm, vec_overDriveCurve);
- vec_hNl = vpowq_f32(vec_hNl, vec_overDriveSm_overDriveCurve);
- vst1q_f32(&hNl[i], vec_hNl);
- }
-
- // Suppress error signal
- {
- float32x4_t vec_efw_re = vld1q_f32(&efw[0][i]);
- float32x4_t vec_efw_im = vld1q_f32(&efw[1][i]);
- vec_efw_re = vmulq_f32(vec_efw_re, vec_hNl);
- vec_efw_im = vmulq_f32(vec_efw_im, vec_hNl);
-
- // Ooura fft returns incorrect sign on imaginary component. It matters
- // here because we are making an additive change with comfort noise.
- vec_efw_im = vmulq_f32(vec_efw_im, vec_minus_one);
- vst1q_f32(&efw[0][i], vec_efw_re);
- vst1q_f32(&efw[1][i], vec_efw_im);
- }
- }
-
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- // Weight subbands
- if (hNl[i] > hNlFb) {
- hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
- (1 - WebRtcAec_weightCurve[i]) * hNl[i];
- }
-
- hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
-
- // Suppress error signal
- efw[0][i] *= hNl[i];
- efw[1][i] *= hNl[i];
-
- // Ooura fft returns incorrect sign on imaginary component. It matters
- // here because we are making an additive change with comfort noise.
- efw[1][i] *= -1;
- }
-}
-
-static int PartitionDelay(const AecCore* aec) {
- // Measures the energy in each filter partition and returns the partition with
- // highest energy.
- // TODO(bjornv): Spread computational cost by computing one partition per
- // block?
- float wfEnMax = 0;
- int i;
- int delay = 0;
-
- for (i = 0; i < aec->num_partitions; i++) {
- int j;
- int pos = i * PART_LEN1;
- float wfEn = 0;
- float32x4_t vec_wfEn = vdupq_n_f32(0.0f);
- // vectorized code (four at once)
- for (j = 0; j + 3 < PART_LEN1; j += 4) {
- const float32x4_t vec_wfBuf0 = vld1q_f32(&aec->wfBuf[0][pos + j]);
- const float32x4_t vec_wfBuf1 = vld1q_f32(&aec->wfBuf[1][pos + j]);
- vec_wfEn = vmlaq_f32(vec_wfEn, vec_wfBuf0, vec_wfBuf0);
- vec_wfEn = vmlaq_f32(vec_wfEn, vec_wfBuf1, vec_wfBuf1);
- }
- {
- float32x2_t vec_total;
- // A B C D
- vec_total = vpadd_f32(vget_low_f32(vec_wfEn), vget_high_f32(vec_wfEn));
- // A+B C+D
- vec_total = vpadd_f32(vec_total, vec_total);
- // A+B+C+D A+B+C+D
- wfEn = vget_lane_f32(vec_total, 0);
- }
-
- // scalar code for the remaining items.
- for (; j < PART_LEN1; j++) {
- wfEn += aec->wfBuf[0][pos + j] * aec->wfBuf[0][pos + j] +
- aec->wfBuf[1][pos + j] * aec->wfBuf[1][pos + j];
- }
-
- if (wfEn > wfEnMax) {
- wfEnMax = wfEn;
- delay = i;
- }
- }
- return delay;
-}
-
-// Updates the following smoothed Power Spectral Densities (PSD):
-// - sd : near-end
-// - se : residual echo
-// - sx : far-end
-// - sde : cross-PSD of near-end and residual echo
-// - sxd : cross-PSD of near-end and far-end
-//
-// In addition to updating the PSDs, also the filter diverge state is determined
-// upon actions are taken.
-static void SmoothedPSD(AecCore* aec,
- float efw[2][PART_LEN1],
- float dfw[2][PART_LEN1],
- float xfw[2][PART_LEN1]) {
- // Power estimate smoothing coefficients.
- const float* ptrGCoh = aec->extended_filter_enabled
- ? WebRtcAec_kExtendedSmoothingCoefficients[aec->mult - 1]
- : WebRtcAec_kNormalSmoothingCoefficients[aec->mult - 1];
- int i;
- float sdSum = 0, seSum = 0;
- const float32x4_t vec_15 = vdupq_n_f32(WebRtcAec_kMinFarendPSD);
- float32x4_t vec_sdSum = vdupq_n_f32(0.0f);
- float32x4_t vec_seSum = vdupq_n_f32(0.0f);
-
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const float32x4_t vec_dfw0 = vld1q_f32(&dfw[0][i]);
- const float32x4_t vec_dfw1 = vld1q_f32(&dfw[1][i]);
- const float32x4_t vec_efw0 = vld1q_f32(&efw[0][i]);
- const float32x4_t vec_efw1 = vld1q_f32(&efw[1][i]);
- const float32x4_t vec_xfw0 = vld1q_f32(&xfw[0][i]);
- const float32x4_t vec_xfw1 = vld1q_f32(&xfw[1][i]);
- float32x4_t vec_sd = vmulq_n_f32(vld1q_f32(&aec->sd[i]), ptrGCoh[0]);
- float32x4_t vec_se = vmulq_n_f32(vld1q_f32(&aec->se[i]), ptrGCoh[0]);
- float32x4_t vec_sx = vmulq_n_f32(vld1q_f32(&aec->sx[i]), ptrGCoh[0]);
- float32x4_t vec_dfw_sumsq = vmulq_f32(vec_dfw0, vec_dfw0);
- float32x4_t vec_efw_sumsq = vmulq_f32(vec_efw0, vec_efw0);
- float32x4_t vec_xfw_sumsq = vmulq_f32(vec_xfw0, vec_xfw0);
-
- vec_dfw_sumsq = vmlaq_f32(vec_dfw_sumsq, vec_dfw1, vec_dfw1);
- vec_efw_sumsq = vmlaq_f32(vec_efw_sumsq, vec_efw1, vec_efw1);
- vec_xfw_sumsq = vmlaq_f32(vec_xfw_sumsq, vec_xfw1, vec_xfw1);
- vec_xfw_sumsq = vmaxq_f32(vec_xfw_sumsq, vec_15);
- vec_sd = vmlaq_n_f32(vec_sd, vec_dfw_sumsq, ptrGCoh[1]);
- vec_se = vmlaq_n_f32(vec_se, vec_efw_sumsq, ptrGCoh[1]);
- vec_sx = vmlaq_n_f32(vec_sx, vec_xfw_sumsq, ptrGCoh[1]);
-
- vst1q_f32(&aec->sd[i], vec_sd);
- vst1q_f32(&aec->se[i], vec_se);
- vst1q_f32(&aec->sx[i], vec_sx);
-
- {
- float32x4x2_t vec_sde = vld2q_f32(&aec->sde[i][0]);
- float32x4_t vec_dfwefw0011 = vmulq_f32(vec_dfw0, vec_efw0);
- float32x4_t vec_dfwefw0110 = vmulq_f32(vec_dfw0, vec_efw1);
- vec_sde.val[0] = vmulq_n_f32(vec_sde.val[0], ptrGCoh[0]);
- vec_sde.val[1] = vmulq_n_f32(vec_sde.val[1], ptrGCoh[0]);
- vec_dfwefw0011 = vmlaq_f32(vec_dfwefw0011, vec_dfw1, vec_efw1);
- vec_dfwefw0110 = vmlsq_f32(vec_dfwefw0110, vec_dfw1, vec_efw0);
- vec_sde.val[0] = vmlaq_n_f32(vec_sde.val[0], vec_dfwefw0011, ptrGCoh[1]);
- vec_sde.val[1] = vmlaq_n_f32(vec_sde.val[1], vec_dfwefw0110, ptrGCoh[1]);
- vst2q_f32(&aec->sde[i][0], vec_sde);
- }
-
- {
- float32x4x2_t vec_sxd = vld2q_f32(&aec->sxd[i][0]);
- float32x4_t vec_dfwxfw0011 = vmulq_f32(vec_dfw0, vec_xfw0);
- float32x4_t vec_dfwxfw0110 = vmulq_f32(vec_dfw0, vec_xfw1);
- vec_sxd.val[0] = vmulq_n_f32(vec_sxd.val[0], ptrGCoh[0]);
- vec_sxd.val[1] = vmulq_n_f32(vec_sxd.val[1], ptrGCoh[0]);
- vec_dfwxfw0011 = vmlaq_f32(vec_dfwxfw0011, vec_dfw1, vec_xfw1);
- vec_dfwxfw0110 = vmlsq_f32(vec_dfwxfw0110, vec_dfw1, vec_xfw0);
- vec_sxd.val[0] = vmlaq_n_f32(vec_sxd.val[0], vec_dfwxfw0011, ptrGCoh[1]);
- vec_sxd.val[1] = vmlaq_n_f32(vec_sxd.val[1], vec_dfwxfw0110, ptrGCoh[1]);
- vst2q_f32(&aec->sxd[i][0], vec_sxd);
- }
-
- vec_sdSum = vaddq_f32(vec_sdSum, vec_sd);
- vec_seSum = vaddq_f32(vec_seSum, vec_se);
- }
- {
- float32x2_t vec_sdSum_total;
- float32x2_t vec_seSum_total;
- // A B C D
- vec_sdSum_total = vpadd_f32(vget_low_f32(vec_sdSum),
- vget_high_f32(vec_sdSum));
- vec_seSum_total = vpadd_f32(vget_low_f32(vec_seSum),
- vget_high_f32(vec_seSum));
- // A+B C+D
- vec_sdSum_total = vpadd_f32(vec_sdSum_total, vec_sdSum_total);
- vec_seSum_total = vpadd_f32(vec_seSum_total, vec_seSum_total);
- // A+B+C+D A+B+C+D
- sdSum = vget_lane_f32(vec_sdSum_total, 0);
- seSum = vget_lane_f32(vec_seSum_total, 0);
- }
-
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- aec->sd[i] = ptrGCoh[0] * aec->sd[i] +
- ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
- aec->se[i] = ptrGCoh[0] * aec->se[i] +
- ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
- // We threshold here to protect against the ill-effects of a zero farend.
- // The threshold is not arbitrarily chosen, but balances protection and
- // adverse interaction with the algorithm's tuning.
- // TODO(bjornv): investigate further why this is so sensitive.
- aec->sx[i] =
- ptrGCoh[0] * aec->sx[i] +
- ptrGCoh[1] * WEBRTC_SPL_MAX(
- xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
- WebRtcAec_kMinFarendPSD);
-
- aec->sde[i][0] =
- ptrGCoh[0] * aec->sde[i][0] +
- ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
- aec->sde[i][1] =
- ptrGCoh[0] * aec->sde[i][1] +
- ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
-
- aec->sxd[i][0] =
- ptrGCoh[0] * aec->sxd[i][0] +
- ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
- aec->sxd[i][1] =
- ptrGCoh[0] * aec->sxd[i][1] +
- ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
-
- sdSum += aec->sd[i];
- seSum += aec->se[i];
- }
-
- // Divergent filter safeguard.
- aec->divergeState = (aec->divergeState ? 1.05f : 1.0f) * seSum > sdSum;
-
- if (aec->divergeState)
- memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
-
- // Reset if error is significantly larger than nearend (13 dB).
- if (!aec->extended_filter_enabled && seSum > (19.95f * sdSum))
- memset(aec->wfBuf, 0, sizeof(aec->wfBuf));
-}
-
-// Window time domain data to be used by the fft.
-__inline static void WindowData(float* x_windowed, const float* x) {
- int i;
- for (i = 0; i < PART_LEN; i += 4) {
- const float32x4_t vec_Buf1 = vld1q_f32(&x[i]);
- const float32x4_t vec_Buf2 = vld1q_f32(&x[PART_LEN + i]);
- const float32x4_t vec_sqrtHanning = vld1q_f32(&WebRtcAec_sqrtHanning[i]);
- // A B C D
- float32x4_t vec_sqrtHanning_rev =
- vld1q_f32(&WebRtcAec_sqrtHanning[PART_LEN - i - 3]);
- // B A D C
- vec_sqrtHanning_rev = vrev64q_f32(vec_sqrtHanning_rev);
- // D C B A
- vec_sqrtHanning_rev = vcombine_f32(vget_high_f32(vec_sqrtHanning_rev),
- vget_low_f32(vec_sqrtHanning_rev));
- vst1q_f32(&x_windowed[i], vmulq_f32(vec_Buf1, vec_sqrtHanning));
- vst1q_f32(&x_windowed[PART_LEN + i],
- vmulq_f32(vec_Buf2, vec_sqrtHanning_rev));
- }
-}
-
-// Puts fft output data into a complex valued array.
-__inline static void StoreAsComplex(const float* data,
- float data_complex[2][PART_LEN1]) {
- int i;
- for (i = 0; i < PART_LEN; i += 4) {
- const float32x4x2_t vec_data = vld2q_f32(&data[2 * i]);
- vst1q_f32(&data_complex[0][i], vec_data.val[0]);
- vst1q_f32(&data_complex[1][i], vec_data.val[1]);
- }
- // fix beginning/end values
- data_complex[1][0] = 0;
- data_complex[1][PART_LEN] = 0;
- data_complex[0][0] = data[0];
- data_complex[0][PART_LEN] = data[1];
-}
-
-static void SubbandCoherenceNEON(AecCore* aec,
- float efw[2][PART_LEN1],
- float xfw[2][PART_LEN1],
- float* fft,
- float* cohde,
- float* cohxd) {
- float dfw[2][PART_LEN1];
- int i;
-
- if (aec->delayEstCtr == 0)
- aec->delayIdx = PartitionDelay(aec);
-
- // Use delayed far.
- memcpy(xfw,
- aec->xfwBuf + aec->delayIdx * PART_LEN1,
- sizeof(xfw[0][0]) * 2 * PART_LEN1);
-
- // Windowed near fft
- WindowData(fft, aec->dBuf);
- aec_rdft_forward_128(fft);
- StoreAsComplex(fft, dfw);
-
- // Windowed error fft
- WindowData(fft, aec->eBuf);
- aec_rdft_forward_128(fft);
- StoreAsComplex(fft, efw);
-
- SmoothedPSD(aec, efw, dfw, xfw);
-
- {
- const float32x4_t vec_1eminus10 = vdupq_n_f32(1e-10f);
-
- // Subband coherence
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const float32x4_t vec_sd = vld1q_f32(&aec->sd[i]);
- const float32x4_t vec_se = vld1q_f32(&aec->se[i]);
- const float32x4_t vec_sx = vld1q_f32(&aec->sx[i]);
- const float32x4_t vec_sdse = vmlaq_f32(vec_1eminus10, vec_sd, vec_se);
- const float32x4_t vec_sdsx = vmlaq_f32(vec_1eminus10, vec_sd, vec_sx);
- float32x4x2_t vec_sde = vld2q_f32(&aec->sde[i][0]);
- float32x4x2_t vec_sxd = vld2q_f32(&aec->sxd[i][0]);
- float32x4_t vec_cohde = vmulq_f32(vec_sde.val[0], vec_sde.val[0]);
- float32x4_t vec_cohxd = vmulq_f32(vec_sxd.val[0], vec_sxd.val[0]);
- vec_cohde = vmlaq_f32(vec_cohde, vec_sde.val[1], vec_sde.val[1]);
- vec_cohde = vdivq_f32(vec_cohde, vec_sdse);
- vec_cohxd = vmlaq_f32(vec_cohxd, vec_sxd.val[1], vec_sxd.val[1]);
- vec_cohxd = vdivq_f32(vec_cohxd, vec_sdsx);
-
- vst1q_f32(&cohde[i], vec_cohde);
- vst1q_f32(&cohxd[i], vec_cohxd);
- }
- }
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- cohde[i] =
- (aec->sde[i][0] * aec->sde[i][0] + aec->sde[i][1] * aec->sde[i][1]) /
- (aec->sd[i] * aec->se[i] + 1e-10f);
- cohxd[i] =
- (aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) /
- (aec->sx[i] * aec->sd[i] + 1e-10f);
- }
-}
-
-void WebRtcAec_InitAec_neon(void) {
- WebRtcAec_FilterFar = FilterFarNEON;
- WebRtcAec_ScaleErrorSignal = ScaleErrorSignalNEON;
- WebRtcAec_FilterAdaptation = FilterAdaptationNEON;
- WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppressNEON;
- WebRtcAec_SubbandCoherence = SubbandCoherenceNEON;
-}
-
diff --git a/webrtc/modules/audio_processing/aec/aec_core_sse2.c b/webrtc/modules/audio_processing/aec/aec_core_sse2.c
deleted file mode 100644
index b1bffcb..0000000
--- a/webrtc/modules/audio_processing/aec/aec_core_sse2.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * The core AEC algorithm, SSE2 version of speed-critical functions.
- */
-
-#include <emmintrin.h>
-#include <math.h>
-#include <string.h> // memset
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/aec/aec_common.h"
-#include "webrtc/modules/audio_processing/aec/aec_core_internal.h"
-#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
-
-__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bRe - aIm * bIm;
-}
-
-__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
- return aRe * bIm + aIm * bRe;
-}
-
-static void FilterFarSSE2(AecCore* aec, float yf[2][PART_LEN1]) {
- int i;
- const int num_partitions = aec->num_partitions;
- for (i = 0; i < num_partitions; i++) {
- int j;
- int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + aec->xfBufBlockPos >= num_partitions) {
- xPos -= num_partitions * (PART_LEN1);
- }
-
- // vectorized code (four at once)
- for (j = 0; j + 3 < PART_LEN1; j += 4) {
- const __m128 xfBuf_re = _mm_loadu_ps(&aec->xfBuf[0][xPos + j]);
- const __m128 xfBuf_im = _mm_loadu_ps(&aec->xfBuf[1][xPos + j]);
- const __m128 wfBuf_re = _mm_loadu_ps(&aec->wfBuf[0][pos + j]);
- const __m128 wfBuf_im = _mm_loadu_ps(&aec->wfBuf[1][pos + j]);
- const __m128 yf_re = _mm_loadu_ps(&yf[0][j]);
- const __m128 yf_im = _mm_loadu_ps(&yf[1][j]);
- const __m128 a = _mm_mul_ps(xfBuf_re, wfBuf_re);
- const __m128 b = _mm_mul_ps(xfBuf_im, wfBuf_im);
- const __m128 c = _mm_mul_ps(xfBuf_re, wfBuf_im);
- const __m128 d = _mm_mul_ps(xfBuf_im, wfBuf_re);
- const __m128 e = _mm_sub_ps(a, b);
- const __m128 f = _mm_add_ps(c, d);
- const __m128 g = _mm_add_ps(yf_re, e);
- const __m128 h = _mm_add_ps(yf_im, f);
- _mm_storeu_ps(&yf[0][j], g);
- _mm_storeu_ps(&yf[1][j], h);
- }
- // scalar code for the remaining items.
- for (; j < PART_LEN1; j++) {
- yf[0][j] += MulRe(aec->xfBuf[0][xPos + j],
- aec->xfBuf[1][xPos + j],
- aec->wfBuf[0][pos + j],
- aec->wfBuf[1][pos + j]);
- yf[1][j] += MulIm(aec->xfBuf[0][xPos + j],
- aec->xfBuf[1][xPos + j],
- aec->wfBuf[0][pos + j],
- aec->wfBuf[1][pos + j]);
- }
- }
-}
-
-static void ScaleErrorSignalSSE2(AecCore* aec, float ef[2][PART_LEN1]) {
- const __m128 k1e_10f = _mm_set1_ps(1e-10f);
- const __m128 kMu = aec->extended_filter_enabled ? _mm_set1_ps(kExtendedMu)
- : _mm_set1_ps(aec->normal_mu);
- const __m128 kThresh = aec->extended_filter_enabled
- ? _mm_set1_ps(kExtendedErrorThreshold)
- : _mm_set1_ps(aec->normal_error_threshold);
-
- int i;
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const __m128 xPow = _mm_loadu_ps(&aec->xPow[i]);
- const __m128 ef_re_base = _mm_loadu_ps(&ef[0][i]);
- const __m128 ef_im_base = _mm_loadu_ps(&ef[1][i]);
-
- const __m128 xPowPlus = _mm_add_ps(xPow, k1e_10f);
- __m128 ef_re = _mm_div_ps(ef_re_base, xPowPlus);
- __m128 ef_im = _mm_div_ps(ef_im_base, xPowPlus);
- const __m128 ef_re2 = _mm_mul_ps(ef_re, ef_re);
- const __m128 ef_im2 = _mm_mul_ps(ef_im, ef_im);
- const __m128 ef_sum2 = _mm_add_ps(ef_re2, ef_im2);
- const __m128 absEf = _mm_sqrt_ps(ef_sum2);
- const __m128 bigger = _mm_cmpgt_ps(absEf, kThresh);
- __m128 absEfPlus = _mm_add_ps(absEf, k1e_10f);
- const __m128 absEfInv = _mm_div_ps(kThresh, absEfPlus);
- __m128 ef_re_if = _mm_mul_ps(ef_re, absEfInv);
- __m128 ef_im_if = _mm_mul_ps(ef_im, absEfInv);
- ef_re_if = _mm_and_ps(bigger, ef_re_if);
- ef_im_if = _mm_and_ps(bigger, ef_im_if);
- ef_re = _mm_andnot_ps(bigger, ef_re);
- ef_im = _mm_andnot_ps(bigger, ef_im);
- ef_re = _mm_or_ps(ef_re, ef_re_if);
- ef_im = _mm_or_ps(ef_im, ef_im_if);
- ef_re = _mm_mul_ps(ef_re, kMu);
- ef_im = _mm_mul_ps(ef_im, kMu);
-
- _mm_storeu_ps(&ef[0][i], ef_re);
- _mm_storeu_ps(&ef[1][i], ef_im);
- }
- // scalar code for the remaining items.
- {
- const float mu =
- aec->extended_filter_enabled ? kExtendedMu : aec->normal_mu;
- const float error_threshold = aec->extended_filter_enabled
- ? kExtendedErrorThreshold
- : aec->normal_error_threshold;
- for (; i < (PART_LEN1); i++) {
- float abs_ef;
- ef[0][i] /= (aec->xPow[i] + 1e-10f);
- ef[1][i] /= (aec->xPow[i] + 1e-10f);
- abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
-
- if (abs_ef > error_threshold) {
- abs_ef = error_threshold / (abs_ef + 1e-10f);
- ef[0][i] *= abs_ef;
- ef[1][i] *= abs_ef;
- }
-
- // Stepsize factor
- ef[0][i] *= mu;
- ef[1][i] *= mu;
- }
- }
-}
-
-static void FilterAdaptationSSE2(AecCore* aec,
- float* fft,
- float ef[2][PART_LEN1]) {
- int i, j;
- const int num_partitions = aec->num_partitions;
- for (i = 0; i < num_partitions; i++) {
- int xPos = (i + aec->xfBufBlockPos) * (PART_LEN1);
- int pos = i * PART_LEN1;
- // Check for wrap
- if (i + aec->xfBufBlockPos >= num_partitions) {
- xPos -= num_partitions * PART_LEN1;
- }
-
- // Process the whole array...
- for (j = 0; j < PART_LEN; j += 4) {
- // Load xfBuf and ef.
- const __m128 xfBuf_re = _mm_loadu_ps(&aec->xfBuf[0][xPos + j]);
- const __m128 xfBuf_im = _mm_loadu_ps(&aec->xfBuf[1][xPos + j]);
- const __m128 ef_re = _mm_loadu_ps(&ef[0][j]);
- const __m128 ef_im = _mm_loadu_ps(&ef[1][j]);
- // Calculate the product of conjugate(xfBuf) by ef.
- // re(conjugate(a) * b) = aRe * bRe + aIm * bIm
- // im(conjugate(a) * b)= aRe * bIm - aIm * bRe
- const __m128 a = _mm_mul_ps(xfBuf_re, ef_re);
- const __m128 b = _mm_mul_ps(xfBuf_im, ef_im);
- const __m128 c = _mm_mul_ps(xfBuf_re, ef_im);
- const __m128 d = _mm_mul_ps(xfBuf_im, ef_re);
- const __m128 e = _mm_add_ps(a, b);
- const __m128 f = _mm_sub_ps(c, d);
- // Interleave real and imaginary parts.
- const __m128 g = _mm_unpacklo_ps(e, f);
- const __m128 h = _mm_unpackhi_ps(e, f);
- // Store
- _mm_storeu_ps(&fft[2 * j + 0], g);
- _mm_storeu_ps(&fft[2 * j + 4], h);
- }
- // ... and fixup the first imaginary entry.
- fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN],
- -aec->xfBuf[1][xPos + PART_LEN],
- ef[0][PART_LEN],
- ef[1][PART_LEN]);
-
- aec_rdft_inverse_128(fft);
- memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
-
- // fft scaling
- {
- float scale = 2.0f / PART_LEN2;
- const __m128 scale_ps = _mm_load_ps1(&scale);
- for (j = 0; j < PART_LEN; j += 4) {
- const __m128 fft_ps = _mm_loadu_ps(&fft[j]);
- const __m128 fft_scale = _mm_mul_ps(fft_ps, scale_ps);
- _mm_storeu_ps(&fft[j], fft_scale);
- }
- }
- aec_rdft_forward_128(fft);
-
- {
- float wt1 = aec->wfBuf[1][pos];
- aec->wfBuf[0][pos + PART_LEN] += fft[1];
- for (j = 0; j < PART_LEN; j += 4) {
- __m128 wtBuf_re = _mm_loadu_ps(&aec->wfBuf[0][pos + j]);
- __m128 wtBuf_im = _mm_loadu_ps(&aec->wfBuf[1][pos + j]);
- const __m128 fft0 = _mm_loadu_ps(&fft[2 * j + 0]);
- const __m128 fft4 = _mm_loadu_ps(&fft[2 * j + 4]);
- const __m128 fft_re =
- _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(2, 0, 2, 0));
- const __m128 fft_im =
- _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(3, 1, 3, 1));
- wtBuf_re = _mm_add_ps(wtBuf_re, fft_re);
- wtBuf_im = _mm_add_ps(wtBuf_im, fft_im);
- _mm_storeu_ps(&aec->wfBuf[0][pos + j], wtBuf_re);
- _mm_storeu_ps(&aec->wfBuf[1][pos + j], wtBuf_im);
- }
- aec->wfBuf[1][pos] = wt1;
- }
- }
-}
-
-static __m128 mm_pow_ps(__m128 a, __m128 b) {
- // a^b = exp2(b * log2(a))
- // exp2(x) and log2(x) are calculated using polynomial approximations.
- __m128 log2_a, b_log2_a, a_exp_b;
-
- // Calculate log2(x), x = a.
- {
- // To calculate log2(x), we decompose x like this:
- // x = y * 2^n
- // n is an integer
- // y is in the [1.0, 2.0) range
- //
- // log2(x) = log2(y) + n
- // n can be evaluated by playing with float representation.
- // log2(y) in a small range can be approximated, this code uses an order
- // five polynomial approximation. The coefficients have been
- // estimated with the Remez algorithm and the resulting
- // polynomial has a maximum relative error of 0.00086%.
-
- // Compute n.
- // This is done by masking the exponent, shifting it into the top bit of
- // the mantissa, putting eight into the biased exponent (to shift/
- // compensate the fact that the exponent has been shifted in the top/
- // fractional part and finally getting rid of the implicit leading one
- // from the mantissa by substracting it out.
- static const ALIGN16_BEG int float_exponent_mask[4] ALIGN16_END = {
- 0x7F800000, 0x7F800000, 0x7F800000, 0x7F800000};
- static const ALIGN16_BEG int eight_biased_exponent[4] ALIGN16_END = {
- 0x43800000, 0x43800000, 0x43800000, 0x43800000};
- static const ALIGN16_BEG int implicit_leading_one[4] ALIGN16_END = {
- 0x43BF8000, 0x43BF8000, 0x43BF8000, 0x43BF8000};
- static const int shift_exponent_into_top_mantissa = 8;
- const __m128 two_n = _mm_and_ps(a, *((__m128*)float_exponent_mask));
- const __m128 n_1 = _mm_castsi128_ps(_mm_srli_epi32(
- _mm_castps_si128(two_n), shift_exponent_into_top_mantissa));
- const __m128 n_0 = _mm_or_ps(n_1, *((__m128*)eight_biased_exponent));
- const __m128 n = _mm_sub_ps(n_0, *((__m128*)implicit_leading_one));
-
- // Compute y.
- static const ALIGN16_BEG int mantissa_mask[4] ALIGN16_END = {
- 0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF};
- static const ALIGN16_BEG int zero_biased_exponent_is_one[4] ALIGN16_END = {
- 0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000};
- const __m128 mantissa = _mm_and_ps(a, *((__m128*)mantissa_mask));
- const __m128 y =
- _mm_or_ps(mantissa, *((__m128*)zero_biased_exponent_is_one));
-
- // Approximate log2(y) ~= (y - 1) * pol5(y).
- // pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0
- static const ALIGN16_BEG float ALIGN16_END C5[4] = {
- -3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f};
- static const ALIGN16_BEG float ALIGN16_END
- C4[4] = {3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f};
- static const ALIGN16_BEG float ALIGN16_END
- C3[4] = {-1.2315303f, -1.2315303f, -1.2315303f, -1.2315303f};
- static const ALIGN16_BEG float ALIGN16_END
- C2[4] = {2.5988452f, 2.5988452f, 2.5988452f, 2.5988452f};
- static const ALIGN16_BEG float ALIGN16_END
- C1[4] = {-3.3241990f, -3.3241990f, -3.3241990f, -3.3241990f};
- static const ALIGN16_BEG float ALIGN16_END
- C0[4] = {3.1157899f, 3.1157899f, 3.1157899f, 3.1157899f};
- const __m128 pol5_y_0 = _mm_mul_ps(y, *((__m128*)C5));
- const __m128 pol5_y_1 = _mm_add_ps(pol5_y_0, *((__m128*)C4));
- const __m128 pol5_y_2 = _mm_mul_ps(pol5_y_1, y);
- const __m128 pol5_y_3 = _mm_add_ps(pol5_y_2, *((__m128*)C3));
- const __m128 pol5_y_4 = _mm_mul_ps(pol5_y_3, y);
- const __m128 pol5_y_5 = _mm_add_ps(pol5_y_4, *((__m128*)C2));
- const __m128 pol5_y_6 = _mm_mul_ps(pol5_y_5, y);
- const __m128 pol5_y_7 = _mm_add_ps(pol5_y_6, *((__m128*)C1));
- const __m128 pol5_y_8 = _mm_mul_ps(pol5_y_7, y);
- const __m128 pol5_y = _mm_add_ps(pol5_y_8, *((__m128*)C0));
- const __m128 y_minus_one =
- _mm_sub_ps(y, *((__m128*)zero_biased_exponent_is_one));
- const __m128 log2_y = _mm_mul_ps(y_minus_one, pol5_y);
-
- // Combine parts.
- log2_a = _mm_add_ps(n, log2_y);
- }
-
- // b * log2(a)
- b_log2_a = _mm_mul_ps(b, log2_a);
-
- // Calculate exp2(x), x = b * log2(a).
- {
- // To calculate 2^x, we decompose x like this:
- // x = n + y
- // n is an integer, the value of x - 0.5 rounded down, therefore
- // y is in the [0.5, 1.5) range
- //
- // 2^x = 2^n * 2^y
- // 2^n can be evaluated by playing with float representation.
- // 2^y in a small range can be approximated, this code uses an order two
- // polynomial approximation. The coefficients have been estimated
- // with the Remez algorithm and the resulting polynomial has a
- // maximum relative error of 0.17%.
-
- // To avoid over/underflow, we reduce the range of input to ]-127, 129].
- static const ALIGN16_BEG float max_input[4] ALIGN16_END = {129.f, 129.f,
- 129.f, 129.f};
- static const ALIGN16_BEG float min_input[4] ALIGN16_END = {
- -126.99999f, -126.99999f, -126.99999f, -126.99999f};
- const __m128 x_min = _mm_min_ps(b_log2_a, *((__m128*)max_input));
- const __m128 x_max = _mm_max_ps(x_min, *((__m128*)min_input));
- // Compute n.
- static const ALIGN16_BEG float half[4] ALIGN16_END = {0.5f, 0.5f,
- 0.5f, 0.5f};
- const __m128 x_minus_half = _mm_sub_ps(x_max, *((__m128*)half));
- const __m128i x_minus_half_floor = _mm_cvtps_epi32(x_minus_half);
- // Compute 2^n.
- static const ALIGN16_BEG int float_exponent_bias[4] ALIGN16_END = {
- 127, 127, 127, 127};
- static const int float_exponent_shift = 23;
- const __m128i two_n_exponent =
- _mm_add_epi32(x_minus_half_floor, *((__m128i*)float_exponent_bias));
- const __m128 two_n =
- _mm_castsi128_ps(_mm_slli_epi32(two_n_exponent, float_exponent_shift));
- // Compute y.
- const __m128 y = _mm_sub_ps(x_max, _mm_cvtepi32_ps(x_minus_half_floor));
- // Approximate 2^y ~= C2 * y^2 + C1 * y + C0.
- static const ALIGN16_BEG float C2[4] ALIGN16_END = {
- 3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f};
- static const ALIGN16_BEG float C1[4] ALIGN16_END = {
- 6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f};
- static const ALIGN16_BEG float C0[4] ALIGN16_END = {1.0017247f, 1.0017247f,
- 1.0017247f, 1.0017247f};
- const __m128 exp2_y_0 = _mm_mul_ps(y, *((__m128*)C2));
- const __m128 exp2_y_1 = _mm_add_ps(exp2_y_0, *((__m128*)C1));
- const __m128 exp2_y_2 = _mm_mul_ps(exp2_y_1, y);
- const __m128 exp2_y = _mm_add_ps(exp2_y_2, *((__m128*)C0));
-
- // Combine parts.
- a_exp_b = _mm_mul_ps(exp2_y, two_n);
- }
- return a_exp_b;
-}
-
-static void OverdriveAndSuppressSSE2(AecCore* aec,
- float hNl[PART_LEN1],
- const float hNlFb,
- float efw[2][PART_LEN1]) {
- int i;
- const __m128 vec_hNlFb = _mm_set1_ps(hNlFb);
- const __m128 vec_one = _mm_set1_ps(1.0f);
- const __m128 vec_minus_one = _mm_set1_ps(-1.0f);
- const __m128 vec_overDriveSm = _mm_set1_ps(aec->overDriveSm);
- // vectorized code (four at once)
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- // Weight subbands
- __m128 vec_hNl = _mm_loadu_ps(&hNl[i]);
- const __m128 vec_weightCurve = _mm_loadu_ps(&WebRtcAec_weightCurve[i]);
- const __m128 bigger = _mm_cmpgt_ps(vec_hNl, vec_hNlFb);
- const __m128 vec_weightCurve_hNlFb = _mm_mul_ps(vec_weightCurve, vec_hNlFb);
- const __m128 vec_one_weightCurve = _mm_sub_ps(vec_one, vec_weightCurve);
- const __m128 vec_one_weightCurve_hNl =
- _mm_mul_ps(vec_one_weightCurve, vec_hNl);
- const __m128 vec_if0 = _mm_andnot_ps(bigger, vec_hNl);
- const __m128 vec_if1 = _mm_and_ps(
- bigger, _mm_add_ps(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl));
- vec_hNl = _mm_or_ps(vec_if0, vec_if1);
-
- {
- const __m128 vec_overDriveCurve =
- _mm_loadu_ps(&WebRtcAec_overDriveCurve[i]);
- const __m128 vec_overDriveSm_overDriveCurve =
- _mm_mul_ps(vec_overDriveSm, vec_overDriveCurve);
- vec_hNl = mm_pow_ps(vec_hNl, vec_overDriveSm_overDriveCurve);
- _mm_storeu_ps(&hNl[i], vec_hNl);
- }
-
- // Suppress error signal
- {
- __m128 vec_efw_re = _mm_loadu_ps(&efw[0][i]);
- __m128 vec_efw_im = _mm_loadu_ps(&efw[1][i]);
- vec_efw_re = _mm_mul_ps(vec_efw_re, vec_hNl);
- vec_efw_im = _mm_mul_ps(vec_efw_im, vec_hNl);
-
- // Ooura fft returns incorrect sign on imaginary component. It matters
- // here because we are making an additive change with comfort noise.
- vec_efw_im = _mm_mul_ps(vec_efw_im, vec_minus_one);
- _mm_storeu_ps(&efw[0][i], vec_efw_re);
- _mm_storeu_ps(&efw[1][i], vec_efw_im);
- }
- }
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- // Weight subbands
- if (hNl[i] > hNlFb) {
- hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
- (1 - WebRtcAec_weightCurve[i]) * hNl[i];
- }
- hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
-
- // Suppress error signal
- efw[0][i] *= hNl[i];
- efw[1][i] *= hNl[i];
-
- // Ooura fft returns incorrect sign on imaginary component. It matters
- // here because we are making an additive change with comfort noise.
- efw[1][i] *= -1;
- }
-}
-
-__inline static void _mm_add_ps_4x1(__m128 sum, float *dst) {
- // A+B C+D
- sum = _mm_add_ps(sum, _mm_shuffle_ps(sum, sum, _MM_SHUFFLE(0, 0, 3, 2)));
- // A+B+C+D A+B+C+D
- sum = _mm_add_ps(sum, _mm_shuffle_ps(sum, sum, _MM_SHUFFLE(1, 1, 1, 1)));
- _mm_store_ss(dst, sum);
-}
-static int PartitionDelay(const AecCore* aec) {
- // Measures the energy in each filter partition and returns the partition with
- // highest energy.
- // TODO(bjornv): Spread computational cost by computing one partition per
- // block?
- float wfEnMax = 0;
- int i;
- int delay = 0;
-
- for (i = 0; i < aec->num_partitions; i++) {
- int j;
- int pos = i * PART_LEN1;
- float wfEn = 0;
- __m128 vec_wfEn = _mm_set1_ps(0.0f);
- // vectorized code (four at once)
- for (j = 0; j + 3 < PART_LEN1; j += 4) {
- const __m128 vec_wfBuf0 = _mm_loadu_ps(&aec->wfBuf[0][pos + j]);
- const __m128 vec_wfBuf1 = _mm_loadu_ps(&aec->wfBuf[1][pos + j]);
- vec_wfEn = _mm_add_ps(vec_wfEn, _mm_mul_ps(vec_wfBuf0, vec_wfBuf0));
- vec_wfEn = _mm_add_ps(vec_wfEn, _mm_mul_ps(vec_wfBuf1, vec_wfBuf1));
- }
- _mm_add_ps_4x1(vec_wfEn, &wfEn);
-
- // scalar code for the remaining items.
- for (; j < PART_LEN1; j++) {
- wfEn += aec->wfBuf[0][pos + j] * aec->wfBuf[0][pos + j] +
- aec->wfBuf[1][pos + j] * aec->wfBuf[1][pos + j];
- }
-
- if (wfEn > wfEnMax) {
- wfEnMax = wfEn;
- delay = i;
- }
- }
- return delay;
-}
-
-// Updates the following smoothed Power Spectral Densities (PSD):
-// - sd : near-end
-// - se : residual echo
-// - sx : far-end
-// - sde : cross-PSD of near-end and residual echo
-// - sxd : cross-PSD of near-end and far-end
-//
-// In addition to updating the PSDs, also the filter diverge state is determined
-// upon actions are taken.
-static void SmoothedPSD(AecCore* aec,
- float efw[2][PART_LEN1],
- float dfw[2][PART_LEN1],
- float xfw[2][PART_LEN1]) {
- // Power estimate smoothing coefficients.
- const float* ptrGCoh = aec->extended_filter_enabled
- ? WebRtcAec_kExtendedSmoothingCoefficients[aec->mult - 1]
- : WebRtcAec_kNormalSmoothingCoefficients[aec->mult - 1];
- int i;
- float sdSum = 0, seSum = 0;
- const __m128 vec_15 = _mm_set1_ps(WebRtcAec_kMinFarendPSD);
- const __m128 vec_GCoh0 = _mm_set1_ps(ptrGCoh[0]);
- const __m128 vec_GCoh1 = _mm_set1_ps(ptrGCoh[1]);
- __m128 vec_sdSum = _mm_set1_ps(0.0f);
- __m128 vec_seSum = _mm_set1_ps(0.0f);
-
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const __m128 vec_dfw0 = _mm_loadu_ps(&dfw[0][i]);
- const __m128 vec_dfw1 = _mm_loadu_ps(&dfw[1][i]);
- const __m128 vec_efw0 = _mm_loadu_ps(&efw[0][i]);
- const __m128 vec_efw1 = _mm_loadu_ps(&efw[1][i]);
- const __m128 vec_xfw0 = _mm_loadu_ps(&xfw[0][i]);
- const __m128 vec_xfw1 = _mm_loadu_ps(&xfw[1][i]);
- __m128 vec_sd = _mm_mul_ps(_mm_loadu_ps(&aec->sd[i]), vec_GCoh0);
- __m128 vec_se = _mm_mul_ps(_mm_loadu_ps(&aec->se[i]), vec_GCoh0);
- __m128 vec_sx = _mm_mul_ps(_mm_loadu_ps(&aec->sx[i]), vec_GCoh0);
- __m128 vec_dfw_sumsq = _mm_mul_ps(vec_dfw0, vec_dfw0);
- __m128 vec_efw_sumsq = _mm_mul_ps(vec_efw0, vec_efw0);
- __m128 vec_xfw_sumsq = _mm_mul_ps(vec_xfw0, vec_xfw0);
- vec_dfw_sumsq = _mm_add_ps(vec_dfw_sumsq, _mm_mul_ps(vec_dfw1, vec_dfw1));
- vec_efw_sumsq = _mm_add_ps(vec_efw_sumsq, _mm_mul_ps(vec_efw1, vec_efw1));
- vec_xfw_sumsq = _mm_add_ps(vec_xfw_sumsq, _mm_mul_ps(vec_xfw1, vec_xfw1));
- vec_xfw_sumsq = _mm_max_ps(vec_xfw_sumsq, vec_15);
- vec_sd = _mm_add_ps(vec_sd, _mm_mul_ps(vec_dfw_sumsq, vec_GCoh1));
- vec_se = _mm_add_ps(vec_se, _mm_mul_ps(vec_efw_sumsq, vec_GCoh1));
- vec_sx = _mm_add_ps(vec_sx, _mm_mul_ps(vec_xfw_sumsq, vec_GCoh1));
- _mm_storeu_ps(&aec->sd[i], vec_sd);
- _mm_storeu_ps(&aec->se[i], vec_se);
- _mm_storeu_ps(&aec->sx[i], vec_sx);
-
- {
- const __m128 vec_3210 = _mm_loadu_ps(&aec->sde[i][0]);
- const __m128 vec_7654 = _mm_loadu_ps(&aec->sde[i + 2][0]);
- __m128 vec_a = _mm_shuffle_ps(vec_3210, vec_7654,
- _MM_SHUFFLE(2, 0, 2, 0));
- __m128 vec_b = _mm_shuffle_ps(vec_3210, vec_7654,
- _MM_SHUFFLE(3, 1, 3, 1));
- __m128 vec_dfwefw0011 = _mm_mul_ps(vec_dfw0, vec_efw0);
- __m128 vec_dfwefw0110 = _mm_mul_ps(vec_dfw0, vec_efw1);
- vec_a = _mm_mul_ps(vec_a, vec_GCoh0);
- vec_b = _mm_mul_ps(vec_b, vec_GCoh0);
- vec_dfwefw0011 = _mm_add_ps(vec_dfwefw0011,
- _mm_mul_ps(vec_dfw1, vec_efw1));
- vec_dfwefw0110 = _mm_sub_ps(vec_dfwefw0110,
- _mm_mul_ps(vec_dfw1, vec_efw0));
- vec_a = _mm_add_ps(vec_a, _mm_mul_ps(vec_dfwefw0011, vec_GCoh1));
- vec_b = _mm_add_ps(vec_b, _mm_mul_ps(vec_dfwefw0110, vec_GCoh1));
- _mm_storeu_ps(&aec->sde[i][0], _mm_unpacklo_ps(vec_a, vec_b));
- _mm_storeu_ps(&aec->sde[i + 2][0], _mm_unpackhi_ps(vec_a, vec_b));
- }
-
- {
- const __m128 vec_3210 = _mm_loadu_ps(&aec->sxd[i][0]);
- const __m128 vec_7654 = _mm_loadu_ps(&aec->sxd[i + 2][0]);
- __m128 vec_a = _mm_shuffle_ps(vec_3210, vec_7654,
- _MM_SHUFFLE(2, 0, 2, 0));
- __m128 vec_b = _mm_shuffle_ps(vec_3210, vec_7654,
- _MM_SHUFFLE(3, 1, 3, 1));
- __m128 vec_dfwxfw0011 = _mm_mul_ps(vec_dfw0, vec_xfw0);
- __m128 vec_dfwxfw0110 = _mm_mul_ps(vec_dfw0, vec_xfw1);
- vec_a = _mm_mul_ps(vec_a, vec_GCoh0);
- vec_b = _mm_mul_ps(vec_b, vec_GCoh0);
- vec_dfwxfw0011 = _mm_add_ps(vec_dfwxfw0011,
- _mm_mul_ps(vec_dfw1, vec_xfw1));
- vec_dfwxfw0110 = _mm_sub_ps(vec_dfwxfw0110,
- _mm_mul_ps(vec_dfw1, vec_xfw0));
- vec_a = _mm_add_ps(vec_a, _mm_mul_ps(vec_dfwxfw0011, vec_GCoh1));
- vec_b = _mm_add_ps(vec_b, _mm_mul_ps(vec_dfwxfw0110, vec_GCoh1));
- _mm_storeu_ps(&aec->sxd[i][0], _mm_unpacklo_ps(vec_a, vec_b));
- _mm_storeu_ps(&aec->sxd[i + 2][0], _mm_unpackhi_ps(vec_a, vec_b));
- }
-
- vec_sdSum = _mm_add_ps(vec_sdSum, vec_sd);
- vec_seSum = _mm_add_ps(vec_seSum, vec_se);
- }
-
- _mm_add_ps_4x1(vec_sdSum, &sdSum);
- _mm_add_ps_4x1(vec_seSum, &seSum);
-
- for (; i < PART_LEN1; i++) {
- aec->sd[i] = ptrGCoh[0] * aec->sd[i] +
- ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
- aec->se[i] = ptrGCoh[0] * aec->se[i] +
- ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
- // We threshold here to protect against the ill-effects of a zero farend.
- // The threshold is not arbitrarily chosen, but balances protection and
- // adverse interaction with the algorithm's tuning.
- // TODO(bjornv): investigate further why this is so sensitive.
- aec->sx[i] =
- ptrGCoh[0] * aec->sx[i] +
- ptrGCoh[1] * WEBRTC_SPL_MAX(
- xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
- WebRtcAec_kMinFarendPSD);
-
- aec->sde[i][0] =
- ptrGCoh[0] * aec->sde[i][0] +
- ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
- aec->sde[i][1] =
- ptrGCoh[0] * aec->sde[i][1] +
- ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
-
- aec->sxd[i][0] =
- ptrGCoh[0] * aec->sxd[i][0] +
- ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
- aec->sxd[i][1] =
- ptrGCoh[0] * aec->sxd[i][1] +
- ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
-
- sdSum += aec->sd[i];
- seSum += aec->se[i];
- }
-
- // Divergent filter safeguard.
- aec->divergeState = (aec->divergeState ? 1.05f : 1.0f) * seSum > sdSum;
-
- if (aec->divergeState)
- memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
-
- // Reset if error is significantly larger than nearend (13 dB).
- if (!aec->extended_filter_enabled && seSum > (19.95f * sdSum))
- memset(aec->wfBuf, 0, sizeof(aec->wfBuf));
-}
-
-// Window time domain data to be used by the fft.
-__inline static void WindowData(float* x_windowed, const float* x) {
- int i;
- for (i = 0; i < PART_LEN; i += 4) {
- const __m128 vec_Buf1 = _mm_loadu_ps(&x[i]);
- const __m128 vec_Buf2 = _mm_loadu_ps(&x[PART_LEN + i]);
- const __m128 vec_sqrtHanning = _mm_load_ps(&WebRtcAec_sqrtHanning[i]);
- // A B C D
- __m128 vec_sqrtHanning_rev =
- _mm_loadu_ps(&WebRtcAec_sqrtHanning[PART_LEN - i - 3]);
- // D C B A
- vec_sqrtHanning_rev =
- _mm_shuffle_ps(vec_sqrtHanning_rev, vec_sqrtHanning_rev,
- _MM_SHUFFLE(0, 1, 2, 3));
- _mm_storeu_ps(&x_windowed[i], _mm_mul_ps(vec_Buf1, vec_sqrtHanning));
- _mm_storeu_ps(&x_windowed[PART_LEN + i],
- _mm_mul_ps(vec_Buf2, vec_sqrtHanning_rev));
- }
-}
-
-// Puts fft output data into a complex valued array.
-__inline static void StoreAsComplex(const float* data,
- float data_complex[2][PART_LEN1]) {
- int i;
- for (i = 0; i < PART_LEN; i += 4) {
- const __m128 vec_fft0 = _mm_loadu_ps(&data[2 * i]);
- const __m128 vec_fft4 = _mm_loadu_ps(&data[2 * i + 4]);
- const __m128 vec_a = _mm_shuffle_ps(vec_fft0, vec_fft4,
- _MM_SHUFFLE(2, 0, 2, 0));
- const __m128 vec_b = _mm_shuffle_ps(vec_fft0, vec_fft4,
- _MM_SHUFFLE(3, 1, 3, 1));
- _mm_storeu_ps(&data_complex[0][i], vec_a);
- _mm_storeu_ps(&data_complex[1][i], vec_b);
- }
- // fix beginning/end values
- data_complex[1][0] = 0;
- data_complex[1][PART_LEN] = 0;
- data_complex[0][0] = data[0];
- data_complex[0][PART_LEN] = data[1];
-}
-
-static void SubbandCoherenceSSE2(AecCore* aec,
- float efw[2][PART_LEN1],
- float xfw[2][PART_LEN1],
- float* fft,
- float* cohde,
- float* cohxd) {
- float dfw[2][PART_LEN1];
- int i;
-
- if (aec->delayEstCtr == 0)
- aec->delayIdx = PartitionDelay(aec);
-
- // Use delayed far.
- memcpy(xfw,
- aec->xfwBuf + aec->delayIdx * PART_LEN1,
- sizeof(xfw[0][0]) * 2 * PART_LEN1);
-
- // Windowed near fft
- WindowData(fft, aec->dBuf);
- aec_rdft_forward_128(fft);
- StoreAsComplex(fft, dfw);
-
- // Windowed error fft
- WindowData(fft, aec->eBuf);
- aec_rdft_forward_128(fft);
- StoreAsComplex(fft, efw);
-
- SmoothedPSD(aec, efw, dfw, xfw);
-
- {
- const __m128 vec_1eminus10 = _mm_set1_ps(1e-10f);
-
- // Subband coherence
- for (i = 0; i + 3 < PART_LEN1; i += 4) {
- const __m128 vec_sd = _mm_loadu_ps(&aec->sd[i]);
- const __m128 vec_se = _mm_loadu_ps(&aec->se[i]);
- const __m128 vec_sx = _mm_loadu_ps(&aec->sx[i]);
- const __m128 vec_sdse = _mm_add_ps(vec_1eminus10,
- _mm_mul_ps(vec_sd, vec_se));
- const __m128 vec_sdsx = _mm_add_ps(vec_1eminus10,
- _mm_mul_ps(vec_sd, vec_sx));
- const __m128 vec_sde_3210 = _mm_loadu_ps(&aec->sde[i][0]);
- const __m128 vec_sde_7654 = _mm_loadu_ps(&aec->sde[i + 2][0]);
- const __m128 vec_sxd_3210 = _mm_loadu_ps(&aec->sxd[i][0]);
- const __m128 vec_sxd_7654 = _mm_loadu_ps(&aec->sxd[i + 2][0]);
- const __m128 vec_sde_0 = _mm_shuffle_ps(vec_sde_3210, vec_sde_7654,
- _MM_SHUFFLE(2, 0, 2, 0));
- const __m128 vec_sde_1 = _mm_shuffle_ps(vec_sde_3210, vec_sde_7654,
- _MM_SHUFFLE(3, 1, 3, 1));
- const __m128 vec_sxd_0 = _mm_shuffle_ps(vec_sxd_3210, vec_sxd_7654,
- _MM_SHUFFLE(2, 0, 2, 0));
- const __m128 vec_sxd_1 = _mm_shuffle_ps(vec_sxd_3210, vec_sxd_7654,
- _MM_SHUFFLE(3, 1, 3, 1));
- __m128 vec_cohde = _mm_mul_ps(vec_sde_0, vec_sde_0);
- __m128 vec_cohxd = _mm_mul_ps(vec_sxd_0, vec_sxd_0);
- vec_cohde = _mm_add_ps(vec_cohde, _mm_mul_ps(vec_sde_1, vec_sde_1));
- vec_cohde = _mm_div_ps(vec_cohde, vec_sdse);
- vec_cohxd = _mm_add_ps(vec_cohxd, _mm_mul_ps(vec_sxd_1, vec_sxd_1));
- vec_cohxd = _mm_div_ps(vec_cohxd, vec_sdsx);
- _mm_storeu_ps(&cohde[i], vec_cohde);
- _mm_storeu_ps(&cohxd[i], vec_cohxd);
- }
-
- // scalar code for the remaining items.
- for (; i < PART_LEN1; i++) {
- cohde[i] =
- (aec->sde[i][0] * aec->sde[i][0] + aec->sde[i][1] * aec->sde[i][1]) /
- (aec->sd[i] * aec->se[i] + 1e-10f);
- cohxd[i] =
- (aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) /
- (aec->sx[i] * aec->sd[i] + 1e-10f);
- }
- }
-}
-
-void WebRtcAec_InitAec_SSE2(void) {
- WebRtcAec_FilterFar = FilterFarSSE2;
- WebRtcAec_ScaleErrorSignal = ScaleErrorSignalSSE2;
- WebRtcAec_FilterAdaptation = FilterAdaptationSSE2;
- WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppressSSE2;
- WebRtcAec_SubbandCoherence = SubbandCoherenceSSE2;
-}
diff --git a/webrtc/modules/audio_processing/aec/aec_rdft.h b/webrtc/modules/audio_processing/aec/aec_rdft.h
deleted file mode 100644
index 18eb7a5..0000000
--- a/webrtc/modules/audio_processing/aec/aec_rdft.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
-
-#include "webrtc/modules/audio_processing/aec/aec_common.h"
-
-// These intrinsics were unavailable before VS 2008.
-// TODO(andrew): move to a common file.
-#if defined(_MSC_VER) && _MSC_VER < 1500
-#include <emmintrin.h>
-static __inline __m128 _mm_castsi128_ps(__m128i a) { return *(__m128*)&a; }
-static __inline __m128i _mm_castps_si128(__m128 a) { return *(__m128i*)&a; }
-#endif
-
-// Constants shared by all paths (C, SSE2, NEON).
-extern const float rdft_w[64];
-// Constants used by the C path.
-extern const float rdft_wk3ri_first[16];
-extern const float rdft_wk3ri_second[16];
-// Constants used by SSE2 and NEON but initialized in the C path.
-extern ALIGN16_BEG const float ALIGN16_END rdft_wk1r[32];
-extern ALIGN16_BEG const float ALIGN16_END rdft_wk2r[32];
-extern ALIGN16_BEG const float ALIGN16_END rdft_wk3r[32];
-extern ALIGN16_BEG const float ALIGN16_END rdft_wk1i[32];
-extern ALIGN16_BEG const float ALIGN16_END rdft_wk2i[32];
-extern ALIGN16_BEG const float ALIGN16_END rdft_wk3i[32];
-extern ALIGN16_BEG const float ALIGN16_END cftmdl_wk1r[4];
-
-// code path selection function pointers
-typedef void (*RftSub128)(float* a);
-extern RftSub128 rftfsub_128;
-extern RftSub128 rftbsub_128;
-extern RftSub128 cft1st_128;
-extern RftSub128 cftmdl_128;
-extern RftSub128 cftfsub_128;
-extern RftSub128 cftbsub_128;
-extern RftSub128 bitrv2_128;
-
-// entry points
-void aec_rdft_init(void);
-void aec_rdft_init_sse2(void);
-void aec_rdft_forward_128(float* a);
-void aec_rdft_inverse_128(float* a);
-
-#if defined(MIPS_FPU_LE)
-void aec_rdft_init_mips(void);
-#endif
-#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
-void aec_rdft_init_neon(void);
-#endif
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
diff --git a/webrtc/modules/audio_processing/aec/aec_rdft_mips.c b/webrtc/modules/audio_processing/aec/aec_rdft_mips.c
deleted file mode 100644
index 7e64e65..0000000
--- a/webrtc/modules/audio_processing/aec/aec_rdft_mips.c
+++ /dev/null
@@ -1,1187 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
-#include "webrtc/typedefs.h"
-
-static void bitrv2_128_mips(float* a) {
- // n is 128
- float xr, xi, yr, yi;
-
- xr = a[8];
- xi = a[9];
- yr = a[16];
- yi = a[17];
- a[8] = yr;
- a[9] = yi;
- a[16] = xr;
- a[17] = xi;
-
- xr = a[64];
- xi = a[65];
- yr = a[2];
- yi = a[3];
- a[64] = yr;
- a[65] = yi;
- a[2] = xr;
- a[3] = xi;
-
- xr = a[72];
- xi = a[73];
- yr = a[18];
- yi = a[19];
- a[72] = yr;
- a[73] = yi;
- a[18] = xr;
- a[19] = xi;
-
- xr = a[80];
- xi = a[81];
- yr = a[10];
- yi = a[11];
- a[80] = yr;
- a[81] = yi;
- a[10] = xr;
- a[11] = xi;
-
- xr = a[88];
- xi = a[89];
- yr = a[26];
- yi = a[27];
- a[88] = yr;
- a[89] = yi;
- a[26] = xr;
- a[27] = xi;
-
- xr = a[74];
- xi = a[75];
- yr = a[82];
- yi = a[83];
- a[74] = yr;
- a[75] = yi;
- a[82] = xr;
- a[83] = xi;
-
- xr = a[32];
- xi = a[33];
- yr = a[4];
- yi = a[5];
- a[32] = yr;
- a[33] = yi;
- a[4] = xr;
- a[5] = xi;
-
- xr = a[40];
- xi = a[41];
- yr = a[20];
- yi = a[21];
- a[40] = yr;
- a[41] = yi;
- a[20] = xr;
- a[21] = xi;
-
- xr = a[48];
- xi = a[49];
- yr = a[12];
- yi = a[13];
- a[48] = yr;
- a[49] = yi;
- a[12] = xr;
- a[13] = xi;
-
- xr = a[56];
- xi = a[57];
- yr = a[28];
- yi = a[29];
- a[56] = yr;
- a[57] = yi;
- a[28] = xr;
- a[29] = xi;
-
- xr = a[34];
- xi = a[35];
- yr = a[68];
- yi = a[69];
- a[34] = yr;
- a[35] = yi;
- a[68] = xr;
- a[69] = xi;
-
- xr = a[42];
- xi = a[43];
- yr = a[84];
- yi = a[85];
- a[42] = yr;
- a[43] = yi;
- a[84] = xr;
- a[85] = xi;
-
- xr = a[50];
- xi = a[51];
- yr = a[76];
- yi = a[77];
- a[50] = yr;
- a[51] = yi;
- a[76] = xr;
- a[77] = xi;
-
- xr = a[58];
- xi = a[59];
- yr = a[92];
- yi = a[93];
- a[58] = yr;
- a[59] = yi;
- a[92] = xr;
- a[93] = xi;
-
- xr = a[44];
- xi = a[45];
- yr = a[52];
- yi = a[53];
- a[44] = yr;
- a[45] = yi;
- a[52] = xr;
- a[53] = xi;
-
- xr = a[96];
- xi = a[97];
- yr = a[6];
- yi = a[7];
- a[96] = yr;
- a[97] = yi;
- a[6] = xr;
- a[7] = xi;
-
- xr = a[104];
- xi = a[105];
- yr = a[22];
- yi = a[23];
- a[104] = yr;
- a[105] = yi;
- a[22] = xr;
- a[23] = xi;
-
- xr = a[112];
- xi = a[113];
- yr = a[14];
- yi = a[15];
- a[112] = yr;
- a[113] = yi;
- a[14] = xr;
- a[15] = xi;
-
- xr = a[120];
- xi = a[121];
- yr = a[30];
- yi = a[31];
- a[120] = yr;
- a[121] = yi;
- a[30] = xr;
- a[31] = xi;
-
- xr = a[98];
- xi = a[99];
- yr = a[70];
- yi = a[71];
- a[98] = yr;
- a[99] = yi;
- a[70] = xr;
- a[71] = xi;
-
- xr = a[106];
- xi = a[107];
- yr = a[86];
- yi = a[87];
- a[106] = yr;
- a[107] = yi;
- a[86] = xr;
- a[87] = xi;
-
- xr = a[114];
- xi = a[115];
- yr = a[78];
- yi = a[79];
- a[114] = yr;
- a[115] = yi;
- a[78] = xr;
- a[79] = xi;
-
- xr = a[122];
- xi = a[123];
- yr = a[94];
- yi = a[95];
- a[122] = yr;
- a[123] = yi;
- a[94] = xr;
- a[95] = xi;
-
- xr = a[100];
- xi = a[101];
- yr = a[38];
- yi = a[39];
- a[100] = yr;
- a[101] = yi;
- a[38] = xr;
- a[39] = xi;
-
- xr = a[108];
- xi = a[109];
- yr = a[54];
- yi = a[55];
- a[108] = yr;
- a[109] = yi;
- a[54] = xr;
- a[55] = xi;
-
- xr = a[116];
- xi = a[117];
- yr = a[46];
- yi = a[47];
- a[116] = yr;
- a[117] = yi;
- a[46] = xr;
- a[47] = xi;
-
- xr = a[124];
- xi = a[125];
- yr = a[62];
- yi = a[63];
- a[124] = yr;
- a[125] = yi;
- a[62] = xr;
- a[63] = xi;
-
- xr = a[110];
- xi = a[111];
- yr = a[118];
- yi = a[119];
- a[110] = yr;
- a[111] = yi;
- a[118] = xr;
- a[119] = xi;
-}
-
-static void cft1st_128_mips(float* a) {
- float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14;
- int a_ptr, p1_rdft, p2_rdft, count;
- const float* first = rdft_wk3ri_first;
- const float* second = rdft_wk3ri_second;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- // first 8
- "lwc1 %[f0], 0(%[a]) \n\t"
- "lwc1 %[f1], 4(%[a]) \n\t"
- "lwc1 %[f2], 8(%[a]) \n\t"
- "lwc1 %[f3], 12(%[a]) \n\t"
- "lwc1 %[f4], 16(%[a]) \n\t"
- "lwc1 %[f5], 20(%[a]) \n\t"
- "lwc1 %[f6], 24(%[a]) \n\t"
- "lwc1 %[f7], 28(%[a]) \n\t"
- "add.s %[f8], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f1], %[f3] \n\t"
- "add.s %[f3], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "add.s %[f7], %[f8], %[f2] \n\t"
- "sub.s %[f8], %[f8], %[f2] \n\t"
- "sub.s %[f2], %[f1], %[f4] \n\t"
- "add.s %[f1], %[f1], %[f4] \n\t"
- "add.s %[f4], %[f6], %[f3] \n\t"
- "sub.s %[f6], %[f6], %[f3] \n\t"
- "sub.s %[f3], %[f0], %[f5] \n\t"
- "add.s %[f0], %[f0], %[f5] \n\t"
- "swc1 %[f7], 0(%[a]) \n\t"
- "swc1 %[f8], 16(%[a]) \n\t"
- "swc1 %[f2], 28(%[a]) \n\t"
- "swc1 %[f1], 12(%[a]) \n\t"
- "swc1 %[f4], 4(%[a]) \n\t"
- "swc1 %[f6], 20(%[a]) \n\t"
- "swc1 %[f3], 8(%[a]) \n\t"
- "swc1 %[f0], 24(%[a]) \n\t"
- // second 8
- "lwc1 %[f0], 32(%[a]) \n\t"
- "lwc1 %[f1], 36(%[a]) \n\t"
- "lwc1 %[f2], 40(%[a]) \n\t"
- "lwc1 %[f3], 44(%[a]) \n\t"
- "lwc1 %[f4], 48(%[a]) \n\t"
- "lwc1 %[f5], 52(%[a]) \n\t"
- "lwc1 %[f6], 56(%[a]) \n\t"
- "lwc1 %[f7], 60(%[a]) \n\t"
- "add.s %[f8], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f1], %[f3] \n\t"
- "add.s %[f3], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "add.s %[f7], %[f4], %[f1] \n\t"
- "sub.s %[f4], %[f4], %[f1] \n\t"
- "add.s %[f1], %[f3], %[f8] \n\t"
- "sub.s %[f3], %[f3], %[f8] \n\t"
- "sub.s %[f8], %[f0], %[f5] \n\t"
- "add.s %[f0], %[f0], %[f5] \n\t"
- "add.s %[f5], %[f6], %[f2] \n\t"
- "sub.s %[f6], %[f2], %[f6] \n\t"
- "lwc1 %[f9], 8(%[rdft_w]) \n\t"
- "sub.s %[f2], %[f8], %[f7] \n\t"
- "add.s %[f8], %[f8], %[f7] \n\t"
- "sub.s %[f7], %[f4], %[f0] \n\t"
- "add.s %[f4], %[f4], %[f0] \n\t"
- // prepare for loop
- "addiu %[a_ptr], %[a], 64 \n\t"
- "addiu %[p1_rdft], %[rdft_w], 8 \n\t"
- "addiu %[p2_rdft], %[rdft_w], 16 \n\t"
- "addiu %[count], $zero, 7 \n\t"
- // finish second 8
- "mul.s %[f2], %[f9], %[f2] \n\t"
- "mul.s %[f8], %[f9], %[f8] \n\t"
- "mul.s %[f7], %[f9], %[f7] \n\t"
- "mul.s %[f4], %[f9], %[f4] \n\t"
- "swc1 %[f1], 32(%[a]) \n\t"
- "swc1 %[f3], 52(%[a]) \n\t"
- "swc1 %[f5], 36(%[a]) \n\t"
- "swc1 %[f6], 48(%[a]) \n\t"
- "swc1 %[f2], 40(%[a]) \n\t"
- "swc1 %[f8], 44(%[a]) \n\t"
- "swc1 %[f7], 56(%[a]) \n\t"
- "swc1 %[f4], 60(%[a]) \n\t"
- // loop
- "1: \n\t"
- "lwc1 %[f0], 0(%[a_ptr]) \n\t"
- "lwc1 %[f1], 4(%[a_ptr]) \n\t"
- "lwc1 %[f2], 8(%[a_ptr]) \n\t"
- "lwc1 %[f3], 12(%[a_ptr]) \n\t"
- "lwc1 %[f4], 16(%[a_ptr]) \n\t"
- "lwc1 %[f5], 20(%[a_ptr]) \n\t"
- "lwc1 %[f6], 24(%[a_ptr]) \n\t"
- "lwc1 %[f7], 28(%[a_ptr]) \n\t"
- "add.s %[f8], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f1], %[f3] \n\t"
- "add.s %[f3], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "lwc1 %[f10], 4(%[p1_rdft]) \n\t"
- "lwc1 %[f11], 0(%[p2_rdft]) \n\t"
- "lwc1 %[f12], 4(%[p2_rdft]) \n\t"
- "lwc1 %[f13], 8(%[first]) \n\t"
- "lwc1 %[f14], 12(%[first]) \n\t"
- "add.s %[f7], %[f8], %[f2] \n\t"
- "sub.s %[f8], %[f8], %[f2] \n\t"
- "add.s %[f2], %[f6], %[f3] \n\t"
- "sub.s %[f6], %[f6], %[f3] \n\t"
- "add.s %[f3], %[f0], %[f5] \n\t"
- "sub.s %[f0], %[f0], %[f5] \n\t"
- "add.s %[f5], %[f1], %[f4] \n\t"
- "sub.s %[f1], %[f1], %[f4] \n\t"
- "swc1 %[f7], 0(%[a_ptr]) \n\t"
- "swc1 %[f2], 4(%[a_ptr]) \n\t"
- "mul.s %[f4], %[f9], %[f8] \n\t"
-#if defined(MIPS32_R2_LE)
- "mul.s %[f8], %[f10], %[f8] \n\t"
- "mul.s %[f7], %[f11], %[f0] \n\t"
- "mul.s %[f0], %[f12], %[f0] \n\t"
- "mul.s %[f2], %[f13], %[f3] \n\t"
- "mul.s %[f3], %[f14], %[f3] \n\t"
- "nmsub.s %[f4], %[f4], %[f10], %[f6] \n\t"
- "madd.s %[f8], %[f8], %[f9], %[f6] \n\t"
- "nmsub.s %[f7], %[f7], %[f12], %[f5] \n\t"
- "madd.s %[f0], %[f0], %[f11], %[f5] \n\t"
- "nmsub.s %[f2], %[f2], %[f14], %[f1] \n\t"
- "madd.s %[f3], %[f3], %[f13], %[f1] \n\t"
-#else
- "mul.s %[f7], %[f10], %[f6] \n\t"
- "mul.s %[f6], %[f9], %[f6] \n\t"
- "mul.s %[f8], %[f10], %[f8] \n\t"
- "mul.s %[f2], %[f11], %[f0] \n\t"
- "mul.s %[f11], %[f11], %[f5] \n\t"
- "mul.s %[f5], %[f12], %[f5] \n\t"
- "mul.s %[f0], %[f12], %[f0] \n\t"
- "mul.s %[f12], %[f13], %[f3] \n\t"
- "mul.s %[f13], %[f13], %[f1] \n\t"
- "mul.s %[f1], %[f14], %[f1] \n\t"
- "mul.s %[f3], %[f14], %[f3] \n\t"
- "sub.s %[f4], %[f4], %[f7] \n\t"
- "add.s %[f8], %[f6], %[f8] \n\t"
- "sub.s %[f7], %[f2], %[f5] \n\t"
- "add.s %[f0], %[f11], %[f0] \n\t"
- "sub.s %[f2], %[f12], %[f1] \n\t"
- "add.s %[f3], %[f13], %[f3] \n\t"
-#endif
- "swc1 %[f4], 16(%[a_ptr]) \n\t"
- "swc1 %[f8], 20(%[a_ptr]) \n\t"
- "swc1 %[f7], 8(%[a_ptr]) \n\t"
- "swc1 %[f0], 12(%[a_ptr]) \n\t"
- "swc1 %[f2], 24(%[a_ptr]) \n\t"
- "swc1 %[f3], 28(%[a_ptr]) \n\t"
- "lwc1 %[f0], 32(%[a_ptr]) \n\t"
- "lwc1 %[f1], 36(%[a_ptr]) \n\t"
- "lwc1 %[f2], 40(%[a_ptr]) \n\t"
- "lwc1 %[f3], 44(%[a_ptr]) \n\t"
- "lwc1 %[f4], 48(%[a_ptr]) \n\t"
- "lwc1 %[f5], 52(%[a_ptr]) \n\t"
- "lwc1 %[f6], 56(%[a_ptr]) \n\t"
- "lwc1 %[f7], 60(%[a_ptr]) \n\t"
- "add.s %[f8], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f1], %[f3] \n\t"
- "add.s %[f3], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "lwc1 %[f11], 8(%[p2_rdft]) \n\t"
- "lwc1 %[f12], 12(%[p2_rdft]) \n\t"
- "lwc1 %[f13], 8(%[second]) \n\t"
- "lwc1 %[f14], 12(%[second]) \n\t"
- "add.s %[f7], %[f8], %[f2] \n\t"
- "sub.s %[f8], %[f2], %[f8] \n\t"
- "add.s %[f2], %[f6], %[f3] \n\t"
- "sub.s %[f6], %[f3], %[f6] \n\t"
- "add.s %[f3], %[f0], %[f5] \n\t"
- "sub.s %[f0], %[f0], %[f5] \n\t"
- "add.s %[f5], %[f1], %[f4] \n\t"
- "sub.s %[f1], %[f1], %[f4] \n\t"
- "swc1 %[f7], 32(%[a_ptr]) \n\t"
- "swc1 %[f2], 36(%[a_ptr]) \n\t"
- "mul.s %[f4], %[f10], %[f8] \n\t"
-#if defined(MIPS32_R2_LE)
- "mul.s %[f10], %[f10], %[f6] \n\t"
- "mul.s %[f7], %[f11], %[f0] \n\t"
- "mul.s %[f11], %[f11], %[f5] \n\t"
- "mul.s %[f2], %[f13], %[f3] \n\t"
- "mul.s %[f13], %[f13], %[f1] \n\t"
- "madd.s %[f4], %[f4], %[f9], %[f6] \n\t"
- "nmsub.s %[f10], %[f10], %[f9], %[f8] \n\t"
- "nmsub.s %[f7], %[f7], %[f12], %[f5] \n\t"
- "madd.s %[f11], %[f11], %[f12], %[f0] \n\t"
- "nmsub.s %[f2], %[f2], %[f14], %[f1] \n\t"
- "madd.s %[f13], %[f13], %[f14], %[f3] \n\t"
-#else
- "mul.s %[f2], %[f9], %[f6] \n\t"
- "mul.s %[f10], %[f10], %[f6] \n\t"
- "mul.s %[f9], %[f9], %[f8] \n\t"
- "mul.s %[f7], %[f11], %[f0] \n\t"
- "mul.s %[f8], %[f12], %[f5] \n\t"
- "mul.s %[f11], %[f11], %[f5] \n\t"
- "mul.s %[f12], %[f12], %[f0] \n\t"
- "mul.s %[f5], %[f13], %[f3] \n\t"
- "mul.s %[f0], %[f14], %[f1] \n\t"
- "mul.s %[f13], %[f13], %[f1] \n\t"
- "mul.s %[f14], %[f14], %[f3] \n\t"
- "add.s %[f4], %[f4], %[f2] \n\t"
- "sub.s %[f10], %[f10], %[f9] \n\t"
- "sub.s %[f7], %[f7], %[f8] \n\t"
- "add.s %[f11], %[f11], %[f12] \n\t"
- "sub.s %[f2], %[f5], %[f0] \n\t"
- "add.s %[f13], %[f13], %[f14] \n\t"
-#endif
- "swc1 %[f4], 48(%[a_ptr]) \n\t"
- "swc1 %[f10], 52(%[a_ptr]) \n\t"
- "swc1 %[f7], 40(%[a_ptr]) \n\t"
- "swc1 %[f11], 44(%[a_ptr]) \n\t"
- "swc1 %[f2], 56(%[a_ptr]) \n\t"
- "swc1 %[f13], 60(%[a_ptr]) \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "lwc1 %[f9], 8(%[p1_rdft]) \n\t"
- "addiu %[a_ptr], %[a_ptr], 64 \n\t"
- "addiu %[p1_rdft], %[p1_rdft], 8 \n\t"
- "addiu %[p2_rdft], %[p2_rdft], 16 \n\t"
- "addiu %[first], %[first], 8 \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[second], %[second], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
- [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
- [f8] "=&f" (f8), [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11),
- [f12] "=&f" (f12), [f13] "=&f" (f13), [f14] "=&f" (f14),
- [a_ptr] "=&r" (a_ptr), [p1_rdft] "=&r" (p1_rdft), [first] "+r" (first),
- [p2_rdft] "=&r" (p2_rdft), [count] "=&r" (count), [second] "+r" (second)
- : [a] "r" (a), [rdft_w] "r" (rdft_w)
- : "memory"
- );
-}
-
-static void cftmdl_128_mips(float* a) {
- float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14;
- int tmp_a, count;
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[tmp_a], %[a], 0 \n\t"
- "addiu %[count], $zero, 4 \n\t"
- "1: \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "lwc1 %[f0], 0(%[tmp_a]) \n\t"
- "lwc1 %[f2], 32(%[tmp_a]) \n\t"
- "lwc1 %[f4], 64(%[tmp_a]) \n\t"
- "lwc1 %[f6], 96(%[tmp_a]) \n\t"
- "lwc1 %[f1], 4(%[tmp_a]) \n\t"
- "lwc1 %[f3], 36(%[tmp_a]) \n\t"
- "lwc1 %[f5], 68(%[tmp_a]) \n\t"
- "lwc1 %[f7], 100(%[tmp_a]) \n\t"
- "add.s %[f8], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f1], %[f3] \n\t"
- "add.s %[f3], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "add.s %[f7], %[f8], %[f2] \n\t"
- "sub.s %[f8], %[f8], %[f2] \n\t"
- "add.s %[f2], %[f1], %[f4] \n\t"
- "sub.s %[f1], %[f1], %[f4] \n\t"
- "add.s %[f4], %[f6], %[f3] \n\t"
- "sub.s %[f6], %[f6], %[f3] \n\t"
- "sub.s %[f3], %[f0], %[f5] \n\t"
- "add.s %[f0], %[f0], %[f5] \n\t"
- "swc1 %[f7], 0(%[tmp_a]) \n\t"
- "swc1 %[f8], 64(%[tmp_a]) \n\t"
- "swc1 %[f2], 36(%[tmp_a]) \n\t"
- "swc1 %[f1], 100(%[tmp_a]) \n\t"
- "swc1 %[f4], 4(%[tmp_a]) \n\t"
- "swc1 %[f6], 68(%[tmp_a]) \n\t"
- "swc1 %[f3], 32(%[tmp_a]) \n\t"
- "swc1 %[f0], 96(%[tmp_a]) \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[tmp_a], %[tmp_a], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
- [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
- [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
- : [a] "r" (a)
- : "memory"
- );
- f9 = rdft_w[2];
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[tmp_a], %[a], 128 \n\t"
- "addiu %[count], $zero, 4 \n\t"
- "1: \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "lwc1 %[f0], 0(%[tmp_a]) \n\t"
- "lwc1 %[f2], 32(%[tmp_a]) \n\t"
- "lwc1 %[f5], 68(%[tmp_a]) \n\t"
- "lwc1 %[f7], 100(%[tmp_a]) \n\t"
- "lwc1 %[f1], 4(%[tmp_a]) \n\t"
- "lwc1 %[f3], 36(%[tmp_a]) \n\t"
- "lwc1 %[f4], 64(%[tmp_a]) \n\t"
- "lwc1 %[f6], 96(%[tmp_a]) \n\t"
- "sub.s %[f8], %[f0], %[f2] \n\t"
- "add.s %[f0], %[f0], %[f2] \n\t"
- "sub.s %[f2], %[f5], %[f7] \n\t"
- "add.s %[f5], %[f5], %[f7] \n\t"
- "sub.s %[f7], %[f1], %[f3] \n\t"
- "add.s %[f1], %[f1], %[f3] \n\t"
- "sub.s %[f3], %[f4], %[f6] \n\t"
- "add.s %[f4], %[f4], %[f6] \n\t"
- "sub.s %[f6], %[f8], %[f2] \n\t"
- "add.s %[f8], %[f8], %[f2] \n\t"
- "add.s %[f2], %[f5], %[f1] \n\t"
- "sub.s %[f5], %[f5], %[f1] \n\t"
- "add.s %[f1], %[f3], %[f7] \n\t"
- "sub.s %[f3], %[f3], %[f7] \n\t"
- "add.s %[f7], %[f0], %[f4] \n\t"
- "sub.s %[f0], %[f0], %[f4] \n\t"
- "sub.s %[f4], %[f6], %[f1] \n\t"
- "add.s %[f6], %[f6], %[f1] \n\t"
- "sub.s %[f1], %[f3], %[f8] \n\t"
- "add.s %[f3], %[f3], %[f8] \n\t"
- "mul.s %[f4], %[f4], %[f9] \n\t"
- "mul.s %[f6], %[f6], %[f9] \n\t"
- "mul.s %[f1], %[f1], %[f9] \n\t"
- "mul.s %[f3], %[f3], %[f9] \n\t"
- "swc1 %[f7], 0(%[tmp_a]) \n\t"
- "swc1 %[f2], 4(%[tmp_a]) \n\t"
- "swc1 %[f5], 64(%[tmp_a]) \n\t"
- "swc1 %[f0], 68(%[tmp_a]) \n\t"
- "swc1 %[f4], 32(%[tmp_a]) \n\t"
- "swc1 %[f6], 36(%[tmp_a]) \n\t"
- "swc1 %[f1], 96(%[tmp_a]) \n\t"
- "swc1 %[f3], 100(%[tmp_a]) \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[tmp_a], %[tmp_a], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
- [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
- [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
- : [a] "r" (a), [f9] "f" (f9)
- : "memory"
- );
- f10 = rdft_w[3];
- f11 = rdft_w[4];
- f12 = rdft_w[5];
- f13 = rdft_wk3ri_first[2];
- f14 = rdft_wk3ri_first[3];
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[tmp_a], %[a], 256 \n\t"
- "addiu %[count], $zero, 4 \n\t"
- "1: \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "lwc1 %[f0], 0(%[tmp_a]) \n\t"
- "lwc1 %[f2], 32(%[tmp_a]) \n\t"
- "lwc1 %[f4], 64(%[tmp_a]) \n\t"
- "lwc1 %[f6], 96(%[tmp_a]) \n\t"
- "lwc1 %[f1], 4(%[tmp_a]) \n\t"
- "lwc1 %[f3], 36(%[tmp_a]) \n\t"
- "lwc1 %[f5], 68(%[tmp_a]) \n\t"
- "lwc1 %[f7], 100(%[tmp_a]) \n\t"
- "add.s %[f8], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f1], %[f3] \n\t"
- "add.s %[f3], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "sub.s %[f7], %[f8], %[f2] \n\t"
- "add.s %[f8], %[f8], %[f2] \n\t"
- "add.s %[f2], %[f1], %[f4] \n\t"
- "sub.s %[f1], %[f1], %[f4] \n\t"
- "sub.s %[f4], %[f6], %[f3] \n\t"
- "add.s %[f6], %[f6], %[f3] \n\t"
- "sub.s %[f3], %[f0], %[f5] \n\t"
- "add.s %[f0], %[f0], %[f5] \n\t"
- "swc1 %[f8], 0(%[tmp_a]) \n\t"
- "swc1 %[f6], 4(%[tmp_a]) \n\t"
- "mul.s %[f5], %[f9], %[f7] \n\t"
-#if defined(MIPS32_R2_LE)
- "mul.s %[f7], %[f10], %[f7] \n\t"
- "mul.s %[f8], %[f11], %[f3] \n\t"
- "mul.s %[f3], %[f12], %[f3] \n\t"
- "mul.s %[f6], %[f13], %[f0] \n\t"
- "mul.s %[f0], %[f14], %[f0] \n\t"
- "nmsub.s %[f5], %[f5], %[f10], %[f4] \n\t"
- "madd.s %[f7], %[f7], %[f9], %[f4] \n\t"
- "nmsub.s %[f8], %[f8], %[f12], %[f2] \n\t"
- "madd.s %[f3], %[f3], %[f11], %[f2] \n\t"
- "nmsub.s %[f6], %[f6], %[f14], %[f1] \n\t"
- "madd.s %[f0], %[f0], %[f13], %[f1] \n\t"
- "swc1 %[f5], 64(%[tmp_a]) \n\t"
- "swc1 %[f7], 68(%[tmp_a]) \n\t"
-#else
- "mul.s %[f8], %[f10], %[f4] \n\t"
- "mul.s %[f4], %[f9], %[f4] \n\t"
- "mul.s %[f7], %[f10], %[f7] \n\t"
- "mul.s %[f6], %[f11], %[f3] \n\t"
- "mul.s %[f3], %[f12], %[f3] \n\t"
- "sub.s %[f5], %[f5], %[f8] \n\t"
- "mul.s %[f8], %[f12], %[f2] \n\t"
- "mul.s %[f2], %[f11], %[f2] \n\t"
- "add.s %[f7], %[f4], %[f7] \n\t"
- "mul.s %[f4], %[f13], %[f0] \n\t"
- "mul.s %[f0], %[f14], %[f0] \n\t"
- "sub.s %[f8], %[f6], %[f8] \n\t"
- "mul.s %[f6], %[f14], %[f1] \n\t"
- "mul.s %[f1], %[f13], %[f1] \n\t"
- "add.s %[f3], %[f2], %[f3] \n\t"
- "swc1 %[f5], 64(%[tmp_a]) \n\t"
- "swc1 %[f7], 68(%[tmp_a]) \n\t"
- "sub.s %[f6], %[f4], %[f6] \n\t"
- "add.s %[f0], %[f1], %[f0] \n\t"
-#endif
- "swc1 %[f8], 32(%[tmp_a]) \n\t"
- "swc1 %[f3], 36(%[tmp_a]) \n\t"
- "swc1 %[f6], 96(%[tmp_a]) \n\t"
- "swc1 %[f0], 100(%[tmp_a]) \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[tmp_a], %[tmp_a], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
- [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
- [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
- : [a] "r" (a), [f9] "f" (f9), [f10] "f" (f10), [f11] "f" (f11),
- [f12] "f" (f12), [f13] "f" (f13), [f14] "f" (f14)
- : "memory"
- );
- f11 = rdft_w[6];
- f12 = rdft_w[7];
- f13 = rdft_wk3ri_second[2];
- f14 = rdft_wk3ri_second[3];
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[tmp_a], %[a], 384 \n\t"
- "addiu %[count], $zero, 4 \n\t"
- "1: \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "lwc1 %[f0], 0(%[tmp_a]) \n\t"
- "lwc1 %[f1], 4(%[tmp_a]) \n\t"
- "lwc1 %[f2], 32(%[tmp_a]) \n\t"
- "lwc1 %[f3], 36(%[tmp_a]) \n\t"
- "lwc1 %[f4], 64(%[tmp_a]) \n\t"
- "lwc1 %[f5], 68(%[tmp_a]) \n\t"
- "lwc1 %[f6], 96(%[tmp_a]) \n\t"
- "lwc1 %[f7], 100(%[tmp_a]) \n\t"
- "add.s %[f8], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f1], %[f3] \n\t"
- "add.s %[f3], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "sub.s %[f7], %[f2], %[f8] \n\t"
- "add.s %[f2], %[f2], %[f8] \n\t"
- "add.s %[f8], %[f1], %[f4] \n\t"
- "sub.s %[f1], %[f1], %[f4] \n\t"
- "sub.s %[f4], %[f3], %[f6] \n\t"
- "add.s %[f3], %[f3], %[f6] \n\t"
- "sub.s %[f6], %[f0], %[f5] \n\t"
- "add.s %[f0], %[f0], %[f5] \n\t"
- "swc1 %[f2], 0(%[tmp_a]) \n\t"
- "swc1 %[f3], 4(%[tmp_a]) \n\t"
- "mul.s %[f5], %[f10], %[f7] \n\t"
-#if defined(MIPS32_R2_LE)
- "mul.s %[f7], %[f9], %[f7] \n\t"
- "mul.s %[f2], %[f12], %[f8] \n\t"
- "mul.s %[f8], %[f11], %[f8] \n\t"
- "mul.s %[f3], %[f14], %[f1] \n\t"
- "mul.s %[f1], %[f13], %[f1] \n\t"
- "madd.s %[f5], %[f5], %[f9], %[f4] \n\t"
- "msub.s %[f7], %[f7], %[f10], %[f4] \n\t"
- "msub.s %[f2], %[f2], %[f11], %[f6] \n\t"
- "madd.s %[f8], %[f8], %[f12], %[f6] \n\t"
- "msub.s %[f3], %[f3], %[f13], %[f0] \n\t"
- "madd.s %[f1], %[f1], %[f14], %[f0] \n\t"
- "swc1 %[f5], 64(%[tmp_a]) \n\t"
- "swc1 %[f7], 68(%[tmp_a]) \n\t"
-#else
- "mul.s %[f2], %[f9], %[f4] \n\t"
- "mul.s %[f4], %[f10], %[f4] \n\t"
- "mul.s %[f7], %[f9], %[f7] \n\t"
- "mul.s %[f3], %[f11], %[f6] \n\t"
- "mul.s %[f6], %[f12], %[f6] \n\t"
- "add.s %[f5], %[f5], %[f2] \n\t"
- "sub.s %[f7], %[f4], %[f7] \n\t"
- "mul.s %[f2], %[f12], %[f8] \n\t"
- "mul.s %[f8], %[f11], %[f8] \n\t"
- "mul.s %[f4], %[f14], %[f1] \n\t"
- "mul.s %[f1], %[f13], %[f1] \n\t"
- "sub.s %[f2], %[f3], %[f2] \n\t"
- "mul.s %[f3], %[f13], %[f0] \n\t"
- "mul.s %[f0], %[f14], %[f0] \n\t"
- "add.s %[f8], %[f8], %[f6] \n\t"
- "swc1 %[f5], 64(%[tmp_a]) \n\t"
- "swc1 %[f7], 68(%[tmp_a]) \n\t"
- "sub.s %[f3], %[f3], %[f4] \n\t"
- "add.s %[f1], %[f1], %[f0] \n\t"
-#endif
- "swc1 %[f2], 32(%[tmp_a]) \n\t"
- "swc1 %[f8], 36(%[tmp_a]) \n\t"
- "swc1 %[f3], 96(%[tmp_a]) \n\t"
- "swc1 %[f1], 100(%[tmp_a]) \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[tmp_a], %[tmp_a], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
- [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
- [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
- : [a] "r" (a), [f9] "f" (f9), [f10] "f" (f10), [f11] "f" (f11),
- [f12] "f" (f12), [f13] "f" (f13), [f14] "f" (f14)
- : "memory"
- );
-}
-
-static void cftfsub_128_mips(float* a) {
- float f0, f1, f2, f3, f4, f5, f6, f7, f8;
- int tmp_a, count;
-
- cft1st_128(a);
- cftmdl_128(a);
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[tmp_a], %[a], 0 \n\t"
- "addiu %[count], $zero, 16 \n\t"
- "1: \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "lwc1 %[f0], 0(%[tmp_a]) \n\t"
- "lwc1 %[f2], 128(%[tmp_a]) \n\t"
- "lwc1 %[f4], 256(%[tmp_a]) \n\t"
- "lwc1 %[f6], 384(%[tmp_a]) \n\t"
- "lwc1 %[f1], 4(%[tmp_a]) \n\t"
- "lwc1 %[f3], 132(%[tmp_a]) \n\t"
- "lwc1 %[f5], 260(%[tmp_a]) \n\t"
- "lwc1 %[f7], 388(%[tmp_a]) \n\t"
- "add.s %[f8], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f1], %[f3] \n\t"
- "add.s %[f3], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "add.s %[f7], %[f8], %[f2] \n\t"
- "sub.s %[f8], %[f8], %[f2] \n\t"
- "add.s %[f2], %[f1], %[f4] \n\t"
- "sub.s %[f1], %[f1], %[f4] \n\t"
- "add.s %[f4], %[f6], %[f3] \n\t"
- "sub.s %[f6], %[f6], %[f3] \n\t"
- "sub.s %[f3], %[f0], %[f5] \n\t"
- "add.s %[f0], %[f0], %[f5] \n\t"
- "swc1 %[f7], 0(%[tmp_a]) \n\t"
- "swc1 %[f8], 256(%[tmp_a]) \n\t"
- "swc1 %[f2], 132(%[tmp_a]) \n\t"
- "swc1 %[f1], 388(%[tmp_a]) \n\t"
- "swc1 %[f4], 4(%[tmp_a]) \n\t"
- "swc1 %[f6], 260(%[tmp_a]) \n\t"
- "swc1 %[f3], 128(%[tmp_a]) \n\t"
- "swc1 %[f0], 384(%[tmp_a]) \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[tmp_a], %[tmp_a], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
- [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
- [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a),
- [count] "=&r" (count)
- : [a] "r" (a)
- : "memory"
- );
-}
-
-static void cftbsub_128_mips(float* a) {
- float f0, f1, f2, f3, f4, f5, f6, f7, f8;
- int tmp_a, count;
-
- cft1st_128(a);
- cftmdl_128(a);
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[tmp_a], %[a], 0 \n\t"
- "addiu %[count], $zero, 16 \n\t"
- "1: \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "lwc1 %[f0], 0(%[tmp_a]) \n\t"
- "lwc1 %[f2], 128(%[tmp_a]) \n\t"
- "lwc1 %[f4], 256(%[tmp_a]) \n\t"
- "lwc1 %[f6], 384(%[tmp_a]) \n\t"
- "lwc1 %[f1], 4(%[tmp_a]) \n\t"
- "lwc1 %[f3], 132(%[tmp_a]) \n\t"
- "lwc1 %[f5], 260(%[tmp_a]) \n\t"
- "lwc1 %[f7], 388(%[tmp_a]) \n\t"
- "add.s %[f8], %[f0], %[f2] \n\t"
- "sub.s %[f0], %[f0], %[f2] \n\t"
- "add.s %[f2], %[f4], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "add.s %[f6], %[f1], %[f3] \n\t"
- "sub.s %[f1], %[f3], %[f1] \n\t"
- "add.s %[f3], %[f5], %[f7] \n\t"
- "sub.s %[f5], %[f5], %[f7] \n\t"
- "add.s %[f7], %[f8], %[f2] \n\t"
- "sub.s %[f8], %[f8], %[f2] \n\t"
- "sub.s %[f2], %[f1], %[f4] \n\t"
- "add.s %[f1], %[f1], %[f4] \n\t"
- "add.s %[f4], %[f3], %[f6] \n\t"
- "sub.s %[f6], %[f3], %[f6] \n\t"
- "sub.s %[f3], %[f0], %[f5] \n\t"
- "add.s %[f0], %[f0], %[f5] \n\t"
- "neg.s %[f4], %[f4] \n\t"
- "swc1 %[f7], 0(%[tmp_a]) \n\t"
- "swc1 %[f8], 256(%[tmp_a]) \n\t"
- "swc1 %[f2], 132(%[tmp_a]) \n\t"
- "swc1 %[f1], 388(%[tmp_a]) \n\t"
- "swc1 %[f6], 260(%[tmp_a]) \n\t"
- "swc1 %[f3], 128(%[tmp_a]) \n\t"
- "swc1 %[f0], 384(%[tmp_a]) \n\t"
- "swc1 %[f4], 4(%[tmp_a]) \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[tmp_a], %[tmp_a], 8 \n\t"
- ".set pop \n\t"
- : [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3),
- [f4] "=&f" (f4), [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7),
- [f8] "=&f" (f8), [tmp_a] "=&r" (tmp_a), [count] "=&r" (count)
- : [a] "r" (a)
- : "memory"
- );
-}
-
-static void rftfsub_128_mips(float* a) {
- const float* c = rdft_w + 32;
- const float f0 = 0.5f;
- float* a1 = &a[2];
- float* a2 = &a[126];
- const float* c1 = &c[1];
- const float* c2 = &c[31];
- float f1, f2, f3 ,f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
- int count;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "lwc1 %[f6], 0(%[c2]) \n\t"
- "lwc1 %[f1], 0(%[a1]) \n\t"
- "lwc1 %[f2], 0(%[a2]) \n\t"
- "lwc1 %[f3], 4(%[a1]) \n\t"
- "lwc1 %[f4], 4(%[a2]) \n\t"
- "lwc1 %[f5], 0(%[c1]) \n\t"
- "sub.s %[f6], %[f0], %[f6] \n\t"
- "sub.s %[f7], %[f1], %[f2] \n\t"
- "add.s %[f8], %[f3], %[f4] \n\t"
- "addiu %[count], $zero, 15 \n\t"
- "mul.s %[f9], %[f6], %[f7] \n\t"
- "mul.s %[f6], %[f6], %[f8] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f8], %[f5], %[f8] \n\t"
- "mul.s %[f5], %[f5], %[f7] \n\t"
- "sub.s %[f9], %[f9], %[f8] \n\t"
- "add.s %[f6], %[f6], %[f5] \n\t"
-#else
- "nmsub.s %[f9], %[f9], %[f5], %[f8] \n\t"
- "madd.s %[f6], %[f6], %[f5], %[f7] \n\t"
-#endif
- "sub.s %[f1], %[f1], %[f9] \n\t"
- "add.s %[f2], %[f2], %[f9] \n\t"
- "sub.s %[f3], %[f3], %[f6] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "swc1 %[f1], 0(%[a1]) \n\t"
- "swc1 %[f2], 0(%[a2]) \n\t"
- "swc1 %[f3], 4(%[a1]) \n\t"
- "swc1 %[f4], 4(%[a2]) \n\t"
- "addiu %[a1], %[a1], 8 \n\t"
- "addiu %[a2], %[a2], -8 \n\t"
- "addiu %[c1], %[c1], 4 \n\t"
- "addiu %[c2], %[c2], -4 \n\t"
- "1: \n\t"
- "lwc1 %[f6], 0(%[c2]) \n\t"
- "lwc1 %[f1], 0(%[a1]) \n\t"
- "lwc1 %[f2], 0(%[a2]) \n\t"
- "lwc1 %[f3], 4(%[a1]) \n\t"
- "lwc1 %[f4], 4(%[a2]) \n\t"
- "lwc1 %[f5], 0(%[c1]) \n\t"
- "sub.s %[f6], %[f0], %[f6] \n\t"
- "sub.s %[f7], %[f1], %[f2] \n\t"
- "add.s %[f8], %[f3], %[f4] \n\t"
- "lwc1 %[f10], -4(%[c2]) \n\t"
- "lwc1 %[f11], 8(%[a1]) \n\t"
- "lwc1 %[f12], -8(%[a2]) \n\t"
- "mul.s %[f9], %[f6], %[f7] \n\t"
- "mul.s %[f6], %[f6], %[f8] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f8], %[f5], %[f8] \n\t"
- "mul.s %[f5], %[f5], %[f7] \n\t"
- "lwc1 %[f13], 12(%[a1]) \n\t"
- "lwc1 %[f14], -4(%[a2]) \n\t"
- "lwc1 %[f15], 4(%[c1]) \n\t"
- "sub.s %[f9], %[f9], %[f8] \n\t"
- "add.s %[f6], %[f6], %[f5] \n\t"
-#else
- "lwc1 %[f13], 12(%[a1]) \n\t"
- "lwc1 %[f14], -4(%[a2]) \n\t"
- "lwc1 %[f15], 4(%[c1]) \n\t"
- "nmsub.s %[f9], %[f9], %[f5], %[f8] \n\t"
- "madd.s %[f6], %[f6], %[f5], %[f7] \n\t"
-#endif
- "sub.s %[f10], %[f0], %[f10] \n\t"
- "sub.s %[f5], %[f11], %[f12] \n\t"
- "add.s %[f7], %[f13], %[f14] \n\t"
- "sub.s %[f1], %[f1], %[f9] \n\t"
- "add.s %[f2], %[f2], %[f9] \n\t"
- "sub.s %[f3], %[f3], %[f6] \n\t"
- "mul.s %[f8], %[f10], %[f5] \n\t"
- "mul.s %[f10], %[f10], %[f7] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f9], %[f15], %[f7] \n\t"
- "mul.s %[f15], %[f15], %[f5] \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "swc1 %[f1], 0(%[a1]) \n\t"
- "swc1 %[f2], 0(%[a2]) \n\t"
- "sub.s %[f8], %[f8], %[f9] \n\t"
- "add.s %[f10], %[f10], %[f15] \n\t"
-#else
- "swc1 %[f1], 0(%[a1]) \n\t"
- "swc1 %[f2], 0(%[a2]) \n\t"
- "sub.s %[f4], %[f4], %[f6] \n\t"
- "nmsub.s %[f8], %[f8], %[f15], %[f7] \n\t"
- "madd.s %[f10], %[f10], %[f15], %[f5] \n\t"
-#endif
- "swc1 %[f3], 4(%[a1]) \n\t"
- "swc1 %[f4], 4(%[a2]) \n\t"
- "sub.s %[f11], %[f11], %[f8] \n\t"
- "add.s %[f12], %[f12], %[f8] \n\t"
- "sub.s %[f13], %[f13], %[f10] \n\t"
- "sub.s %[f14], %[f14], %[f10] \n\t"
- "addiu %[c2], %[c2], -8 \n\t"
- "addiu %[c1], %[c1], 8 \n\t"
- "swc1 %[f11], 8(%[a1]) \n\t"
- "swc1 %[f12], -8(%[a2]) \n\t"
- "swc1 %[f13], 12(%[a1]) \n\t"
- "swc1 %[f14], -4(%[a2]) \n\t"
- "addiu %[a1], %[a1], 16 \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[a2], %[a2], -16 \n\t"
- ".set pop \n\t"
- : [a1] "+r" (a1), [a2] "+r" (a2), [c1] "+r" (c1), [c2] "+r" (c2),
- [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3), [f4] "=&f" (f4),
- [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
- [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11), [f12] "=&f" (f12),
- [f13] "=&f" (f13), [f14] "=&f" (f14), [f15] "=&f" (f15),
- [count] "=&r" (count)
- : [f0] "f" (f0)
- : "memory"
- );
-}
-
-static void rftbsub_128_mips(float* a) {
- const float *c = rdft_w + 32;
- const float f0 = 0.5f;
- float* a1 = &a[2];
- float* a2 = &a[126];
- const float* c1 = &c[1];
- const float* c2 = &c[31];
- float f1, f2, f3 ,f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
- int count;
-
- a[1] = -a[1];
- a[65] = -a[65];
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "lwc1 %[f6], 0(%[c2]) \n\t"
- "lwc1 %[f1], 0(%[a1]) \n\t"
- "lwc1 %[f2], 0(%[a2]) \n\t"
- "lwc1 %[f3], 4(%[a1]) \n\t"
- "lwc1 %[f4], 4(%[a2]) \n\t"
- "lwc1 %[f5], 0(%[c1]) \n\t"
- "sub.s %[f6], %[f0], %[f6] \n\t"
- "sub.s %[f7], %[f1], %[f2] \n\t"
- "add.s %[f8], %[f3], %[f4] \n\t"
- "addiu %[count], $zero, 15 \n\t"
- "mul.s %[f9], %[f6], %[f7] \n\t"
- "mul.s %[f6], %[f6], %[f8] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f8], %[f5], %[f8] \n\t"
- "mul.s %[f5], %[f5], %[f7] \n\t"
- "add.s %[f9], %[f9], %[f8] \n\t"
- "sub.s %[f6], %[f6], %[f5] \n\t"
-#else
- "madd.s %[f9], %[f9], %[f5], %[f8] \n\t"
- "nmsub.s %[f6], %[f6], %[f5], %[f7] \n\t"
-#endif
- "sub.s %[f1], %[f1], %[f9] \n\t"
- "add.s %[f2], %[f2], %[f9] \n\t"
- "sub.s %[f3], %[f6], %[f3] \n\t"
- "sub.s %[f4], %[f6], %[f4] \n\t"
- "swc1 %[f1], 0(%[a1]) \n\t"
- "swc1 %[f2], 0(%[a2]) \n\t"
- "swc1 %[f3], 4(%[a1]) \n\t"
- "swc1 %[f4], 4(%[a2]) \n\t"
- "addiu %[a1], %[a1], 8 \n\t"
- "addiu %[a2], %[a2], -8 \n\t"
- "addiu %[c1], %[c1], 4 \n\t"
- "addiu %[c2], %[c2], -4 \n\t"
- "1: \n\t"
- "lwc1 %[f6], 0(%[c2]) \n\t"
- "lwc1 %[f1], 0(%[a1]) \n\t"
- "lwc1 %[f2], 0(%[a2]) \n\t"
- "lwc1 %[f3], 4(%[a1]) \n\t"
- "lwc1 %[f4], 4(%[a2]) \n\t"
- "lwc1 %[f5], 0(%[c1]) \n\t"
- "sub.s %[f6], %[f0], %[f6] \n\t"
- "sub.s %[f7], %[f1], %[f2] \n\t"
- "add.s %[f8], %[f3], %[f4] \n\t"
- "lwc1 %[f10], -4(%[c2]) \n\t"
- "lwc1 %[f11], 8(%[a1]) \n\t"
- "lwc1 %[f12], -8(%[a2]) \n\t"
- "mul.s %[f9], %[f6], %[f7] \n\t"
- "mul.s %[f6], %[f6], %[f8] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f8], %[f5], %[f8] \n\t"
- "mul.s %[f5], %[f5], %[f7] \n\t"
- "lwc1 %[f13], 12(%[a1]) \n\t"
- "lwc1 %[f14], -4(%[a2]) \n\t"
- "lwc1 %[f15], 4(%[c1]) \n\t"
- "add.s %[f9], %[f9], %[f8] \n\t"
- "sub.s %[f6], %[f6], %[f5] \n\t"
-#else
- "lwc1 %[f13], 12(%[a1]) \n\t"
- "lwc1 %[f14], -4(%[a2]) \n\t"
- "lwc1 %[f15], 4(%[c1]) \n\t"
- "madd.s %[f9], %[f9], %[f5], %[f8] \n\t"
- "nmsub.s %[f6], %[f6], %[f5], %[f7] \n\t"
-#endif
- "sub.s %[f10], %[f0], %[f10] \n\t"
- "sub.s %[f5], %[f11], %[f12] \n\t"
- "add.s %[f7], %[f13], %[f14] \n\t"
- "sub.s %[f1], %[f1], %[f9] \n\t"
- "add.s %[f2], %[f2], %[f9] \n\t"
- "sub.s %[f3], %[f6], %[f3] \n\t"
- "mul.s %[f8], %[f10], %[f5] \n\t"
- "mul.s %[f10], %[f10], %[f7] \n\t"
-#if !defined(MIPS32_R2_LE)
- "mul.s %[f9], %[f15], %[f7] \n\t"
- "mul.s %[f15], %[f15], %[f5] \n\t"
- "sub.s %[f4], %[f6], %[f4] \n\t"
- "swc1 %[f1], 0(%[a1]) \n\t"
- "swc1 %[f2], 0(%[a2]) \n\t"
- "add.s %[f8], %[f8], %[f9] \n\t"
- "sub.s %[f10], %[f10], %[f15] \n\t"
-#else
- "swc1 %[f1], 0(%[a1]) \n\t"
- "swc1 %[f2], 0(%[a2]) \n\t"
- "sub.s %[f4], %[f6], %[f4] \n\t"
- "madd.s %[f8], %[f8], %[f15], %[f7] \n\t"
- "nmsub.s %[f10], %[f10], %[f15], %[f5] \n\t"
-#endif
- "swc1 %[f3], 4(%[a1]) \n\t"
- "swc1 %[f4], 4(%[a2]) \n\t"
- "sub.s %[f11], %[f11], %[f8] \n\t"
- "add.s %[f12], %[f12], %[f8] \n\t"
- "sub.s %[f13], %[f10], %[f13] \n\t"
- "sub.s %[f14], %[f10], %[f14] \n\t"
- "addiu %[c2], %[c2], -8 \n\t"
- "addiu %[c1], %[c1], 8 \n\t"
- "swc1 %[f11], 8(%[a1]) \n\t"
- "swc1 %[f12], -8(%[a2]) \n\t"
- "swc1 %[f13], 12(%[a1]) \n\t"
- "swc1 %[f14], -4(%[a2]) \n\t"
- "addiu %[a1], %[a1], 16 \n\t"
- "addiu %[count], %[count], -1 \n\t"
- "bgtz %[count], 1b \n\t"
- " addiu %[a2], %[a2], -16 \n\t"
- ".set pop \n\t"
- : [a1] "+r" (a1), [a2] "+r" (a2), [c1] "+r" (c1), [c2] "+r" (c2),
- [f1] "=&f" (f1), [f2] "=&f" (f2), [f3] "=&f" (f3), [f4] "=&f" (f4),
- [f5] "=&f" (f5), [f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
- [f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11), [f12] "=&f" (f12),
- [f13] "=&f" (f13), [f14] "=&f" (f14), [f15] "=&f" (f15),
- [count] "=&r" (count)
- : [f0] "f" (f0)
- : "memory"
- );
-}
-
-void aec_rdft_init_mips(void) {
- cft1st_128 = cft1st_128_mips;
- cftmdl_128 = cftmdl_128_mips;
- rftfsub_128 = rftfsub_128_mips;
- rftbsub_128 = rftbsub_128_mips;
- cftfsub_128 = cftfsub_128_mips;
- cftbsub_128 = cftbsub_128_mips;
- bitrv2_128 = bitrv2_128_mips;
-}
diff --git a/webrtc/modules/audio_processing/aec/aec_resampler.c b/webrtc/modules/audio_processing/aec/aec_resampler.c
deleted file mode 100644
index 99c39ef..0000000
--- a/webrtc/modules/audio_processing/aec/aec_resampler.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for
- * clock skew by resampling the farend signal.
- */
-
-#include "webrtc/modules/audio_processing/aec/aec_resampler.h"
-
-#include <assert.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-
-enum {
- kEstimateLengthFrames = 400
-};
-
-typedef struct {
- float buffer[kResamplerBufferSize];
- float position;
-
- int deviceSampleRateHz;
- int skewData[kEstimateLengthFrames];
- int skewDataIndex;
- float skewEstimate;
-} AecResampler;
-
-static int EstimateSkew(const int* rawSkew,
- int size,
- int absLimit,
- float* skewEst);
-
-void* WebRtcAec_CreateResampler() {
- return malloc(sizeof(AecResampler));
-}
-
-int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
- AecResampler* obj = (AecResampler*)resampInst;
- memset(obj->buffer, 0, sizeof(obj->buffer));
- obj->position = 0.0;
-
- obj->deviceSampleRateHz = deviceSampleRateHz;
- memset(obj->skewData, 0, sizeof(obj->skewData));
- obj->skewDataIndex = 0;
- obj->skewEstimate = 0.0;
-
- return 0;
-}
-
-void WebRtcAec_FreeResampler(void* resampInst) {
- AecResampler* obj = (AecResampler*)resampInst;
- free(obj);
-}
-
-void WebRtcAec_ResampleLinear(void* resampInst,
- const float* inspeech,
- size_t size,
- float skew,
- float* outspeech,
- size_t* size_out) {
- AecResampler* obj = (AecResampler*)resampInst;
-
- float* y;
- float be, tnew;
- size_t tn, mm;
-
- assert(size <= 2 * FRAME_LEN);
- assert(resampInst != NULL);
- assert(inspeech != NULL);
- assert(outspeech != NULL);
- assert(size_out != NULL);
-
- // Add new frame data in lookahead
- memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
- inspeech,
- size * sizeof(inspeech[0]));
-
- // Sample rate ratio
- be = 1 + skew;
-
- // Loop over input frame
- mm = 0;
- y = &obj->buffer[FRAME_LEN]; // Point at current frame
-
- tnew = be * mm + obj->position;
- tn = (size_t)tnew;
-
- while (tn < size) {
-
- // Interpolation
- outspeech[mm] = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
- mm++;
-
- tnew = be * mm + obj->position;
- tn = (int)tnew;
- }
-
- *size_out = mm;
- obj->position += (*size_out) * be - size;
-
- // Shift buffer
- memmove(obj->buffer,
- &obj->buffer[size],
- (kResamplerBufferSize - size) * sizeof(obj->buffer[0]));
-}
-
-int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
- AecResampler* obj = (AecResampler*)resampInst;
- int err = 0;
-
- if (obj->skewDataIndex < kEstimateLengthFrames) {
- obj->skewData[obj->skewDataIndex] = rawSkew;
- obj->skewDataIndex++;
- } else if (obj->skewDataIndex == kEstimateLengthFrames) {
- err = EstimateSkew(
- obj->skewData, kEstimateLengthFrames, obj->deviceSampleRateHz, skewEst);
- obj->skewEstimate = *skewEst;
- obj->skewDataIndex++;
- } else {
- *skewEst = obj->skewEstimate;
- }
-
- return err;
-}
-
-int EstimateSkew(const int* rawSkew,
- int size,
- int deviceSampleRateHz,
- float* skewEst) {
- const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
- const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
- int i = 0;
- int n = 0;
- float rawAvg = 0;
- float err = 0;
- float rawAbsDev = 0;
- int upperLimit = 0;
- int lowerLimit = 0;
- float cumSum = 0;
- float x = 0;
- float x2 = 0;
- float y = 0;
- float xy = 0;
- float xAvg = 0;
- float denom = 0;
- float skew = 0;
-
- *skewEst = 0; // Set in case of error below.
- for (i = 0; i < size; i++) {
- if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
- n++;
- rawAvg += rawSkew[i];
- }
- }
-
- if (n == 0) {
- return -1;
- }
- assert(n > 0);
- rawAvg /= n;
-
- for (i = 0; i < size; i++) {
- if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
- err = rawSkew[i] - rawAvg;
- rawAbsDev += err >= 0 ? err : -err;
- }
- }
- assert(n > 0);
- rawAbsDev /= n;
- upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
- lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
-
- n = 0;
- for (i = 0; i < size; i++) {
- if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
- (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
- n++;
- cumSum += rawSkew[i];
- x += n;
- x2 += n * n;
- y += cumSum;
- xy += n * cumSum;
- }
- }
-
- if (n == 0) {
- return -1;
- }
- assert(n > 0);
- xAvg = x / n;
- denom = x2 - xAvg * x;
-
- if (denom != 0) {
- skew = (xy - xAvg * y) / denom;
- }
-
- *skewEst = skew;
- return 0;
-}
diff --git a/webrtc/modules/audio_processing/aec/aec_resampler.h b/webrtc/modules/audio_processing/aec/aec_resampler.h
deleted file mode 100644
index a5002c1..0000000
--- a/webrtc/modules/audio_processing/aec/aec_resampler.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
-
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-
-enum {
- kResamplingDelay = 1
-};
-enum {
- kResamplerBufferSize = FRAME_LEN * 4
-};
-
-// Unless otherwise specified, functions return 0 on success and -1 on error.
-void* WebRtcAec_CreateResampler(); // Returns NULL on error.
-int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz);
-void WebRtcAec_FreeResampler(void* resampInst);
-
-// Estimates skew from raw measurement.
-int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst);
-
-// Resamples input using linear interpolation.
-void WebRtcAec_ResampleLinear(void* resampInst,
- const float* inspeech,
- size_t size,
- float skew,
- float* outspeech,
- size_t* size_out);
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
diff --git a/webrtc/modules/audio_processing/aec/echo_cancellation.c b/webrtc/modules/audio_processing/aec/echo_cancellation.c
deleted file mode 100644
index 0f5cd31..0000000
--- a/webrtc/modules/audio_processing/aec/echo_cancellation.c
+++ /dev/null
@@ -1,923 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/*
- * Contains the API functions for the AEC.
- */
-#include "webrtc/modules/audio_processing/aec/include/echo_cancellation.h"
-
-#include <math.h>
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-#include <stdio.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-
-#include "webrtc/common_audio/ring_buffer.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-#include "webrtc/modules/audio_processing/aec/aec_resampler.h"
-#include "webrtc/modules/audio_processing/aec/echo_cancellation_internal.h"
-#include "webrtc/typedefs.h"
-
-// Measured delays [ms]
-// Device Chrome GTP
-// MacBook Air 10
-// MacBook Retina 10 100
-// MacPro 30?
-//
-// Win7 Desktop 70 80?
-// Win7 T430s 110
-// Win8 T420s 70
-//
-// Daisy 50
-// Pixel (w/ preproc?) 240
-// Pixel (w/o preproc?) 110 110
-
-// The extended filter mode gives us the flexibility to ignore the system's
-// reported delays. We do this for platforms which we believe provide results
-// which are incompatible with the AEC's expectations. Based on measurements
-// (some provided above) we set a conservative (i.e. lower than measured)
-// fixed delay.
-//
-// WEBRTC_UNTRUSTED_DELAY will only have an impact when |extended_filter_mode|
-// is enabled. See the note along with |DelayCorrection| in
-// echo_cancellation_impl.h for more details on the mode.
-//
-// Justification:
-// Chromium/Mac: Here, the true latency is so low (~10-20 ms), that it plays
-// havoc with the AEC's buffering. To avoid this, we set a fixed delay of 20 ms
-// and then compensate by rewinding by 10 ms (in wideband) through
-// kDelayDiffOffsetSamples. This trick does not seem to work for larger rewind
-// values, but fortunately this is sufficient.
-//
-// Chromium/Linux(ChromeOS): The values we get on this platform don't correspond
-// well to reality. The variance doesn't match the AEC's buffer changes, and the
-// bulk values tend to be too low. However, the range across different hardware
-// appears to be too large to choose a single value.
-//
-// GTP/Linux(ChromeOS): TBD, but for the moment we will trust the values.
-#if defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_MAC)
-#define WEBRTC_UNTRUSTED_DELAY
-#endif
-
-#if defined(WEBRTC_UNTRUSTED_DELAY) && defined(WEBRTC_MAC)
-static const int kDelayDiffOffsetSamples = -160;
-#else
-// Not enabled for now.
-static const int kDelayDiffOffsetSamples = 0;
-#endif
-
-#if defined(WEBRTC_MAC)
-static const int kFixedDelayMs = 20;
-#else
-static const int kFixedDelayMs = 50;
-#endif
-#if !defined(WEBRTC_UNTRUSTED_DELAY)
-static const int kMinTrustedDelayMs = 20;
-#endif
-static const int kMaxTrustedDelayMs = 500;
-
-// Maximum length of resampled signal. Must be an integer multiple of frames
-// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
-// The factor of 2 handles wb, and the + 1 is as a safety margin
-// TODO(bjornv): Replace with kResamplerBufferSize
-#define MAX_RESAMP_LEN (5 * FRAME_LEN)
-
-static const int kMaxBufSizeStart = 62; // In partitions
-static const int sampMsNb = 8; // samples per ms in nb
-static const int initCheck = 42;
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-int webrtc_aec_instance_count = 0;
-#endif
-
-// Estimates delay to set the position of the far-end buffer read pointer
-// (controlled by knownDelay)
-static void EstBufDelayNormal(Aec* aecInst);
-static void EstBufDelayExtended(Aec* aecInst);
-static int ProcessNormal(Aec* self,
- const float* const* near,
- size_t num_bands,
- float* const* out,
- size_t num_samples,
- int16_t reported_delay_ms,
- int32_t skew);
-static void ProcessExtended(Aec* self,
- const float* const* near,
- size_t num_bands,
- float* const* out,
- size_t num_samples,
- int16_t reported_delay_ms,
- int32_t skew);
-
-void* WebRtcAec_Create() {
- Aec* aecpc = malloc(sizeof(Aec));
-
- if (!aecpc) {
- return NULL;
- }
-
- aecpc->aec = WebRtcAec_CreateAec();
- if (!aecpc->aec) {
- WebRtcAec_Free(aecpc);
- return NULL;
- }
- aecpc->resampler = WebRtcAec_CreateResampler();
- if (!aecpc->resampler) {
- WebRtcAec_Free(aecpc);
- return NULL;
- }
- // Create far-end pre-buffer. The buffer size has to be large enough for
- // largest possible drift compensation (kResamplerBufferSize) + "almost" an
- // FFT buffer (PART_LEN2 - 1).
- aecpc->far_pre_buf =
- WebRtc_CreateBuffer(PART_LEN2 + kResamplerBufferSize, sizeof(float));
- if (!aecpc->far_pre_buf) {
- WebRtcAec_Free(aecpc);
- return NULL;
- }
-
- aecpc->initFlag = 0;
- aecpc->lastError = 0;
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- {
- char filename[64];
- sprintf(filename, "aec_buf%d.dat", webrtc_aec_instance_count);
- aecpc->bufFile = fopen(filename, "wb");
- sprintf(filename, "aec_skew%d.dat", webrtc_aec_instance_count);
- aecpc->skewFile = fopen(filename, "wb");
- sprintf(filename, "aec_delay%d.dat", webrtc_aec_instance_count);
- aecpc->delayFile = fopen(filename, "wb");
- webrtc_aec_instance_count++;
- }
-#endif
-
- return aecpc;
-}
-
-void WebRtcAec_Free(void* aecInst) {
- Aec* aecpc = aecInst;
-
- if (aecpc == NULL) {
- return;
- }
-
- WebRtc_FreeBuffer(aecpc->far_pre_buf);
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- fclose(aecpc->bufFile);
- fclose(aecpc->skewFile);
- fclose(aecpc->delayFile);
-#endif
-
- WebRtcAec_FreeAec(aecpc->aec);
- WebRtcAec_FreeResampler(aecpc->resampler);
- free(aecpc);
-}
-
-int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
- Aec* aecpc = aecInst;
- AecConfig aecConfig;
-
- if (sampFreq != 8000 &&
- sampFreq != 16000 &&
- sampFreq != 32000 &&
- sampFreq != 48000) {
- aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecpc->sampFreq = sampFreq;
-
- if (scSampFreq < 1 || scSampFreq > 96000) {
- aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecpc->scSampFreq = scSampFreq;
-
- // Initialize echo canceller core
- if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
- aecpc->lastError = AEC_UNSPECIFIED_ERROR;
- return -1;
- }
-
- if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
- aecpc->lastError = AEC_UNSPECIFIED_ERROR;
- return -1;
- }
-
- WebRtc_InitBuffer(aecpc->far_pre_buf);
- WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN); // Start overlap.
-
- aecpc->initFlag = initCheck; // indicates that initialization has been done
-
- if (aecpc->sampFreq == 32000 || aecpc->sampFreq == 48000) {
- aecpc->splitSampFreq = 16000;
- } else {
- aecpc->splitSampFreq = sampFreq;
- }
-
- aecpc->delayCtr = 0;
- aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;
- // Sampling frequency multiplier (SWB is processed as 160 frame size).
- aecpc->rate_factor = aecpc->splitSampFreq / 8000;
-
- aecpc->sum = 0;
- aecpc->counter = 0;
- aecpc->checkBuffSize = 1;
- aecpc->firstVal = 0;
-
- // We skip the startup_phase completely (setting to 0) if DA-AEC is enabled,
- // but not extended_filter mode.
- aecpc->startup_phase = WebRtcAec_extended_filter_enabled(aecpc->aec) ||
- !WebRtcAec_delay_agnostic_enabled(aecpc->aec);
- aecpc->bufSizeStart = 0;
- aecpc->checkBufSizeCtr = 0;
- aecpc->msInSndCardBuf = 0;
- aecpc->filtDelay = -1; // -1 indicates an initialized state.
- aecpc->timeForDelayChange = 0;
- aecpc->knownDelay = 0;
- aecpc->lastDelayDiff = 0;
-
- aecpc->skewFrCtr = 0;
- aecpc->resample = kAecFalse;
- aecpc->highSkewCtr = 0;
- aecpc->skew = 0;
-
- aecpc->farend_started = 0;
-
- // Default settings.
- aecConfig.nlpMode = kAecNlpModerate;
- aecConfig.skewMode = kAecFalse;
- aecConfig.metricsMode = kAecFalse;
- aecConfig.delay_logging = kAecFalse;
-
- if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
- aecpc->lastError = AEC_UNSPECIFIED_ERROR;
- return -1;
- }
-
- return 0;
-}
-
-// only buffer L band for farend
-int32_t WebRtcAec_BufferFarend(void* aecInst,
- const float* farend,
- size_t nrOfSamples) {
- Aec* aecpc = aecInst;
- size_t newNrOfSamples = nrOfSamples;
- float new_farend[MAX_RESAMP_LEN];
- const float* farend_ptr = farend;
-
- if (farend == NULL) {
- aecpc->lastError = AEC_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (aecpc->initFlag != initCheck) {
- aecpc->lastError = AEC_UNINITIALIZED_ERROR;
- return -1;
- }
-
- // number of samples == 160 for SWB input
- if (nrOfSamples != 80 && nrOfSamples != 160) {
- aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
- // Resample and get a new number of samples
- WebRtcAec_ResampleLinear(aecpc->resampler,
- farend,
- nrOfSamples,
- aecpc->skew,
- new_farend,
- &newNrOfSamples);
- farend_ptr = new_farend;
- }
-
- aecpc->farend_started = 1;
- WebRtcAec_SetSystemDelay(
- aecpc->aec, WebRtcAec_system_delay(aecpc->aec) + (int)newNrOfSamples);
-
- // Write the time-domain data to |far_pre_buf|.
- WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, newNrOfSamples);
-
- // Transform to frequency domain if we have enough data.
- while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
- // We have enough data to pass to the FFT, hence read PART_LEN2 samples.
- {
- float* ptmp = NULL;
- float tmp[PART_LEN2];
- WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**)&ptmp, tmp, PART_LEN2);
- WebRtcAec_BufferFarendPartition(aecpc->aec, ptmp);
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- WebRtc_WriteBuffer(
- WebRtcAec_far_time_buf(aecpc->aec), &ptmp[PART_LEN], 1);
-#endif
- }
-
- // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
- WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
- }
-
- return 0;
-}
-
-int32_t WebRtcAec_Process(void* aecInst,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t nrOfSamples,
- int16_t msInSndCardBuf,
- int32_t skew) {
- Aec* aecpc = aecInst;
- int32_t retVal = 0;
-
- if (out == NULL) {
- aecpc->lastError = AEC_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (aecpc->initFlag != initCheck) {
- aecpc->lastError = AEC_UNINITIALIZED_ERROR;
- return -1;
- }
-
- // number of samples == 160 for SWB input
- if (nrOfSamples != 80 && nrOfSamples != 160) {
- aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- if (msInSndCardBuf < 0) {
- msInSndCardBuf = 0;
- aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
- retVal = -1;
- } else if (msInSndCardBuf > kMaxTrustedDelayMs) {
- // The clamping is now done in ProcessExtended/Normal().
- aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
- retVal = -1;
- }
-
- // This returns the value of aec->extended_filter_enabled.
- if (WebRtcAec_extended_filter_enabled(aecpc->aec)) {
- ProcessExtended(aecpc,
- nearend,
- num_bands,
- out,
- nrOfSamples,
- msInSndCardBuf,
- skew);
- } else {
- if (ProcessNormal(aecpc,
- nearend,
- num_bands,
- out,
- nrOfSamples,
- msInSndCardBuf,
- skew) != 0) {
- retVal = -1;
- }
- }
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- {
- int16_t far_buf_size_ms = (int16_t)(WebRtcAec_system_delay(aecpc->aec) /
- (sampMsNb * aecpc->rate_factor));
- (void)fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile);
- (void)fwrite(
- &aecpc->knownDelay, sizeof(aecpc->knownDelay), 1, aecpc->delayFile);
- }
-#endif
-
- return retVal;
-}
-
-int WebRtcAec_set_config(void* handle, AecConfig config) {
- Aec* self = (Aec*)handle;
- if (self->initFlag != initCheck) {
- self->lastError = AEC_UNINITIALIZED_ERROR;
- return -1;
- }
-
- if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) {
- self->lastError = AEC_BAD_PARAMETER_ERROR;
- return -1;
- }
- self->skewMode = config.skewMode;
-
- if (config.nlpMode != kAecNlpConservative &&
- config.nlpMode != kAecNlpModerate &&
- config.nlpMode != kAecNlpAggressive) {
- self->lastError = AEC_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) {
- self->lastError = AEC_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) {
- self->lastError = AEC_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- WebRtcAec_SetConfigCore(
- self->aec, config.nlpMode, config.metricsMode, config.delay_logging);
- return 0;
-}
-
-int WebRtcAec_get_echo_status(void* handle, int* status) {
- Aec* self = (Aec*)handle;
- if (status == NULL) {
- self->lastError = AEC_NULL_POINTER_ERROR;
- return -1;
- }
- if (self->initFlag != initCheck) {
- self->lastError = AEC_UNINITIALIZED_ERROR;
- return -1;
- }
-
- *status = WebRtcAec_echo_state(self->aec);
-
- return 0;
-}
-
-int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics) {
- const float kUpWeight = 0.7f;
- float dtmp;
- int stmp;
- Aec* self = (Aec*)handle;
- Stats erl;
- Stats erle;
- Stats a_nlp;
-
- if (handle == NULL) {
- return -1;
- }
- if (metrics == NULL) {
- self->lastError = AEC_NULL_POINTER_ERROR;
- return -1;
- }
- if (self->initFlag != initCheck) {
- self->lastError = AEC_UNINITIALIZED_ERROR;
- return -1;
- }
-
- WebRtcAec_GetEchoStats(self->aec, &erl, &erle, &a_nlp);
-
- // ERL
- metrics->erl.instant = (int)erl.instant;
-
- if ((erl.himean > kOffsetLevel) && (erl.average > kOffsetLevel)) {
- // Use a mix between regular average and upper part average.
- dtmp = kUpWeight * erl.himean + (1 - kUpWeight) * erl.average;
- metrics->erl.average = (int)dtmp;
- } else {
- metrics->erl.average = kOffsetLevel;
- }
-
- metrics->erl.max = (int)erl.max;
-
- if (erl.min < (kOffsetLevel * (-1))) {
- metrics->erl.min = (int)erl.min;
- } else {
- metrics->erl.min = kOffsetLevel;
- }
-
- // ERLE
- metrics->erle.instant = (int)erle.instant;
-
- if ((erle.himean > kOffsetLevel) && (erle.average > kOffsetLevel)) {
- // Use a mix between regular average and upper part average.
- dtmp = kUpWeight * erle.himean + (1 - kUpWeight) * erle.average;
- metrics->erle.average = (int)dtmp;
- } else {
- metrics->erle.average = kOffsetLevel;
- }
-
- metrics->erle.max = (int)erle.max;
-
- if (erle.min < (kOffsetLevel * (-1))) {
- metrics->erle.min = (int)erle.min;
- } else {
- metrics->erle.min = kOffsetLevel;
- }
-
- // RERL
- if ((metrics->erl.average > kOffsetLevel) &&
- (metrics->erle.average > kOffsetLevel)) {
- stmp = metrics->erl.average + metrics->erle.average;
- } else {
- stmp = kOffsetLevel;
- }
- metrics->rerl.average = stmp;
-
- // No other statistics needed, but returned for completeness.
- metrics->rerl.instant = stmp;
- metrics->rerl.max = stmp;
- metrics->rerl.min = stmp;
-
- // A_NLP
- metrics->aNlp.instant = (int)a_nlp.instant;
-
- if ((a_nlp.himean > kOffsetLevel) && (a_nlp.average > kOffsetLevel)) {
- // Use a mix between regular average and upper part average.
- dtmp = kUpWeight * a_nlp.himean + (1 - kUpWeight) * a_nlp.average;
- metrics->aNlp.average = (int)dtmp;
- } else {
- metrics->aNlp.average = kOffsetLevel;
- }
-
- metrics->aNlp.max = (int)a_nlp.max;
-
- if (a_nlp.min < (kOffsetLevel * (-1))) {
- metrics->aNlp.min = (int)a_nlp.min;
- } else {
- metrics->aNlp.min = kOffsetLevel;
- }
-
- return 0;
-}
-
-int WebRtcAec_GetDelayMetrics(void* handle,
- int* median,
- int* std,
- float* fraction_poor_delays) {
- Aec* self = handle;
- if (median == NULL) {
- self->lastError = AEC_NULL_POINTER_ERROR;
- return -1;
- }
- if (std == NULL) {
- self->lastError = AEC_NULL_POINTER_ERROR;
- return -1;
- }
- if (self->initFlag != initCheck) {
- self->lastError = AEC_UNINITIALIZED_ERROR;
- return -1;
- }
- if (WebRtcAec_GetDelayMetricsCore(self->aec, median, std,
- fraction_poor_delays) ==
- -1) {
- // Logging disabled.
- self->lastError = AEC_UNSUPPORTED_FUNCTION_ERROR;
- return -1;
- }
-
- return 0;
-}
-
-int32_t WebRtcAec_get_error_code(void* aecInst) {
- Aec* aecpc = aecInst;
- return aecpc->lastError;
-}
-
-AecCore* WebRtcAec_aec_core(void* handle) {
- if (!handle) {
- return NULL;
- }
- return ((Aec*)handle)->aec;
-}
-
-static int ProcessNormal(Aec* aecpc,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t nrOfSamples,
- int16_t msInSndCardBuf,
- int32_t skew) {
- int retVal = 0;
- size_t i;
- size_t nBlocks10ms;
- // Limit resampling to doubling/halving of signal
- const float minSkewEst = -0.5f;
- const float maxSkewEst = 1.0f;
-
- msInSndCardBuf =
- msInSndCardBuf > kMaxTrustedDelayMs ? kMaxTrustedDelayMs : msInSndCardBuf;
- // TODO(andrew): we need to investigate if this +10 is really wanted.
- msInSndCardBuf += 10;
- aecpc->msInSndCardBuf = msInSndCardBuf;
-
- if (aecpc->skewMode == kAecTrue) {
- if (aecpc->skewFrCtr < 25) {
- aecpc->skewFrCtr++;
- } else {
- retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
- if (retVal == -1) {
- aecpc->skew = 0;
- aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
- }
-
- aecpc->skew /= aecpc->sampFactor * nrOfSamples;
-
- if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) {
- aecpc->resample = kAecFalse;
- } else {
- aecpc->resample = kAecTrue;
- }
-
- if (aecpc->skew < minSkewEst) {
- aecpc->skew = minSkewEst;
- } else if (aecpc->skew > maxSkewEst) {
- aecpc->skew = maxSkewEst;
- }
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- (void)fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile);
-#endif
- }
- }
-
- nBlocks10ms = nrOfSamples / (FRAME_LEN * aecpc->rate_factor);
-
- if (aecpc->startup_phase) {
- for (i = 0; i < num_bands; ++i) {
- // Only needed if they don't already point to the same place.
- if (nearend[i] != out[i]) {
- memcpy(out[i], nearend[i], sizeof(nearend[i][0]) * nrOfSamples);
- }
- }
-
- // The AEC is in the start up mode
- // AEC is disabled until the system delay is OK
-
- // Mechanism to ensure that the system delay is reasonably stable.
- if (aecpc->checkBuffSize) {
- aecpc->checkBufSizeCtr++;
- // Before we fill up the far-end buffer we require the system delay
- // to be stable (+/-8 ms) compared to the first value. This
- // comparison is made during the following 6 consecutive 10 ms
- // blocks. If it seems to be stable then we start to fill up the
- // far-end buffer.
- if (aecpc->counter == 0) {
- aecpc->firstVal = aecpc->msInSndCardBuf;
- aecpc->sum = 0;
- }
-
- if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) <
- WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) {
- aecpc->sum += aecpc->msInSndCardBuf;
- aecpc->counter++;
- } else {
- aecpc->counter = 0;
- }
-
- if (aecpc->counter * nBlocks10ms >= 6) {
- // The far-end buffer size is determined in partitions of
- // PART_LEN samples. Use 75% of the average value of the system
- // delay as buffer size to start with.
- aecpc->bufSizeStart =
- WEBRTC_SPL_MIN((3 * aecpc->sum * aecpc->rate_factor * 8) /
- (4 * aecpc->counter * PART_LEN),
- kMaxBufSizeStart);
- // Buffer size has now been determined.
- aecpc->checkBuffSize = 0;
- }
-
- if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) {
- // For really bad systems, don't disable the echo canceller for
- // more than 0.5 sec.
- aecpc->bufSizeStart = WEBRTC_SPL_MIN(
- (aecpc->msInSndCardBuf * aecpc->rate_factor * 3) / 40,
- kMaxBufSizeStart);
- aecpc->checkBuffSize = 0;
- }
- }
-
- // If |checkBuffSize| changed in the if-statement above.
- if (!aecpc->checkBuffSize) {
- // The system delay is now reasonably stable (or has been unstable
- // for too long). When the far-end buffer is filled with
- // approximately the same amount of data as reported by the system
- // we end the startup phase.
- int overhead_elements =
- WebRtcAec_system_delay(aecpc->aec) / PART_LEN - aecpc->bufSizeStart;
- if (overhead_elements == 0) {
- // Enable the AEC
- aecpc->startup_phase = 0;
- } else if (overhead_elements > 0) {
- // TODO(bjornv): Do we need a check on how much we actually
- // moved the read pointer? It should always be possible to move
- // the pointer |overhead_elements| since we have only added data
- // to the buffer and no delay compensation nor AEC processing
- // has been done.
- WebRtcAec_MoveFarReadPtr(aecpc->aec, overhead_elements);
-
- // Enable the AEC
- aecpc->startup_phase = 0;
- }
- }
- } else {
- // AEC is enabled.
- EstBufDelayNormal(aecpc);
-
- // Call the AEC.
- // TODO(bjornv): Re-structure such that we don't have to pass
- // |aecpc->knownDelay| as input. Change name to something like
- // |system_buffer_diff|.
- WebRtcAec_ProcessFrames(aecpc->aec,
- nearend,
- num_bands,
- nrOfSamples,
- aecpc->knownDelay,
- out);
- }
-
- return retVal;
-}
-
-static void ProcessExtended(Aec* self,
- const float* const* near,
- size_t num_bands,
- float* const* out,
- size_t num_samples,
- int16_t reported_delay_ms,
- int32_t skew) {
- size_t i;
- const int delay_diff_offset = kDelayDiffOffsetSamples;
-#if defined(WEBRTC_UNTRUSTED_DELAY)
- reported_delay_ms = kFixedDelayMs;
-#else
- // This is the usual mode where we trust the reported system delay values.
- // Due to the longer filter, we no longer add 10 ms to the reported delay
- // to reduce chance of non-causality. Instead we apply a minimum here to avoid
- // issues with the read pointer jumping around needlessly.
- reported_delay_ms = reported_delay_ms < kMinTrustedDelayMs
- ? kMinTrustedDelayMs
- : reported_delay_ms;
- // If the reported delay appears to be bogus, we attempt to recover by using
- // the measured fixed delay values. We use >= here because higher layers
- // may already clamp to this maximum value, and we would otherwise not
- // detect it here.
- reported_delay_ms = reported_delay_ms >= kMaxTrustedDelayMs
- ? kFixedDelayMs
- : reported_delay_ms;
-#endif
- self->msInSndCardBuf = reported_delay_ms;
-
- if (!self->farend_started) {
- for (i = 0; i < num_bands; ++i) {
- // Only needed if they don't already point to the same place.
- if (near[i] != out[i]) {
- memcpy(out[i], near[i], sizeof(near[i][0]) * num_samples);
- }
- }
- return;
- }
- if (self->startup_phase) {
- // In the extended mode, there isn't a startup "phase", just a special
- // action on the first frame. In the trusted delay case, we'll take the
- // current reported delay, unless it's less then our conservative
- // measurement.
- int startup_size_ms =
- reported_delay_ms < kFixedDelayMs ? kFixedDelayMs : reported_delay_ms;
-#if defined(WEBRTC_ANDROID)
- int target_delay = startup_size_ms * self->rate_factor * 8;
-#else
- // To avoid putting the AEC in a non-causal state we're being slightly
- // conservative and scale by 2. On Android we use a fixed delay and
- // therefore there is no need to scale the target_delay.
- int target_delay = startup_size_ms * self->rate_factor * 8 / 2;
-#endif
- int overhead_elements =
- (WebRtcAec_system_delay(self->aec) - target_delay) / PART_LEN;
- WebRtcAec_MoveFarReadPtr(self->aec, overhead_elements);
- self->startup_phase = 0;
- }
-
- EstBufDelayExtended(self);
-
- {
- // |delay_diff_offset| gives us the option to manually rewind the delay on
- // very low delay platforms which can't be expressed purely through
- // |reported_delay_ms|.
- const int adjusted_known_delay =
- WEBRTC_SPL_MAX(0, self->knownDelay + delay_diff_offset);
-
- WebRtcAec_ProcessFrames(self->aec,
- near,
- num_bands,
- num_samples,
- adjusted_known_delay,
- out);
- }
-}
-
-static void EstBufDelayNormal(Aec* aecpc) {
- int nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->rate_factor;
- int current_delay = nSampSndCard - WebRtcAec_system_delay(aecpc->aec);
- int delay_difference = 0;
-
- // Before we proceed with the delay estimate filtering we:
- // 1) Compensate for the frame that will be read.
- // 2) Compensate for drift resampling.
- // 3) Compensate for non-causality if needed, since the estimated delay can't
- // be negative.
-
- // 1) Compensating for the frame(s) that will be read/processed.
- current_delay += FRAME_LEN * aecpc->rate_factor;
-
- // 2) Account for resampling frame delay.
- if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
- current_delay -= kResamplingDelay;
- }
-
- // 3) Compensate for non-causality, if needed, by flushing one block.
- if (current_delay < PART_LEN) {
- current_delay += WebRtcAec_MoveFarReadPtr(aecpc->aec, 1) * PART_LEN;
- }
-
- // We use -1 to signal an initialized state in the "extended" implementation;
- // compensate for that.
- aecpc->filtDelay = aecpc->filtDelay < 0 ? 0 : aecpc->filtDelay;
- aecpc->filtDelay =
- WEBRTC_SPL_MAX(0, (short)(0.8 * aecpc->filtDelay + 0.2 * current_delay));
-
- delay_difference = aecpc->filtDelay - aecpc->knownDelay;
- if (delay_difference > 224) {
- if (aecpc->lastDelayDiff < 96) {
- aecpc->timeForDelayChange = 0;
- } else {
- aecpc->timeForDelayChange++;
- }
- } else if (delay_difference < 96 && aecpc->knownDelay > 0) {
- if (aecpc->lastDelayDiff > 224) {
- aecpc->timeForDelayChange = 0;
- } else {
- aecpc->timeForDelayChange++;
- }
- } else {
- aecpc->timeForDelayChange = 0;
- }
- aecpc->lastDelayDiff = delay_difference;
-
- if (aecpc->timeForDelayChange > 25) {
- aecpc->knownDelay = WEBRTC_SPL_MAX((int)aecpc->filtDelay - 160, 0);
- }
-}
-
-static void EstBufDelayExtended(Aec* self) {
- int reported_delay = self->msInSndCardBuf * sampMsNb * self->rate_factor;
- int current_delay = reported_delay - WebRtcAec_system_delay(self->aec);
- int delay_difference = 0;
-
- // Before we proceed with the delay estimate filtering we:
- // 1) Compensate for the frame that will be read.
- // 2) Compensate for drift resampling.
- // 3) Compensate for non-causality if needed, since the estimated delay can't
- // be negative.
-
- // 1) Compensating for the frame(s) that will be read/processed.
- current_delay += FRAME_LEN * self->rate_factor;
-
- // 2) Account for resampling frame delay.
- if (self->skewMode == kAecTrue && self->resample == kAecTrue) {
- current_delay -= kResamplingDelay;
- }
-
- // 3) Compensate for non-causality, if needed, by flushing two blocks.
- if (current_delay < PART_LEN) {
- current_delay += WebRtcAec_MoveFarReadPtr(self->aec, 2) * PART_LEN;
- }
-
- if (self->filtDelay == -1) {
- self->filtDelay = WEBRTC_SPL_MAX(0, 0.5 * current_delay);
- } else {
- self->filtDelay = WEBRTC_SPL_MAX(
- 0, (short)(0.95 * self->filtDelay + 0.05 * current_delay));
- }
-
- delay_difference = self->filtDelay - self->knownDelay;
- if (delay_difference > 384) {
- if (self->lastDelayDiff < 128) {
- self->timeForDelayChange = 0;
- } else {
- self->timeForDelayChange++;
- }
- } else if (delay_difference < 128 && self->knownDelay > 0) {
- if (self->lastDelayDiff > 384) {
- self->timeForDelayChange = 0;
- } else {
- self->timeForDelayChange++;
- }
- } else {
- self->timeForDelayChange = 0;
- }
- self->lastDelayDiff = delay_difference;
-
- if (self->timeForDelayChange > 25) {
- self->knownDelay = WEBRTC_SPL_MAX((int)self->filtDelay - 256, 0);
- }
-}
diff --git a/webrtc/modules/audio_processing/aec/echo_cancellation_internal.h b/webrtc/modules/audio_processing/aec/echo_cancellation_internal.h
deleted file mode 100644
index 95a6cf3..0000000
--- a/webrtc/modules/audio_processing/aec/echo_cancellation_internal.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_INTERNAL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_INTERNAL_H_
-
-#include "webrtc/common_audio/ring_buffer.h"
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-
-typedef struct {
- int delayCtr;
- int sampFreq;
- int splitSampFreq;
- int scSampFreq;
- float sampFactor; // scSampRate / sampFreq
- short skewMode;
- int bufSizeStart;
- int knownDelay;
- int rate_factor;
-
- short initFlag; // indicates if AEC has been initialized
-
- // Variables used for averaging far end buffer size
- short counter;
- int sum;
- short firstVal;
- short checkBufSizeCtr;
-
- // Variables used for delay shifts
- short msInSndCardBuf;
- short filtDelay; // Filtered delay estimate.
- int timeForDelayChange;
- int startup_phase;
- int checkBuffSize;
- short lastDelayDiff;
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
- FILE* bufFile;
- FILE* delayFile;
- FILE* skewFile;
-#endif
-
- // Structures
- void* resampler;
-
- int skewFrCtr;
- int resample; // if the skew is small enough we don't resample
- int highSkewCtr;
- float skew;
-
- RingBuffer* far_pre_buf; // Time domain far-end pre-buffer.
-
- int lastError;
-
- int farend_started;
-
- AecCore* aec;
-} Aec;
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_INTERNAL_H_
diff --git a/webrtc/modules/audio_processing/aec/include/echo_cancellation.h b/webrtc/modules/audio_processing/aec/include/echo_cancellation.h
deleted file mode 100644
index a340cf8..0000000
--- a/webrtc/modules/audio_processing/aec/include/echo_cancellation.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_
-
-#include <stddef.h>
-
-#include "webrtc/typedefs.h"
-
-// Errors
-#define AEC_UNSPECIFIED_ERROR 12000
-#define AEC_UNSUPPORTED_FUNCTION_ERROR 12001
-#define AEC_UNINITIALIZED_ERROR 12002
-#define AEC_NULL_POINTER_ERROR 12003
-#define AEC_BAD_PARAMETER_ERROR 12004
-
-// Warnings
-#define AEC_BAD_PARAMETER_WARNING 12050
-
-enum {
- kAecNlpConservative = 0,
- kAecNlpModerate,
- kAecNlpAggressive
-};
-
-enum {
- kAecFalse = 0,
- kAecTrue
-};
-
-typedef struct {
- int16_t nlpMode; // default kAecNlpModerate
- int16_t skewMode; // default kAecFalse
- int16_t metricsMode; // default kAecFalse
- int delay_logging; // default kAecFalse
- // float realSkew;
-} AecConfig;
-
-typedef struct {
- int instant;
- int average;
- int max;
- int min;
-} AecLevel;
-
-typedef struct {
- AecLevel rerl;
- AecLevel erl;
- AecLevel erle;
- AecLevel aNlp;
-} AecMetrics;
-
-struct AecCore;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Allocates the memory needed by the AEC. The memory needs to be initialized
- * separately using the WebRtcAec_Init() function. Returns a pointer to the
- * object or NULL on error.
- */
-void* WebRtcAec_Create();
-
-/*
- * This function releases the memory allocated by WebRtcAec_Create().
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- */
-void WebRtcAec_Free(void* aecInst);
-
-/*
- * Initializes an AEC instance.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- * int32_t sampFreq Sampling frequency of data
- * int32_t scSampFreq Soundcard sampling frequency
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int32_t return 0: OK
- * -1: error
- */
-int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq);
-
-/*
- * Inserts an 80 or 160 sample block of data into the farend buffer.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- * const float* farend In buffer containing one frame of
- * farend signal for L band
- * int16_t nrOfSamples Number of samples in farend buffer
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int32_t return 0: OK
- * -1: error
- */
-int32_t WebRtcAec_BufferFarend(void* aecInst,
- const float* farend,
- size_t nrOfSamples);
-
-/*
- * Runs the echo canceller on an 80 or 160 sample blocks of data.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- * float* const* nearend In buffer containing one frame of
- * nearend+echo signal for each band
- * int num_bands Number of bands in nearend buffer
- * int16_t nrOfSamples Number of samples in nearend buffer
- * int16_t msInSndCardBuf Delay estimate for sound card and
- * system buffers
- * int16_t skew Difference between number of samples played
- * and recorded at the soundcard (for clock skew
- * compensation)
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * float* const* out Out buffer, one frame of processed nearend
- * for each band
- * int32_t return 0: OK
- * -1: error
- */
-int32_t WebRtcAec_Process(void* aecInst,
- const float* const* nearend,
- size_t num_bands,
- float* const* out,
- size_t nrOfSamples,
- int16_t msInSndCardBuf,
- int32_t skew);
-
-/*
- * This function enables the user to set certain parameters on-the-fly.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* handle Pointer to the AEC instance
- * AecConfig config Config instance that contains all
- * properties to be set
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int return 0: OK
- * -1: error
- */
-int WebRtcAec_set_config(void* handle, AecConfig config);
-
-/*
- * Gets the current echo status of the nearend signal.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* handle Pointer to the AEC instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int* status 0: Almost certainly nearend single-talk
- * 1: Might not be neared single-talk
- * int return 0: OK
- * -1: error
- */
-int WebRtcAec_get_echo_status(void* handle, int* status);
-
-/*
- * Gets the current echo metrics for the session.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* handle Pointer to the AEC instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * AecMetrics* metrics Struct which will be filled out with the
- * current echo metrics.
- * int return 0: OK
- * -1: error
- */
-int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics);
-
-/*
- * Gets the current delay metrics for the session.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* handle Pointer to the AEC instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int* median Delay median value.
- * int* std Delay standard deviation.
- * float* fraction_poor_delays Fraction of the delay estimates that may
- * cause the AEC to perform poorly.
- *
- * int return 0: OK
- * -1: error
- */
-int WebRtcAec_GetDelayMetrics(void* handle,
- int* median,
- int* std,
- float* fraction_poor_delays);
-
-/*
- * Gets the last error code.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecInst Pointer to the AEC instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int32_t return 11000-11100: error code
- */
-int32_t WebRtcAec_get_error_code(void* aecInst);
-
-// Returns a pointer to the low level AEC handle.
-//
-// Input:
-// - handle : Pointer to the AEC instance.
-//
-// Return value:
-// - AecCore pointer : NULL for error.
-//
-struct AecCore* WebRtcAec_aec_core(void* handle);
-
-#ifdef __cplusplus
-}
-#endif
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_
diff --git a/webrtc/modules/audio_processing/aec3/BUILD.gn b/webrtc/modules/audio_processing/aec3/BUILD.gn
new file mode 100644
index 0000000..c98fa4c
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/BUILD.gn
@@ -0,0 +1,367 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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_library("aec3") {
+ visibility = [ "*" ]
+ configs += [ "..:apm_debug_dump" ]
+ sources = [
+ "adaptive_fir_filter.cc",
+ "adaptive_fir_filter_erl.cc",
+ "aec3_common.cc",
+ "aec3_fft.cc",
+ "aec_state.cc",
+ "aec_state.h",
+ "alignment_mixer.cc",
+ "alignment_mixer.h",
+ "api_call_jitter_metrics.cc",
+ "api_call_jitter_metrics.h",
+ "block_buffer.cc",
+ "block_delay_buffer.cc",
+ "block_delay_buffer.h",
+ "block_framer.cc",
+ "block_framer.h",
+ "block_processor.cc",
+ "block_processor.h",
+ "block_processor_metrics.cc",
+ "block_processor_metrics.h",
+ "clockdrift_detector.cc",
+ "clockdrift_detector.h",
+ "coarse_filter_update_gain.cc",
+ "coarse_filter_update_gain.h",
+ "comfort_noise_generator.cc",
+ "comfort_noise_generator.h",
+ "decimator.cc",
+ "decimator.h",
+ "delay_estimate.h",
+ "dominant_nearend_detector.cc",
+ "dominant_nearend_detector.h",
+ "downsampled_render_buffer.cc",
+ "downsampled_render_buffer.h",
+ "echo_audibility.cc",
+ "echo_audibility.h",
+ "echo_canceller3.cc",
+ "echo_canceller3.h",
+ "echo_path_delay_estimator.cc",
+ "echo_path_delay_estimator.h",
+ "echo_path_variability.cc",
+ "echo_path_variability.h",
+ "echo_remover.cc",
+ "echo_remover.h",
+ "echo_remover_metrics.cc",
+ "echo_remover_metrics.h",
+ "erl_estimator.cc",
+ "erl_estimator.h",
+ "erle_estimator.cc",
+ "erle_estimator.h",
+ "fft_buffer.cc",
+ "filter_analyzer.cc",
+ "filter_analyzer.h",
+ "frame_blocker.cc",
+ "frame_blocker.h",
+ "fullband_erle_estimator.cc",
+ "fullband_erle_estimator.h",
+ "matched_filter.cc",
+ "matched_filter_lag_aggregator.cc",
+ "matched_filter_lag_aggregator.h",
+ "moving_average.cc",
+ "moving_average.h",
+ "nearend_detector.h",
+ "refined_filter_update_gain.cc",
+ "refined_filter_update_gain.h",
+ "render_buffer.cc",
+ "render_delay_buffer.cc",
+ "render_delay_buffer.h",
+ "render_delay_controller.cc",
+ "render_delay_controller.h",
+ "render_delay_controller_metrics.cc",
+ "render_delay_controller_metrics.h",
+ "render_signal_analyzer.cc",
+ "render_signal_analyzer.h",
+ "residual_echo_estimator.cc",
+ "residual_echo_estimator.h",
+ "reverb_decay_estimator.cc",
+ "reverb_decay_estimator.h",
+ "reverb_frequency_response.cc",
+ "reverb_frequency_response.h",
+ "reverb_model.cc",
+ "reverb_model.h",
+ "reverb_model_estimator.cc",
+ "reverb_model_estimator.h",
+ "signal_dependent_erle_estimator.cc",
+ "signal_dependent_erle_estimator.h",
+ "spectrum_buffer.cc",
+ "stationarity_estimator.cc",
+ "stationarity_estimator.h",
+ "subband_erle_estimator.cc",
+ "subband_erle_estimator.h",
+ "subband_nearend_detector.cc",
+ "subband_nearend_detector.h",
+ "subtractor.cc",
+ "subtractor.h",
+ "subtractor_output.cc",
+ "subtractor_output.h",
+ "subtractor_output_analyzer.cc",
+ "subtractor_output_analyzer.h",
+ "suppression_filter.cc",
+ "suppression_filter.h",
+ "suppression_gain.cc",
+ "suppression_gain.h",
+ "transparent_mode.cc",
+ "transparent_mode.h",
+ ]
+
+ defines = []
+ if (rtc_build_with_neon && current_cpu != "arm64") {
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags = [ "-mfpu=neon" ]
+ }
+
+ deps = [
+ ":adaptive_fir_filter",
+ ":adaptive_fir_filter_erl",
+ ":aec3_common",
+ ":aec3_fft",
+ ":fft_data",
+ ":matched_filter",
+ ":render_buffer",
+ ":vector_math",
+ "..:apm_logging",
+ "..:audio_buffer",
+ "..:high_pass_filter",
+ "../../../api:array_view",
+ "../../../api/audio:aec3_config",
+ "../../../api/audio:echo_control",
+ "../../../common_audio:common_audio_c",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:safe_minmax",
+ "../../../rtc_base/experiments:field_trial_parser",
+ "../../../rtc_base/system:arch",
+ "../../../system_wrappers",
+ "../../../system_wrappers:field_trial",
+ "../../../system_wrappers:metrics",
+ "../utility:cascaded_biquad_filter",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+
+ if (current_cpu == "x86" || current_cpu == "x64") {
+ deps += [ ":aec3_avx2" ]
+ }
+}
+
+rtc_source_set("aec3_common") {
+ sources = [ "aec3_common.h" ]
+}
+
+rtc_source_set("aec3_fft") {
+ sources = [ "aec3_fft.h" ]
+ deps = [
+ ":aec3_common",
+ ":fft_data",
+ "../../../api:array_view",
+ "../../../common_audio/third_party/ooura:fft_size_128",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base/system:arch",
+ ]
+}
+
+rtc_source_set("render_buffer") {
+ sources = [
+ "block_buffer.h",
+ "fft_buffer.h",
+ "render_buffer.h",
+ "spectrum_buffer.h",
+ ]
+ deps = [
+ ":aec3_common",
+ ":fft_data",
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base/system:arch",
+ ]
+}
+
+rtc_source_set("adaptive_fir_filter") {
+ sources = [ "adaptive_fir_filter.h" ]
+ deps = [
+ ":aec3_common",
+ ":aec3_fft",
+ ":fft_data",
+ ":render_buffer",
+ "..:apm_logging",
+ "../../../api:array_view",
+ "../../../rtc_base/system:arch",
+ ]
+}
+
+rtc_source_set("adaptive_fir_filter_erl") {
+ sources = [ "adaptive_fir_filter_erl.h" ]
+ deps = [
+ ":aec3_common",
+ "../../../api:array_view",
+ "../../../rtc_base/system:arch",
+ ]
+}
+
+rtc_source_set("matched_filter") {
+ sources = [ "matched_filter.h" ]
+ deps = [
+ ":aec3_common",
+ "../../../api:array_view",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base/system:arch",
+ ]
+}
+
+rtc_source_set("vector_math") {
+ sources = [ "vector_math.h" ]
+ deps = [
+ ":aec3_common",
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ "../../../rtc_base/system:arch",
+ ]
+}
+
+rtc_source_set("fft_data") {
+ sources = [ "fft_data.h" ]
+ deps = [
+ ":aec3_common",
+ "../../../api:array_view",
+ "../../../rtc_base/system:arch",
+ ]
+}
+
+if (current_cpu == "x86" || current_cpu == "x64") {
+ rtc_library("aec3_avx2") {
+ configs += [ "..:apm_debug_dump" ]
+ sources = [
+ "adaptive_fir_filter_avx2.cc",
+ "adaptive_fir_filter_erl_avx2.cc",
+ "fft_data_avx2.cc",
+ "matched_filter_avx2.cc",
+ "vector_math_avx2.cc",
+ ]
+
+ if (is_win) {
+ cflags = [ "/arch:AVX2" ]
+ } else {
+ cflags = [
+ "-mavx2",
+ "-mfma",
+ ]
+ }
+
+ deps = [
+ ":adaptive_fir_filter",
+ ":adaptive_fir_filter_erl",
+ ":fft_data",
+ ":matched_filter",
+ ":vector_math",
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ ]
+ }
+}
+
+if (rtc_include_tests) {
+ rtc_library("aec3_unittests") {
+ testonly = true
+
+ configs += [ "..:apm_debug_dump" ]
+ sources = [
+ "mock/mock_block_processor.cc",
+ "mock/mock_block_processor.h",
+ "mock/mock_echo_remover.cc",
+ "mock/mock_echo_remover.h",
+ "mock/mock_render_delay_buffer.cc",
+ "mock/mock_render_delay_buffer.h",
+ "mock/mock_render_delay_controller.cc",
+ "mock/mock_render_delay_controller.h",
+ ]
+
+ deps = [
+ ":adaptive_fir_filter",
+ ":adaptive_fir_filter_erl",
+ ":aec3",
+ ":aec3_common",
+ ":aec3_fft",
+ ":fft_data",
+ ":matched_filter",
+ ":render_buffer",
+ ":vector_math",
+ "..:apm_logging",
+ "..:audio_buffer",
+ "..:audio_processing",
+ "..:audio_processing_unittests",
+ "..:high_pass_filter",
+ "../../../api:array_view",
+ "../../../api/audio:aec3_config",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:safe_minmax",
+ "../../../rtc_base/system:arch",
+ "../../../system_wrappers",
+ "../../../test:field_trial",
+ "../../../test:test_support",
+ "../utility:cascaded_biquad_filter",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+
+ defines = []
+
+ if (rtc_enable_protobuf) {
+ sources += [
+ "adaptive_fir_filter_erl_unittest.cc",
+ "adaptive_fir_filter_unittest.cc",
+ "aec3_fft_unittest.cc",
+ "aec_state_unittest.cc",
+ "alignment_mixer_unittest.cc",
+ "api_call_jitter_metrics_unittest.cc",
+ "block_delay_buffer_unittest.cc",
+ "block_framer_unittest.cc",
+ "block_processor_metrics_unittest.cc",
+ "block_processor_unittest.cc",
+ "clockdrift_detector_unittest.cc",
+ "coarse_filter_update_gain_unittest.cc",
+ "comfort_noise_generator_unittest.cc",
+ "decimator_unittest.cc",
+ "echo_canceller3_unittest.cc",
+ "echo_path_delay_estimator_unittest.cc",
+ "echo_path_variability_unittest.cc",
+ "echo_remover_metrics_unittest.cc",
+ "echo_remover_unittest.cc",
+ "erl_estimator_unittest.cc",
+ "erle_estimator_unittest.cc",
+ "fft_data_unittest.cc",
+ "filter_analyzer_unittest.cc",
+ "frame_blocker_unittest.cc",
+ "matched_filter_lag_aggregator_unittest.cc",
+ "matched_filter_unittest.cc",
+ "moving_average_unittest.cc",
+ "refined_filter_update_gain_unittest.cc",
+ "render_buffer_unittest.cc",
+ "render_delay_buffer_unittest.cc",
+ "render_delay_controller_metrics_unittest.cc",
+ "render_delay_controller_unittest.cc",
+ "render_signal_analyzer_unittest.cc",
+ "residual_echo_estimator_unittest.cc",
+ "reverb_model_estimator_unittest.cc",
+ "signal_dependent_erle_estimator_unittest.cc",
+ "subtractor_unittest.cc",
+ "suppression_filter_unittest.cc",
+ "suppression_gain_unittest.cc",
+ "vector_math_unittest.cc",
+ ]
+ }
+ }
+}
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
new file mode 100644
index 0000000..bf3a780
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
@@ -0,0 +1,740 @@
+/*
+ * 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/audio_processing/aec3/adaptive_fir_filter.h"
+
+// Defines WEBRTC_ARCH_X86_FAMILY, used below.
+#include "rtc_base/system/arch.h"
+
+#if defined(WEBRTC_HAS_NEON)
+#include <arm_neon.h>
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#include <emmintrin.h>
+#endif
+#include <math.h>
+
+#include <algorithm>
+#include <functional>
+
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace aec3 {
+
+// Computes and stores the frequency response of the filter.
+void ComputeFrequencyResponse(
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) {
+ for (auto& H2_ch : *H2) {
+ H2_ch.fill(0.f);
+ }
+
+ const size_t num_render_channels = H[0].size();
+ RTC_DCHECK_EQ(H.size(), H2->capacity());
+ for (size_t p = 0; p < num_partitions; ++p) {
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size());
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) {
+ float tmp =
+ H[p][ch].re[j] * H[p][ch].re[j] + H[p][ch].im[j] * H[p][ch].im[j];
+ (*H2)[p][j] = std::max((*H2)[p][j], tmp);
+ }
+ }
+ }
+}
+
+#if defined(WEBRTC_HAS_NEON)
+// Computes and stores the frequency response of the filter.
+void ComputeFrequencyResponse_Neon(
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) {
+ for (auto& H2_ch : *H2) {
+ H2_ch.fill(0.f);
+ }
+
+ const size_t num_render_channels = H[0].size();
+ RTC_DCHECK_EQ(H.size(), H2->capacity());
+ for (size_t p = 0; p < num_partitions; ++p) {
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size());
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ for (size_t j = 0; j < kFftLengthBy2; j += 4) {
+ const float32x4_t re = vld1q_f32(&H[p][ch].re[j]);
+ const float32x4_t im = vld1q_f32(&H[p][ch].im[j]);
+ float32x4_t H2_new = vmulq_f32(re, re);
+ H2_new = vmlaq_f32(H2_new, im, im);
+ float32x4_t H2_p_j = vld1q_f32(&(*H2)[p][j]);
+ H2_p_j = vmaxq_f32(H2_p_j, H2_new);
+ vst1q_f32(&(*H2)[p][j], H2_p_j);
+ }
+ float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] +
+ H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2];
+ (*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new);
+ }
+ }
+}
+#endif
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+// Computes and stores the frequency response of the filter.
+void ComputeFrequencyResponse_Sse2(
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) {
+ for (auto& H2_ch : *H2) {
+ H2_ch.fill(0.f);
+ }
+
+ const size_t num_render_channels = H[0].size();
+ RTC_DCHECK_EQ(H.size(), H2->capacity());
+ // constexpr __mmmask8 kMaxMask = static_cast<__mmmask8>(256u);
+ for (size_t p = 0; p < num_partitions; ++p) {
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size());
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ for (size_t j = 0; j < kFftLengthBy2; j += 4) {
+ const __m128 re = _mm_loadu_ps(&H[p][ch].re[j]);
+ const __m128 re2 = _mm_mul_ps(re, re);
+ const __m128 im = _mm_loadu_ps(&H[p][ch].im[j]);
+ const __m128 im2 = _mm_mul_ps(im, im);
+ const __m128 H2_new = _mm_add_ps(re2, im2);
+ __m128 H2_k_j = _mm_loadu_ps(&(*H2)[p][j]);
+ H2_k_j = _mm_max_ps(H2_k_j, H2_new);
+ _mm_storeu_ps(&(*H2)[p][j], H2_k_j);
+ }
+ float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] +
+ H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2];
+ (*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new);
+ }
+ }
+}
+#endif
+
+// Adapts the filter partitions as H(t+1)=H(t)+G(t)*conj(X(t)).
+void AdaptPartitions(const RenderBuffer& render_buffer,
+ const FftData& G,
+ size_t num_partitions,
+ std::vector<std::vector<FftData>>* H) {
+ rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
+ render_buffer.GetFftBuffer();
+ size_t index = render_buffer.Position();
+ const size_t num_render_channels = render_buffer_data[index].size();
+ for (size_t p = 0; p < num_partitions; ++p) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const FftData& X_p_ch = render_buffer_data[index][ch];
+ FftData& H_p_ch = (*H)[p][ch];
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ H_p_ch.re[k] += X_p_ch.re[k] * G.re[k] + X_p_ch.im[k] * G.im[k];
+ H_p_ch.im[k] += X_p_ch.re[k] * G.im[k] - X_p_ch.im[k] * G.re[k];
+ }
+ }
+ index = index < (render_buffer_data.size() - 1) ? index + 1 : 0;
+ }
+}
+
+#if defined(WEBRTC_HAS_NEON)
+// Adapts the filter partitions. (Neon variant)
+void AdaptPartitions_Neon(const RenderBuffer& render_buffer,
+ const FftData& G,
+ size_t num_partitions,
+ std::vector<std::vector<FftData>>* H) {
+ rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
+ render_buffer.GetFftBuffer();
+ const size_t num_render_channels = render_buffer_data[0].size();
+ const size_t lim1 = std::min(
+ render_buffer_data.size() - render_buffer.Position(), num_partitions);
+ const size_t lim2 = num_partitions;
+ constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4;
+
+ size_t X_partition = render_buffer.Position();
+ size_t limit = lim1;
+ size_t p = 0;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ FftData& H_p_ch = (*H)[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+ for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) {
+ const float32x4_t G_re = vld1q_f32(&G.re[k]);
+ const float32x4_t G_im = vld1q_f32(&G.im[k]);
+ const float32x4_t X_re = vld1q_f32(&X.re[k]);
+ const float32x4_t X_im = vld1q_f32(&X.im[k]);
+ const float32x4_t H_re = vld1q_f32(&H_p_ch.re[k]);
+ const float32x4_t H_im = vld1q_f32(&H_p_ch.im[k]);
+ const float32x4_t a = vmulq_f32(X_re, G_re);
+ const float32x4_t e = vmlaq_f32(a, X_im, G_im);
+ const float32x4_t c = vmulq_f32(X_re, G_im);
+ const float32x4_t f = vmlsq_f32(c, X_im, G_re);
+ const float32x4_t g = vaddq_f32(H_re, e);
+ const float32x4_t h = vaddq_f32(H_im, f);
+ vst1q_f32(&H_p_ch.re[k], g);
+ vst1q_f32(&H_p_ch.im[k], h);
+ }
+ }
+ }
+
+ X_partition = 0;
+ limit = lim2;
+ } while (p < lim2);
+
+ X_partition = render_buffer.Position();
+ limit = lim1;
+ p = 0;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ FftData& H_p_ch = (*H)[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+
+ H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] +
+ X.im[kFftLengthBy2] * G.im[kFftLengthBy2];
+ H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] -
+ X.im[kFftLengthBy2] * G.re[kFftLengthBy2];
+ }
+ }
+ X_partition = 0;
+ limit = lim2;
+ } while (p < lim2);
+}
+#endif
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+// Adapts the filter partitions. (SSE2 variant)
+void AdaptPartitions_Sse2(const RenderBuffer& render_buffer,
+ const FftData& G,
+ size_t num_partitions,
+ std::vector<std::vector<FftData>>* H) {
+ rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
+ render_buffer.GetFftBuffer();
+ const size_t num_render_channels = render_buffer_data[0].size();
+ const size_t lim1 = std::min(
+ render_buffer_data.size() - render_buffer.Position(), num_partitions);
+ const size_t lim2 = num_partitions;
+ constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4;
+
+ size_t X_partition = render_buffer.Position();
+ size_t limit = lim1;
+ size_t p = 0;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ FftData& H_p_ch = (*H)[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+
+ for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) {
+ const __m128 G_re = _mm_loadu_ps(&G.re[k]);
+ const __m128 G_im = _mm_loadu_ps(&G.im[k]);
+ const __m128 X_re = _mm_loadu_ps(&X.re[k]);
+ const __m128 X_im = _mm_loadu_ps(&X.im[k]);
+ const __m128 H_re = _mm_loadu_ps(&H_p_ch.re[k]);
+ const __m128 H_im = _mm_loadu_ps(&H_p_ch.im[k]);
+ const __m128 a = _mm_mul_ps(X_re, G_re);
+ const __m128 b = _mm_mul_ps(X_im, G_im);
+ const __m128 c = _mm_mul_ps(X_re, G_im);
+ const __m128 d = _mm_mul_ps(X_im, G_re);
+ const __m128 e = _mm_add_ps(a, b);
+ const __m128 f = _mm_sub_ps(c, d);
+ const __m128 g = _mm_add_ps(H_re, e);
+ const __m128 h = _mm_add_ps(H_im, f);
+ _mm_storeu_ps(&H_p_ch.re[k], g);
+ _mm_storeu_ps(&H_p_ch.im[k], h);
+ }
+ }
+ }
+ X_partition = 0;
+ limit = lim2;
+ } while (p < lim2);
+
+ X_partition = render_buffer.Position();
+ limit = lim1;
+ p = 0;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ FftData& H_p_ch = (*H)[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+
+ H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] +
+ X.im[kFftLengthBy2] * G.im[kFftLengthBy2];
+ H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] -
+ X.im[kFftLengthBy2] * G.re[kFftLengthBy2];
+ }
+ }
+
+ X_partition = 0;
+ limit = lim2;
+ } while (p < lim2);
+}
+#endif
+
+// Produces the filter output.
+void ApplyFilter(const RenderBuffer& render_buffer,
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ FftData* S) {
+ S->re.fill(0.f);
+ S->im.fill(0.f);
+
+ rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
+ render_buffer.GetFftBuffer();
+ size_t index = render_buffer.Position();
+ const size_t num_render_channels = render_buffer_data[index].size();
+ for (size_t p = 0; p < num_partitions; ++p) {
+ RTC_DCHECK_EQ(num_render_channels, H[p].size());
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const FftData& X_p_ch = render_buffer_data[index][ch];
+ const FftData& H_p_ch = H[p][ch];
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ S->re[k] += X_p_ch.re[k] * H_p_ch.re[k] - X_p_ch.im[k] * H_p_ch.im[k];
+ S->im[k] += X_p_ch.re[k] * H_p_ch.im[k] + X_p_ch.im[k] * H_p_ch.re[k];
+ }
+ }
+ index = index < (render_buffer_data.size() - 1) ? index + 1 : 0;
+ }
+}
+
+#if defined(WEBRTC_HAS_NEON)
+// Produces the filter output (Neon variant).
+void ApplyFilter_Neon(const RenderBuffer& render_buffer,
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ FftData* S) {
+ // const RenderBuffer& render_buffer,
+ // rtc::ArrayView<const FftData> H,
+ // FftData* S) {
+ RTC_DCHECK_GE(H.size(), H.size() - 1);
+ S->Clear();
+
+ rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
+ render_buffer.GetFftBuffer();
+ const size_t num_render_channels = render_buffer_data[0].size();
+ const size_t lim1 = std::min(
+ render_buffer_data.size() - render_buffer.Position(), num_partitions);
+ const size_t lim2 = num_partitions;
+ constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4;
+
+ size_t X_partition = render_buffer.Position();
+ size_t p = 0;
+ size_t limit = lim1;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const FftData& H_p_ch = H[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+ for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) {
+ const float32x4_t X_re = vld1q_f32(&X.re[k]);
+ const float32x4_t X_im = vld1q_f32(&X.im[k]);
+ const float32x4_t H_re = vld1q_f32(&H_p_ch.re[k]);
+ const float32x4_t H_im = vld1q_f32(&H_p_ch.im[k]);
+ const float32x4_t S_re = vld1q_f32(&S->re[k]);
+ const float32x4_t S_im = vld1q_f32(&S->im[k]);
+ const float32x4_t a = vmulq_f32(X_re, H_re);
+ const float32x4_t e = vmlsq_f32(a, X_im, H_im);
+ const float32x4_t c = vmulq_f32(X_re, H_im);
+ const float32x4_t f = vmlaq_f32(c, X_im, H_re);
+ const float32x4_t g = vaddq_f32(S_re, e);
+ const float32x4_t h = vaddq_f32(S_im, f);
+ vst1q_f32(&S->re[k], g);
+ vst1q_f32(&S->im[k], h);
+ }
+ }
+ }
+ limit = lim2;
+ X_partition = 0;
+ } while (p < lim2);
+
+ X_partition = render_buffer.Position();
+ p = 0;
+ limit = lim1;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const FftData& H_p_ch = H[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+ S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] -
+ X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2];
+ S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] +
+ X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2];
+ }
+ }
+ limit = lim2;
+ X_partition = 0;
+ } while (p < lim2);
+}
+#endif
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+// Produces the filter output (SSE2 variant).
+void ApplyFilter_Sse2(const RenderBuffer& render_buffer,
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ FftData* S) {
+ // const RenderBuffer& render_buffer,
+ // rtc::ArrayView<const FftData> H,
+ // FftData* S) {
+ RTC_DCHECK_GE(H.size(), H.size() - 1);
+ S->re.fill(0.f);
+ S->im.fill(0.f);
+
+ rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
+ render_buffer.GetFftBuffer();
+ const size_t num_render_channels = render_buffer_data[0].size();
+ const size_t lim1 = std::min(
+ render_buffer_data.size() - render_buffer.Position(), num_partitions);
+ const size_t lim2 = num_partitions;
+ constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4;
+
+ size_t X_partition = render_buffer.Position();
+ size_t p = 0;
+ size_t limit = lim1;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const FftData& H_p_ch = H[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+ for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) {
+ const __m128 X_re = _mm_loadu_ps(&X.re[k]);
+ const __m128 X_im = _mm_loadu_ps(&X.im[k]);
+ const __m128 H_re = _mm_loadu_ps(&H_p_ch.re[k]);
+ const __m128 H_im = _mm_loadu_ps(&H_p_ch.im[k]);
+ const __m128 S_re = _mm_loadu_ps(&S->re[k]);
+ const __m128 S_im = _mm_loadu_ps(&S->im[k]);
+ const __m128 a = _mm_mul_ps(X_re, H_re);
+ const __m128 b = _mm_mul_ps(X_im, H_im);
+ const __m128 c = _mm_mul_ps(X_re, H_im);
+ const __m128 d = _mm_mul_ps(X_im, H_re);
+ const __m128 e = _mm_sub_ps(a, b);
+ const __m128 f = _mm_add_ps(c, d);
+ const __m128 g = _mm_add_ps(S_re, e);
+ const __m128 h = _mm_add_ps(S_im, f);
+ _mm_storeu_ps(&S->re[k], g);
+ _mm_storeu_ps(&S->im[k], h);
+ }
+ }
+ }
+ limit = lim2;
+ X_partition = 0;
+ } while (p < lim2);
+
+ X_partition = render_buffer.Position();
+ p = 0;
+ limit = lim1;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const FftData& H_p_ch = H[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+ S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] -
+ X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2];
+ S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] +
+ X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2];
+ }
+ }
+ limit = lim2;
+ X_partition = 0;
+ } while (p < lim2);
+}
+#endif
+
+} // namespace aec3
+
+namespace {
+
+// Ensures that the newly added filter partitions after a size increase are set
+// to zero.
+void ZeroFilter(size_t old_size,
+ size_t new_size,
+ std::vector<std::vector<FftData>>* H) {
+ RTC_DCHECK_GE(H->size(), old_size);
+ RTC_DCHECK_GE(H->size(), new_size);
+
+ for (size_t p = old_size; p < new_size; ++p) {
+ RTC_DCHECK_EQ((*H)[p].size(), (*H)[0].size());
+ for (size_t ch = 0; ch < (*H)[0].size(); ++ch) {
+ (*H)[p][ch].Clear();
+ }
+ }
+}
+
+} // namespace
+
+AdaptiveFirFilter::AdaptiveFirFilter(size_t max_size_partitions,
+ size_t initial_size_partitions,
+ size_t size_change_duration_blocks,
+ size_t num_render_channels,
+ Aec3Optimization optimization,
+ ApmDataDumper* data_dumper)
+ : data_dumper_(data_dumper),
+ fft_(),
+ optimization_(optimization),
+ num_render_channels_(num_render_channels),
+ max_size_partitions_(max_size_partitions),
+ size_change_duration_blocks_(
+ static_cast<int>(size_change_duration_blocks)),
+ current_size_partitions_(initial_size_partitions),
+ target_size_partitions_(initial_size_partitions),
+ old_target_size_partitions_(initial_size_partitions),
+ H_(max_size_partitions_, std::vector<FftData>(num_render_channels_)) {
+ RTC_DCHECK(data_dumper_);
+ RTC_DCHECK_GE(max_size_partitions, initial_size_partitions);
+
+ RTC_DCHECK_LT(0, size_change_duration_blocks_);
+ one_by_size_change_duration_blocks_ = 1.f / size_change_duration_blocks_;
+
+ ZeroFilter(0, max_size_partitions_, &H_);
+
+ SetSizePartitions(current_size_partitions_, true);
+}
+
+AdaptiveFirFilter::~AdaptiveFirFilter() = default;
+
+void AdaptiveFirFilter::HandleEchoPathChange() {
+ // TODO(peah): Check the value and purpose of the code below.
+ ZeroFilter(current_size_partitions_, max_size_partitions_, &H_);
+}
+
+void AdaptiveFirFilter::SetSizePartitions(size_t size, bool immediate_effect) {
+ RTC_DCHECK_EQ(max_size_partitions_, H_.capacity());
+ RTC_DCHECK_LE(size, max_size_partitions_);
+
+ target_size_partitions_ = std::min(max_size_partitions_, size);
+ if (immediate_effect) {
+ size_t old_size_partitions_ = current_size_partitions_;
+ current_size_partitions_ = old_target_size_partitions_ =
+ target_size_partitions_;
+ ZeroFilter(old_size_partitions_, current_size_partitions_, &H_);
+
+ partition_to_constrain_ =
+ std::min(partition_to_constrain_, current_size_partitions_ - 1);
+ size_change_counter_ = 0;
+ } else {
+ size_change_counter_ = size_change_duration_blocks_;
+ }
+}
+
+void AdaptiveFirFilter::UpdateSize() {
+ RTC_DCHECK_GE(size_change_duration_blocks_, size_change_counter_);
+ size_t old_size_partitions_ = current_size_partitions_;
+ if (size_change_counter_ > 0) {
+ --size_change_counter_;
+
+ auto average = [](float from, float to, float from_weight) {
+ return from * from_weight + to * (1.f - from_weight);
+ };
+
+ float change_factor =
+ size_change_counter_ * one_by_size_change_duration_blocks_;
+
+ current_size_partitions_ = average(old_target_size_partitions_,
+ target_size_partitions_, change_factor);
+
+ partition_to_constrain_ =
+ std::min(partition_to_constrain_, current_size_partitions_ - 1);
+ } else {
+ current_size_partitions_ = old_target_size_partitions_ =
+ target_size_partitions_;
+ }
+ ZeroFilter(old_size_partitions_, current_size_partitions_, &H_);
+ RTC_DCHECK_LE(0, size_change_counter_);
+}
+
+void AdaptiveFirFilter::Filter(const RenderBuffer& render_buffer,
+ FftData* S) const {
+ RTC_DCHECK(S);
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2:
+ aec3::ApplyFilter_Sse2(render_buffer, current_size_partitions_, H_, S);
+ break;
+ case Aec3Optimization::kAvx2:
+ aec3::ApplyFilter_Avx2(render_buffer, current_size_partitions_, H_, S);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Aec3Optimization::kNeon:
+ aec3::ApplyFilter_Neon(render_buffer, current_size_partitions_, H_, S);
+ break;
+#endif
+ default:
+ aec3::ApplyFilter(render_buffer, current_size_partitions_, H_, S);
+ }
+}
+
+void AdaptiveFirFilter::Adapt(const RenderBuffer& render_buffer,
+ const FftData& G) {
+ // Adapt the filter and update the filter size.
+ AdaptAndUpdateSize(render_buffer, G);
+
+ // Constrain the filter partitions in a cyclic manner.
+ Constrain();
+}
+
+void AdaptiveFirFilter::Adapt(const RenderBuffer& render_buffer,
+ const FftData& G,
+ std::vector<float>* impulse_response) {
+ // Adapt the filter and update the filter size.
+ AdaptAndUpdateSize(render_buffer, G);
+
+ // Constrain the filter partitions in a cyclic manner.
+ ConstrainAndUpdateImpulseResponse(impulse_response);
+}
+
+void AdaptiveFirFilter::ComputeFrequencyResponse(
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) const {
+ RTC_DCHECK_GE(max_size_partitions_, H2->capacity());
+
+ H2->resize(current_size_partitions_);
+
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2:
+ aec3::ComputeFrequencyResponse_Sse2(current_size_partitions_, H_, H2);
+ break;
+ case Aec3Optimization::kAvx2:
+ aec3::ComputeFrequencyResponse_Avx2(current_size_partitions_, H_, H2);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Aec3Optimization::kNeon:
+ aec3::ComputeFrequencyResponse_Neon(current_size_partitions_, H_, H2);
+ break;
+#endif
+ default:
+ aec3::ComputeFrequencyResponse(current_size_partitions_, H_, H2);
+ }
+}
+
+void AdaptiveFirFilter::AdaptAndUpdateSize(const RenderBuffer& render_buffer,
+ const FftData& G) {
+ // Update the filter size if needed.
+ UpdateSize();
+
+ // Adapt the filter.
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2:
+ aec3::AdaptPartitions_Sse2(render_buffer, G, current_size_partitions_,
+ &H_);
+ break;
+ case Aec3Optimization::kAvx2:
+ aec3::AdaptPartitions_Avx2(render_buffer, G, current_size_partitions_,
+ &H_);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Aec3Optimization::kNeon:
+ aec3::AdaptPartitions_Neon(render_buffer, G, current_size_partitions_,
+ &H_);
+ break;
+#endif
+ default:
+ aec3::AdaptPartitions(render_buffer, G, current_size_partitions_, &H_);
+ }
+}
+
+// Constrains the partition of the frequency domain filter to be limited in
+// time via setting the relevant time-domain coefficients to zero and updates
+// the corresponding values in an externally stored impulse response estimate.
+void AdaptiveFirFilter::ConstrainAndUpdateImpulseResponse(
+ std::vector<float>* impulse_response) {
+ RTC_DCHECK_EQ(GetTimeDomainLength(max_size_partitions_),
+ impulse_response->capacity());
+ impulse_response->resize(GetTimeDomainLength(current_size_partitions_));
+ std::array<float, kFftLength> h;
+ impulse_response->resize(GetTimeDomainLength(current_size_partitions_));
+ std::fill(
+ impulse_response->begin() + partition_to_constrain_ * kFftLengthBy2,
+ impulse_response->begin() + (partition_to_constrain_ + 1) * kFftLengthBy2,
+ 0.f);
+
+ for (size_t ch = 0; ch < num_render_channels_; ++ch) {
+ fft_.Ifft(H_[partition_to_constrain_][ch], &h);
+
+ static constexpr float kScale = 1.0f / kFftLengthBy2;
+ std::for_each(h.begin(), h.begin() + kFftLengthBy2,
+ [](float& a) { a *= kScale; });
+ std::fill(h.begin() + kFftLengthBy2, h.end(), 0.f);
+
+ if (ch == 0) {
+ std::copy(
+ h.begin(), h.begin() + kFftLengthBy2,
+ impulse_response->begin() + partition_to_constrain_ * kFftLengthBy2);
+ } else {
+ for (size_t k = 0, j = partition_to_constrain_ * kFftLengthBy2;
+ k < kFftLengthBy2; ++k, ++j) {
+ if (fabsf((*impulse_response)[j]) < fabsf(h[k])) {
+ (*impulse_response)[j] = h[k];
+ }
+ }
+ }
+
+ fft_.Fft(&h, &H_[partition_to_constrain_][ch]);
+ }
+
+ partition_to_constrain_ =
+ partition_to_constrain_ < (current_size_partitions_ - 1)
+ ? partition_to_constrain_ + 1
+ : 0;
+}
+
+// Constrains the a partiton of the frequency domain filter to be limited in
+// time via setting the relevant time-domain coefficients to zero.
+void AdaptiveFirFilter::Constrain() {
+ std::array<float, kFftLength> h;
+ for (size_t ch = 0; ch < num_render_channels_; ++ch) {
+ fft_.Ifft(H_[partition_to_constrain_][ch], &h);
+
+ static constexpr float kScale = 1.0f / kFftLengthBy2;
+ std::for_each(h.begin(), h.begin() + kFftLengthBy2,
+ [](float& a) { a *= kScale; });
+ std::fill(h.begin() + kFftLengthBy2, h.end(), 0.f);
+
+ fft_.Fft(&h, &H_[partition_to_constrain_][ch]);
+ }
+
+ partition_to_constrain_ =
+ partition_to_constrain_ < (current_size_partitions_ - 1)
+ ? partition_to_constrain_ + 1
+ : 0;
+}
+
+void AdaptiveFirFilter::ScaleFilter(float factor) {
+ for (auto& H_p : H_) {
+ for (auto& H_p_ch : H_p) {
+ for (auto& re : H_p_ch.re) {
+ re *= factor;
+ }
+ for (auto& im : H_p_ch.im) {
+ im *= factor;
+ }
+ }
+ }
+}
+
+// Set the filter coefficients.
+void AdaptiveFirFilter::SetFilter(size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H) {
+ const size_t min_num_partitions =
+ std::min(current_size_partitions_, num_partitions);
+ for (size_t p = 0; p < min_num_partitions; ++p) {
+ RTC_DCHECK_EQ(H_[p].size(), H[p].size());
+ RTC_DCHECK_EQ(num_render_channels_, H_[p].size());
+
+ for (size_t ch = 0; ch < num_render_channels_; ++ch) {
+ std::copy(H[p][ch].re.begin(), H[p][ch].re.end(), H_[p][ch].re.begin());
+ std::copy(H[p][ch].im.begin(), H[p][ch].im.end(), H_[p][ch].im.begin());
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h
new file mode 100644
index 0000000..7597709
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h
@@ -0,0 +1,191 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec3_fft.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+namespace aec3 {
+// Computes and stores the frequency response of the filter.
+void ComputeFrequencyResponse(
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2);
+#if defined(WEBRTC_HAS_NEON)
+void ComputeFrequencyResponse_Neon(
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2);
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+void ComputeFrequencyResponse_Sse2(
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2);
+
+void ComputeFrequencyResponse_Avx2(
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2);
+#endif
+
+// Adapts the filter partitions.
+void AdaptPartitions(const RenderBuffer& render_buffer,
+ const FftData& G,
+ size_t num_partitions,
+ std::vector<std::vector<FftData>>* H);
+#if defined(WEBRTC_HAS_NEON)
+void AdaptPartitions_Neon(const RenderBuffer& render_buffer,
+ const FftData& G,
+ size_t num_partitions,
+ std::vector<std::vector<FftData>>* H);
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+void AdaptPartitions_Sse2(const RenderBuffer& render_buffer,
+ const FftData& G,
+ size_t num_partitions,
+ std::vector<std::vector<FftData>>* H);
+
+void AdaptPartitions_Avx2(const RenderBuffer& render_buffer,
+ const FftData& G,
+ size_t num_partitions,
+ std::vector<std::vector<FftData>>* H);
+#endif
+
+// Produces the filter output.
+void ApplyFilter(const RenderBuffer& render_buffer,
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ FftData* S);
+#if defined(WEBRTC_HAS_NEON)
+void ApplyFilter_Neon(const RenderBuffer& render_buffer,
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ FftData* S);
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+void ApplyFilter_Sse2(const RenderBuffer& render_buffer,
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ FftData* S);
+
+void ApplyFilter_Avx2(const RenderBuffer& render_buffer,
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ FftData* S);
+#endif
+
+} // namespace aec3
+
+// Provides a frequency domain adaptive filter functionality.
+class AdaptiveFirFilter {
+ public:
+ AdaptiveFirFilter(size_t max_size_partitions,
+ size_t initial_size_partitions,
+ size_t size_change_duration_blocks,
+ size_t num_render_channels,
+ Aec3Optimization optimization,
+ ApmDataDumper* data_dumper);
+
+ ~AdaptiveFirFilter();
+
+ AdaptiveFirFilter(const AdaptiveFirFilter&) = delete;
+ AdaptiveFirFilter& operator=(const AdaptiveFirFilter&) = delete;
+
+ // Produces the output of the filter.
+ void Filter(const RenderBuffer& render_buffer, FftData* S) const;
+
+ // Adapts the filter and updates an externally stored impulse response
+ // estimate.
+ void Adapt(const RenderBuffer& render_buffer,
+ const FftData& G,
+ std::vector<float>* impulse_response);
+
+ // Adapts the filter.
+ void Adapt(const RenderBuffer& render_buffer, const FftData& G);
+
+ // Receives reports that known echo path changes have occured and adjusts
+ // the filter adaptation accordingly.
+ void HandleEchoPathChange();
+
+ // Returns the filter size.
+ size_t SizePartitions() const { return current_size_partitions_; }
+
+ // Sets the filter size.
+ void SetSizePartitions(size_t size, bool immediate_effect);
+
+ // Computes the frequency responses for the filter partitions.
+ void ComputeFrequencyResponse(
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) const;
+
+ // Returns the maximum number of partitions for the filter.
+ size_t max_filter_size_partitions() const { return max_size_partitions_; }
+
+ void DumpFilter(const char* name_frequency_domain) {
+ for (size_t p = 0; p < max_size_partitions_; ++p) {
+ data_dumper_->DumpRaw(name_frequency_domain, H_[p][0].re);
+ data_dumper_->DumpRaw(name_frequency_domain, H_[p][0].im);
+ }
+ }
+
+ // Scale the filter impulse response and spectrum by a factor.
+ void ScaleFilter(float factor);
+
+ // Set the filter coefficients.
+ void SetFilter(size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H);
+
+ // Gets the filter coefficients.
+ const std::vector<std::vector<FftData>>& GetFilter() const { return H_; }
+
+ private:
+ // Adapts the filter and updates the filter size.
+ void AdaptAndUpdateSize(const RenderBuffer& render_buffer, const FftData& G);
+
+ // Constrain the filter partitions in a cyclic manner.
+ void Constrain();
+ // Constrains the filter in a cyclic manner and updates the corresponding
+ // values in the supplied impulse response.
+ void ConstrainAndUpdateImpulseResponse(std::vector<float>* impulse_response);
+
+ // Gradually Updates the current filter size towards the target size.
+ void UpdateSize();
+
+ ApmDataDumper* const data_dumper_;
+ const Aec3Fft fft_;
+ const Aec3Optimization optimization_;
+ const size_t num_render_channels_;
+ const size_t max_size_partitions_;
+ const int size_change_duration_blocks_;
+ float one_by_size_change_duration_blocks_;
+ size_t current_size_partitions_;
+ size_t target_size_partitions_;
+ size_t old_target_size_partitions_;
+ int size_change_counter_ = 0;
+ std::vector<std::vector<FftData>> H_;
+ size_t partition_to_constrain_ = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_avx2.cc b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_avx2.cc
new file mode 100644
index 0000000..245b45a
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_avx2.cc
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/adaptive_fir_filter.h"
+
+#include <immintrin.h>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace aec3 {
+
+// Computes and stores the frequency response of the filter.
+void ComputeFrequencyResponse_Avx2(
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) {
+ for (auto& H2_ch : *H2) {
+ H2_ch.fill(0.f);
+ }
+
+ const size_t num_render_channels = H[0].size();
+ RTC_DCHECK_EQ(H.size(), H2->capacity());
+ for (size_t p = 0; p < num_partitions; ++p) {
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size());
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ for (size_t j = 0; j < kFftLengthBy2; j += 8) {
+ __m256 re = _mm256_loadu_ps(&H[p][ch].re[j]);
+ __m256 re2 = _mm256_mul_ps(re, re);
+ __m256 im = _mm256_loadu_ps(&H[p][ch].im[j]);
+ re2 = _mm256_fmadd_ps(im, im, re2);
+ __m256 H2_k_j = _mm256_loadu_ps(&(*H2)[p][j]);
+ H2_k_j = _mm256_max_ps(H2_k_j, re2);
+ _mm256_storeu_ps(&(*H2)[p][j], H2_k_j);
+ }
+ float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] +
+ H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2];
+ (*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new);
+ }
+ }
+}
+
+// Adapts the filter partitions.
+void AdaptPartitions_Avx2(const RenderBuffer& render_buffer,
+ const FftData& G,
+ size_t num_partitions,
+ std::vector<std::vector<FftData>>* H) {
+ rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
+ render_buffer.GetFftBuffer();
+ const size_t num_render_channels = render_buffer_data[0].size();
+ const size_t lim1 = std::min(
+ render_buffer_data.size() - render_buffer.Position(), num_partitions);
+ const size_t lim2 = num_partitions;
+ constexpr size_t kNumEightBinBands = kFftLengthBy2 / 8;
+
+ size_t X_partition = render_buffer.Position();
+ size_t limit = lim1;
+ size_t p = 0;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ FftData& H_p_ch = (*H)[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+
+ for (size_t k = 0, n = 0; n < kNumEightBinBands; ++n, k += 8) {
+ const __m256 G_re = _mm256_loadu_ps(&G.re[k]);
+ const __m256 G_im = _mm256_loadu_ps(&G.im[k]);
+ const __m256 X_re = _mm256_loadu_ps(&X.re[k]);
+ const __m256 X_im = _mm256_loadu_ps(&X.im[k]);
+ const __m256 H_re = _mm256_loadu_ps(&H_p_ch.re[k]);
+ const __m256 H_im = _mm256_loadu_ps(&H_p_ch.im[k]);
+ const __m256 a = _mm256_mul_ps(X_re, G_re);
+ const __m256 b = _mm256_mul_ps(X_im, G_im);
+ const __m256 c = _mm256_mul_ps(X_re, G_im);
+ const __m256 d = _mm256_mul_ps(X_im, G_re);
+ const __m256 e = _mm256_add_ps(a, b);
+ const __m256 f = _mm256_sub_ps(c, d);
+ const __m256 g = _mm256_add_ps(H_re, e);
+ const __m256 h = _mm256_add_ps(H_im, f);
+ _mm256_storeu_ps(&H_p_ch.re[k], g);
+ _mm256_storeu_ps(&H_p_ch.im[k], h);
+ }
+ }
+ }
+ X_partition = 0;
+ limit = lim2;
+ } while (p < lim2);
+
+ X_partition = render_buffer.Position();
+ limit = lim1;
+ p = 0;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ FftData& H_p_ch = (*H)[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+
+ H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] +
+ X.im[kFftLengthBy2] * G.im[kFftLengthBy2];
+ H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] -
+ X.im[kFftLengthBy2] * G.re[kFftLengthBy2];
+ }
+ }
+
+ X_partition = 0;
+ limit = lim2;
+ } while (p < lim2);
+}
+
+// Produces the filter output (AVX2 variant).
+void ApplyFilter_Avx2(const RenderBuffer& render_buffer,
+ size_t num_partitions,
+ const std::vector<std::vector<FftData>>& H,
+ FftData* S) {
+ RTC_DCHECK_GE(H.size(), H.size() - 1);
+ S->re.fill(0.f);
+ S->im.fill(0.f);
+
+ rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
+ render_buffer.GetFftBuffer();
+ const size_t num_render_channels = render_buffer_data[0].size();
+ const size_t lim1 = std::min(
+ render_buffer_data.size() - render_buffer.Position(), num_partitions);
+ const size_t lim2 = num_partitions;
+ constexpr size_t kNumEightBinBands = kFftLengthBy2 / 8;
+
+ size_t X_partition = render_buffer.Position();
+ size_t p = 0;
+ size_t limit = lim1;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const FftData& H_p_ch = H[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+ for (size_t k = 0, n = 0; n < kNumEightBinBands; ++n, k += 8) {
+ const __m256 X_re = _mm256_loadu_ps(&X.re[k]);
+ const __m256 X_im = _mm256_loadu_ps(&X.im[k]);
+ const __m256 H_re = _mm256_loadu_ps(&H_p_ch.re[k]);
+ const __m256 H_im = _mm256_loadu_ps(&H_p_ch.im[k]);
+ const __m256 S_re = _mm256_loadu_ps(&S->re[k]);
+ const __m256 S_im = _mm256_loadu_ps(&S->im[k]);
+ const __m256 a = _mm256_mul_ps(X_re, H_re);
+ const __m256 b = _mm256_mul_ps(X_im, H_im);
+ const __m256 c = _mm256_mul_ps(X_re, H_im);
+ const __m256 d = _mm256_mul_ps(X_im, H_re);
+ const __m256 e = _mm256_sub_ps(a, b);
+ const __m256 f = _mm256_add_ps(c, d);
+ const __m256 g = _mm256_add_ps(S_re, e);
+ const __m256 h = _mm256_add_ps(S_im, f);
+ _mm256_storeu_ps(&S->re[k], g);
+ _mm256_storeu_ps(&S->im[k], h);
+ }
+ }
+ }
+ limit = lim2;
+ X_partition = 0;
+ } while (p < lim2);
+
+ X_partition = render_buffer.Position();
+ p = 0;
+ limit = lim1;
+ do {
+ for (; p < limit; ++p, ++X_partition) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const FftData& H_p_ch = H[p][ch];
+ const FftData& X = render_buffer_data[X_partition][ch];
+ S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] -
+ X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2];
+ S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] +
+ X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2];
+ }
+ }
+ limit = lim2;
+ X_partition = 0;
+ } while (p < lim2);
+}
+
+} // namespace aec3
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc
new file mode 100644
index 0000000..45b8813
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h"
+
+#include <algorithm>
+#include <functional>
+
+#if defined(WEBRTC_HAS_NEON)
+#include <arm_neon.h>
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#include <emmintrin.h>
+#endif
+
+namespace webrtc {
+
+namespace aec3 {
+
+// Computes and stores the echo return loss estimate of the filter, which is the
+// sum of the partition frequency responses.
+void ErlComputer(const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl) {
+ std::fill(erl.begin(), erl.end(), 0.f);
+ for (auto& H2_j : H2) {
+ std::transform(H2_j.begin(), H2_j.end(), erl.begin(), erl.begin(),
+ std::plus<float>());
+ }
+}
+
+#if defined(WEBRTC_HAS_NEON)
+// Computes and stores the echo return loss estimate of the filter, which is the
+// sum of the partition frequency responses.
+void ErlComputer_NEON(
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl) {
+ std::fill(erl.begin(), erl.end(), 0.f);
+ for (auto& H2_j : H2) {
+ for (size_t k = 0; k < kFftLengthBy2; k += 4) {
+ const float32x4_t H2_j_k = vld1q_f32(&H2_j[k]);
+ float32x4_t erl_k = vld1q_f32(&erl[k]);
+ erl_k = vaddq_f32(erl_k, H2_j_k);
+ vst1q_f32(&erl[k], erl_k);
+ }
+ erl[kFftLengthBy2] += H2_j[kFftLengthBy2];
+ }
+}
+#endif
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+// Computes and stores the echo return loss estimate of the filter, which is the
+// sum of the partition frequency responses.
+void ErlComputer_SSE2(
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl) {
+ std::fill(erl.begin(), erl.end(), 0.f);
+ for (auto& H2_j : H2) {
+ for (size_t k = 0; k < kFftLengthBy2; k += 4) {
+ const __m128 H2_j_k = _mm_loadu_ps(&H2_j[k]);
+ __m128 erl_k = _mm_loadu_ps(&erl[k]);
+ erl_k = _mm_add_ps(erl_k, H2_j_k);
+ _mm_storeu_ps(&erl[k], erl_k);
+ }
+ erl[kFftLengthBy2] += H2_j[kFftLengthBy2];
+ }
+}
+#endif
+
+} // namespace aec3
+
+void ComputeErl(const Aec3Optimization& optimization,
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl) {
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, erl.size());
+ // Update the frequency response and echo return loss for the filter.
+ switch (optimization) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2:
+ aec3::ErlComputer_SSE2(H2, erl);
+ break;
+ case Aec3Optimization::kAvx2:
+ aec3::ErlComputer_AVX2(H2, erl);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Aec3Optimization::kNeon:
+ aec3::ErlComputer_NEON(H2, erl);
+ break;
+#endif
+ default:
+ aec3::ErlComputer(H2, erl);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.h b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.h
new file mode 100644
index 0000000..4ac13b1
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+namespace aec3 {
+
+// Computes and stores the echo return loss estimate of the filter, which is the
+// sum of the partition frequency responses.
+void ErlComputer(const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl);
+#if defined(WEBRTC_HAS_NEON)
+void ErlComputer_NEON(
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl);
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+void ErlComputer_SSE2(
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl);
+
+void ErlComputer_AVX2(
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl);
+#endif
+
+} // namespace aec3
+
+// Computes the echo return loss based on a frequency response.
+void ComputeErl(const Aec3Optimization& optimization,
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl);
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_
diff --git a/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl_avx2.cc b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl_avx2.cc
new file mode 100644
index 0000000..5fe7514
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl_avx2.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h"
+
+#include <immintrin.h>
+
+namespace webrtc {
+
+namespace aec3 {
+
+// Computes and stores the echo return loss estimate of the filter, which is the
+// sum of the partition frequency responses.
+void ErlComputer_AVX2(
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
+ rtc::ArrayView<float> erl) {
+ std::fill(erl.begin(), erl.end(), 0.f);
+ for (auto& H2_j : H2) {
+ for (size_t k = 0; k < kFftLengthBy2; k += 8) {
+ const __m256 H2_j_k = _mm256_loadu_ps(&H2_j[k]);
+ __m256 erl_k = _mm256_loadu_ps(&erl[k]);
+ erl_k = _mm256_add_ps(erl_k, H2_j_k);
+ _mm256_storeu_ps(&erl[k], erl_k);
+ }
+ erl[kFftLengthBy2] += H2_j[kFftLengthBy2];
+ }
+}
+
+} // namespace aec3
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/aec3_common.cc b/webrtc/modules/audio_processing/aec3/aec3_common.cc
new file mode 100644
index 0000000..7bd8d62
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/aec3_common.cc
@@ -0,0 +1,58 @@
+/*
+ * 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/audio_processing/aec3/aec3_common.h"
+
+#include <stdint.h>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/system/arch.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+
+namespace webrtc {
+
+Aec3Optimization DetectOptimization() {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ if (GetCPUInfo(kAVX2) != 0) {
+ return Aec3Optimization::kAvx2;
+ } else if (GetCPUInfo(kSSE2) != 0) {
+ return Aec3Optimization::kSse2;
+ }
+#endif
+
+#if defined(WEBRTC_HAS_NEON)
+ return Aec3Optimization::kNeon;
+#endif
+
+ return Aec3Optimization::kNone;
+}
+
+float FastApproxLog2f(const float in) {
+ RTC_DCHECK_GT(in, .0f);
+ // Read and interpret float as uint32_t and then cast to float.
+ // This is done to extract the exponent (bits 30 - 23).
+ // "Right shift" of the exponent is then performed by multiplying
+ // with the constant (1/2^23). Finally, we subtract a constant to
+ // remove the bias (https://en.wikipedia.org/wiki/Exponent_bias).
+ union {
+ float dummy;
+ uint32_t a;
+ } x = {in};
+ float out = x.a;
+ out *= 1.1920929e-7f; // 1/2^23
+ out -= 126.942695f; // Remove bias.
+ return out;
+}
+
+float Log2TodB(const float in_log2) {
+ return 3.0102999566398121 * in_log2;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/aec3_common.h b/webrtc/modules/audio_processing/aec3/aec3_common.h
new file mode 100644
index 0000000..a7e3121
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/aec3_common.h
@@ -0,0 +1,114 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_
+
+#include <stddef.h>
+
+namespace webrtc {
+
+#ifdef _MSC_VER /* visual c++ */
+#define ALIGN16_BEG __declspec(align(16))
+#define ALIGN16_END
+#else /* gcc or icc */
+#define ALIGN16_BEG
+#define ALIGN16_END __attribute__((aligned(16)))
+#endif
+
+enum class Aec3Optimization { kNone, kSse2, kAvx2, kNeon };
+
+constexpr int kNumBlocksPerSecond = 250;
+
+constexpr int kMetricsReportingIntervalBlocks = 10 * kNumBlocksPerSecond;
+constexpr int kMetricsComputationBlocks = 7;
+constexpr int kMetricsCollectionBlocks =
+ kMetricsReportingIntervalBlocks - kMetricsComputationBlocks;
+
+constexpr size_t kFftLengthBy2 = 64;
+constexpr size_t kFftLengthBy2Plus1 = kFftLengthBy2 + 1;
+constexpr size_t kFftLengthBy2Minus1 = kFftLengthBy2 - 1;
+constexpr size_t kFftLength = 2 * kFftLengthBy2;
+constexpr size_t kFftLengthBy2Log2 = 6;
+
+constexpr int kRenderTransferQueueSizeFrames = 100;
+
+constexpr size_t kMaxNumBands = 3;
+constexpr size_t kFrameSize = 160;
+constexpr size_t kSubFrameLength = kFrameSize / 2;
+
+constexpr size_t kBlockSize = kFftLengthBy2;
+constexpr size_t kBlockSizeLog2 = kFftLengthBy2Log2;
+
+constexpr size_t kExtendedBlockSize = 2 * kFftLengthBy2;
+constexpr size_t kMatchedFilterWindowSizeSubBlocks = 32;
+constexpr size_t kMatchedFilterAlignmentShiftSizeSubBlocks =
+ kMatchedFilterWindowSizeSubBlocks * 3 / 4;
+
+// TODO(peah): Integrate this with how it is done inside audio_processing_impl.
+constexpr size_t NumBandsForRate(int sample_rate_hz) {
+ return static_cast<size_t>(sample_rate_hz / 16000);
+}
+
+constexpr bool ValidFullBandRate(int sample_rate_hz) {
+ return sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
+ sample_rate_hz == 48000;
+}
+
+constexpr int GetTimeDomainLength(int filter_length_blocks) {
+ return filter_length_blocks * kFftLengthBy2;
+}
+
+constexpr size_t GetDownSampledBufferSize(size_t down_sampling_factor,
+ size_t num_matched_filters) {
+ return kBlockSize / down_sampling_factor *
+ (kMatchedFilterAlignmentShiftSizeSubBlocks * num_matched_filters +
+ kMatchedFilterWindowSizeSubBlocks + 1);
+}
+
+constexpr size_t GetRenderDelayBufferSize(size_t down_sampling_factor,
+ size_t num_matched_filters,
+ size_t filter_length_blocks) {
+ return GetDownSampledBufferSize(down_sampling_factor, num_matched_filters) /
+ (kBlockSize / down_sampling_factor) +
+ filter_length_blocks + 1;
+}
+
+// Detects what kind of optimizations to use for the code.
+Aec3Optimization DetectOptimization();
+
+// Computes the log2 of the input in a fast an approximate manner.
+float FastApproxLog2f(const float in);
+
+// Returns dB from a power quantity expressed in log2.
+float Log2TodB(const float in_log2);
+
+static_assert(1 << kBlockSizeLog2 == kBlockSize,
+ "Proper number of shifts for blocksize");
+
+static_assert(1 << kFftLengthBy2Log2 == kFftLengthBy2,
+ "Proper number of shifts for the fft length");
+
+static_assert(1 == NumBandsForRate(16000), "Number of bands for 16 kHz");
+static_assert(2 == NumBandsForRate(32000), "Number of bands for 32 kHz");
+static_assert(3 == NumBandsForRate(48000), "Number of bands for 48 kHz");
+
+static_assert(ValidFullBandRate(16000),
+ "Test that 16 kHz is a valid sample rate");
+static_assert(ValidFullBandRate(32000),
+ "Test that 32 kHz is a valid sample rate");
+static_assert(ValidFullBandRate(48000),
+ "Test that 48 kHz is a valid sample rate");
+static_assert(!ValidFullBandRate(8001),
+ "Test that 8001 Hz is not a valid sample rate");
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_
diff --git a/webrtc/modules/audio_processing/aec3/aec3_fft.cc b/webrtc/modules/audio_processing/aec3/aec3_fft.cc
new file mode 100644
index 0000000..8dfa183
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/aec3_fft.cc
@@ -0,0 +1,144 @@
+/*
+ * 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/audio_processing/aec3/aec3_fft.h"
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+
+namespace webrtc {
+
+namespace {
+
+const float kHanning64[kFftLengthBy2] = {
+ 0.f, 0.00248461f, 0.00991376f, 0.0222136f, 0.03926189f,
+ 0.06088921f, 0.08688061f, 0.11697778f, 0.15088159f, 0.1882551f,
+ 0.22872687f, 0.27189467f, 0.31732949f, 0.36457977f, 0.41317591f,
+ 0.46263495f, 0.51246535f, 0.56217185f, 0.61126047f, 0.65924333f,
+ 0.70564355f, 0.75f, 0.79187184f, 0.83084292f, 0.86652594f,
+ 0.89856625f, 0.92664544f, 0.95048443f, 0.96984631f, 0.98453864f,
+ 0.99441541f, 0.99937846f, 0.99937846f, 0.99441541f, 0.98453864f,
+ 0.96984631f, 0.95048443f, 0.92664544f, 0.89856625f, 0.86652594f,
+ 0.83084292f, 0.79187184f, 0.75f, 0.70564355f, 0.65924333f,
+ 0.61126047f, 0.56217185f, 0.51246535f, 0.46263495f, 0.41317591f,
+ 0.36457977f, 0.31732949f, 0.27189467f, 0.22872687f, 0.1882551f,
+ 0.15088159f, 0.11697778f, 0.08688061f, 0.06088921f, 0.03926189f,
+ 0.0222136f, 0.00991376f, 0.00248461f, 0.f};
+
+// Hanning window from Matlab command win = sqrt(hanning(128)).
+const float kSqrtHanning128[kFftLength] = {
+ 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
+ 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
+ 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
+ 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
+ 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
+ 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
+ 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
+ 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
+ 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
+ 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
+ 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
+ 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
+ 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
+ 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
+ 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
+ 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
+ 1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
+ 0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f,
+ 0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f,
+ 0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
+ 0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f,
+ 0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f,
+ 0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
+ 0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f,
+ 0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f,
+ 0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
+ 0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f,
+ 0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f,
+ 0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
+ 0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f,
+ 0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f,
+ 0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f};
+
+bool IsSse2Available() {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ return GetCPUInfo(kSSE2) != 0;
+#else
+ return false;
+#endif
+}
+
+} // namespace
+
+Aec3Fft::Aec3Fft() : ooura_fft_(IsSse2Available()) {}
+
+// TODO(peah): Change x to be std::array once the rest of the code allows this.
+void Aec3Fft::ZeroPaddedFft(rtc::ArrayView<const float> x,
+ Window window,
+ FftData* X) const {
+ RTC_DCHECK(X);
+ RTC_DCHECK_EQ(kFftLengthBy2, x.size());
+ std::array<float, kFftLength> fft;
+ std::fill(fft.begin(), fft.begin() + kFftLengthBy2, 0.f);
+ switch (window) {
+ case Window::kRectangular:
+ std::copy(x.begin(), x.end(), fft.begin() + kFftLengthBy2);
+ break;
+ case Window::kHanning:
+ std::transform(x.begin(), x.end(), std::begin(kHanning64),
+ fft.begin() + kFftLengthBy2,
+ [](float a, float b) { return a * b; });
+ break;
+ case Window::kSqrtHanning:
+ RTC_NOTREACHED();
+ break;
+ default:
+ RTC_NOTREACHED();
+ }
+
+ Fft(&fft, X);
+}
+
+void Aec3Fft::PaddedFft(rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> x_old,
+ Window window,
+ FftData* X) const {
+ RTC_DCHECK(X);
+ RTC_DCHECK_EQ(kFftLengthBy2, x.size());
+ RTC_DCHECK_EQ(kFftLengthBy2, x_old.size());
+ std::array<float, kFftLength> fft;
+
+ switch (window) {
+ case Window::kRectangular:
+ std::copy(x_old.begin(), x_old.end(), fft.begin());
+ std::copy(x.begin(), x.end(), fft.begin() + x_old.size());
+ break;
+ case Window::kHanning:
+ RTC_NOTREACHED();
+ break;
+ case Window::kSqrtHanning:
+ std::transform(x_old.begin(), x_old.end(), std::begin(kSqrtHanning128),
+ fft.begin(), std::multiplies<float>());
+ std::transform(x.begin(), x.end(),
+ std::begin(kSqrtHanning128) + x_old.size(),
+ fft.begin() + x_old.size(), std::multiplies<float>());
+ break;
+ default:
+ RTC_NOTREACHED();
+ }
+
+ Fft(&fft, X);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/aec3_fft.h b/webrtc/modules/audio_processing/aec3/aec3_fft.h
new file mode 100644
index 0000000..6f7fbe4
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/aec3_fft.h
@@ -0,0 +1,75 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Wrapper class that provides 128 point real valued FFT functionality with the
+// FftData type.
+class Aec3Fft {
+ public:
+ enum class Window { kRectangular, kHanning, kSqrtHanning };
+
+ Aec3Fft();
+
+ // Computes the FFT. Note that both the input and output are modified.
+ void Fft(std::array<float, kFftLength>* x, FftData* X) const {
+ RTC_DCHECK(x);
+ RTC_DCHECK(X);
+ ooura_fft_.Fft(x->data());
+ X->CopyFromPackedArray(*x);
+ }
+ // Computes the inverse Fft.
+ void Ifft(const FftData& X, std::array<float, kFftLength>* x) const {
+ RTC_DCHECK(x);
+ X.CopyToPackedArray(x);
+ ooura_fft_.InverseFft(x->data());
+ }
+
+ // Windows the input using a Hanning window, and then adds padding of
+ // kFftLengthBy2 initial zeros before computing the Fft.
+ void ZeroPaddedFft(rtc::ArrayView<const float> x,
+ Window window,
+ FftData* X) const;
+
+ // Concatenates the kFftLengthBy2 values long x and x_old before computing the
+ // Fft. After that, x is copied to x_old.
+ void PaddedFft(rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> x_old,
+ FftData* X) const {
+ PaddedFft(x, x_old, Window::kRectangular, X);
+ }
+
+ // Padded Fft using a time-domain window.
+ void PaddedFft(rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> x_old,
+ Window window,
+ FftData* X) const;
+
+ private:
+ const OouraFft ooura_fft_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(Aec3Fft);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_
diff --git a/webrtc/modules/audio_processing/aec3/aec_state.cc b/webrtc/modules/audio_processing/aec3/aec_state.cc
new file mode 100644
index 0000000..df56c3a
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/aec_state.cc
@@ -0,0 +1,477 @@
+/*
+ * 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/audio_processing/aec3/aec_state.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <numeric>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+namespace {
+
+bool DeactivateInitialStateResetAtEchoPathChange() {
+ return field_trial::IsEnabled(
+ "WebRTC-Aec3DeactivateInitialStateResetKillSwitch");
+}
+
+bool FullResetAtEchoPathChange() {
+ return !field_trial::IsEnabled("WebRTC-Aec3AecStateFullResetKillSwitch");
+}
+
+bool SubtractorAnalyzerResetAtEchoPathChange() {
+ return !field_trial::IsEnabled(
+ "WebRTC-Aec3AecStateSubtractorAnalyzerResetKillSwitch");
+}
+
+void ComputeAvgRenderReverb(
+ const SpectrumBuffer& spectrum_buffer,
+ int delay_blocks,
+ float reverb_decay,
+ ReverbModel* reverb_model,
+ rtc::ArrayView<float, kFftLengthBy2Plus1> reverb_power_spectrum) {
+ RTC_DCHECK(reverb_model);
+ const size_t num_render_channels = spectrum_buffer.buffer[0].size();
+ int idx_at_delay =
+ spectrum_buffer.OffsetIndex(spectrum_buffer.read, delay_blocks);
+ int idx_past = spectrum_buffer.IncIndex(idx_at_delay);
+
+ std::array<float, kFftLengthBy2Plus1> X2_data;
+ rtc::ArrayView<const float> X2;
+ if (num_render_channels > 1) {
+ auto average_channels =
+ [](size_t num_render_channels,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ spectrum_band_0,
+ rtc::ArrayView<float, kFftLengthBy2Plus1> render_power) {
+ std::fill(render_power.begin(), render_power.end(), 0.f);
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ render_power[k] += spectrum_band_0[ch][k];
+ }
+ }
+ const float normalizer = 1.f / num_render_channels;
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ render_power[k] *= normalizer;
+ }
+ };
+ average_channels(num_render_channels, spectrum_buffer.buffer[idx_past],
+ X2_data);
+ reverb_model->UpdateReverbNoFreqShaping(
+ X2_data, /*power_spectrum_scaling=*/1.0f, reverb_decay);
+
+ average_channels(num_render_channels, spectrum_buffer.buffer[idx_at_delay],
+ X2_data);
+ X2 = X2_data;
+ } else {
+ reverb_model->UpdateReverbNoFreqShaping(
+ spectrum_buffer.buffer[idx_past][/*channel=*/0],
+ /*power_spectrum_scaling=*/1.0f, reverb_decay);
+
+ X2 = spectrum_buffer.buffer[idx_at_delay][/*channel=*/0];
+ }
+
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> reverb_power =
+ reverb_model->reverb();
+ for (size_t k = 0; k < X2.size(); ++k) {
+ reverb_power_spectrum[k] = X2[k] + reverb_power[k];
+ }
+}
+
+} // namespace
+
+int AecState::instance_count_ = 0;
+
+void AecState::GetResidualEchoScaling(
+ rtc::ArrayView<float> residual_scaling) const {
+ bool filter_has_had_time_to_converge;
+ if (config_.filter.conservative_initial_phase) {
+ filter_has_had_time_to_converge =
+ strong_not_saturated_render_blocks_ >= 1.5f * kNumBlocksPerSecond;
+ } else {
+ filter_has_had_time_to_converge =
+ strong_not_saturated_render_blocks_ >= 0.8f * kNumBlocksPerSecond;
+ }
+ echo_audibility_.GetResidualEchoScaling(filter_has_had_time_to_converge,
+ residual_scaling);
+}
+
+absl::optional<float> AecState::ErleUncertainty() const {
+ if (SaturatedEcho()) {
+ return 1.f;
+ }
+
+ return absl::nullopt;
+}
+
+AecState::AecState(const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ config_(config),
+ num_capture_channels_(num_capture_channels),
+ deactivate_initial_state_reset_at_echo_path_change_(
+ DeactivateInitialStateResetAtEchoPathChange()),
+ full_reset_at_echo_path_change_(FullResetAtEchoPathChange()),
+ subtractor_analyzer_reset_at_echo_path_change_(
+ SubtractorAnalyzerResetAtEchoPathChange()),
+ initial_state_(config_),
+ delay_state_(config_, num_capture_channels_),
+ transparent_state_(TransparentMode::Create(config_)),
+ filter_quality_state_(config_, num_capture_channels_),
+ erl_estimator_(2 * kNumBlocksPerSecond),
+ erle_estimator_(2 * kNumBlocksPerSecond, config_, num_capture_channels_),
+ filter_analyzer_(config_, num_capture_channels_),
+ echo_audibility_(
+ config_.echo_audibility.use_stationarity_properties_at_init),
+ reverb_model_estimator_(config_, num_capture_channels_),
+ subtractor_output_analyzer_(num_capture_channels_) {}
+
+AecState::~AecState() = default;
+
+void AecState::HandleEchoPathChange(
+ const EchoPathVariability& echo_path_variability) {
+ const auto full_reset = [&]() {
+ filter_analyzer_.Reset();
+ capture_signal_saturation_ = false;
+ strong_not_saturated_render_blocks_ = 0;
+ blocks_with_active_render_ = 0;
+ if (!deactivate_initial_state_reset_at_echo_path_change_) {
+ initial_state_.Reset();
+ }
+ if (transparent_state_) {
+ transparent_state_->Reset();
+ }
+ erle_estimator_.Reset(true);
+ erl_estimator_.Reset();
+ filter_quality_state_.Reset();
+ };
+
+ // TODO(peah): Refine the reset scheme according to the type of gain and
+ // delay adjustment.
+
+ if (full_reset_at_echo_path_change_ &&
+ echo_path_variability.delay_change !=
+ EchoPathVariability::DelayAdjustment::kNone) {
+ full_reset();
+ } else if (echo_path_variability.gain_change) {
+ erle_estimator_.Reset(false);
+ }
+ if (subtractor_analyzer_reset_at_echo_path_change_) {
+ subtractor_output_analyzer_.HandleEchoPathChange();
+ }
+}
+
+void AecState::Update(
+ const absl::optional<DelayEstimate>& external_delay,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ adaptive_filter_frequency_responses,
+ rtc::ArrayView<const std::vector<float>> adaptive_filter_impulse_responses,
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2_refined,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const SubtractorOutput> subtractor_output) {
+ RTC_DCHECK_EQ(num_capture_channels_, Y2.size());
+ RTC_DCHECK_EQ(num_capture_channels_, subtractor_output.size());
+ RTC_DCHECK_EQ(num_capture_channels_,
+ adaptive_filter_frequency_responses.size());
+ RTC_DCHECK_EQ(num_capture_channels_,
+ adaptive_filter_impulse_responses.size());
+
+ // Analyze the filter outputs and filters.
+ bool any_filter_converged;
+ bool all_filters_diverged;
+ subtractor_output_analyzer_.Update(subtractor_output, &any_filter_converged,
+ &all_filters_diverged);
+
+ bool any_filter_consistent;
+ float max_echo_path_gain;
+ filter_analyzer_.Update(adaptive_filter_impulse_responses, render_buffer,
+ &any_filter_consistent, &max_echo_path_gain);
+
+ // Estimate the direct path delay of the filter.
+ if (config_.filter.use_linear_filter) {
+ delay_state_.Update(filter_analyzer_.FilterDelaysBlocks(), external_delay,
+ strong_not_saturated_render_blocks_);
+ }
+
+ const std::vector<std::vector<float>>& aligned_render_block =
+ render_buffer.Block(-delay_state_.MinDirectPathFilterDelay())[0];
+
+ // Update render counters.
+ bool active_render = false;
+ for (size_t ch = 0; ch < aligned_render_block.size(); ++ch) {
+ const float render_energy = std::inner_product(
+ aligned_render_block[ch].begin(), aligned_render_block[ch].end(),
+ aligned_render_block[ch].begin(), 0.f);
+ if (render_energy > (config_.render_levels.active_render_limit *
+ config_.render_levels.active_render_limit) *
+ kFftLengthBy2) {
+ active_render = true;
+ break;
+ }
+ }
+ blocks_with_active_render_ += active_render ? 1 : 0;
+ strong_not_saturated_render_blocks_ +=
+ active_render && !SaturatedCapture() ? 1 : 0;
+
+ std::array<float, kFftLengthBy2Plus1> avg_render_spectrum_with_reverb;
+
+ ComputeAvgRenderReverb(render_buffer.GetSpectrumBuffer(),
+ delay_state_.MinDirectPathFilterDelay(), ReverbDecay(),
+ &avg_render_reverb_, avg_render_spectrum_with_reverb);
+
+ if (config_.echo_audibility.use_stationarity_properties) {
+ // Update the echo audibility evaluator.
+ echo_audibility_.Update(render_buffer, avg_render_reverb_.reverb(),
+ delay_state_.MinDirectPathFilterDelay(),
+ delay_state_.ExternalDelayReported());
+ }
+
+ // Update the ERL and ERLE measures.
+ if (initial_state_.TransitionTriggered()) {
+ erle_estimator_.Reset(false);
+ }
+
+ erle_estimator_.Update(render_buffer, adaptive_filter_frequency_responses,
+ avg_render_spectrum_with_reverb, Y2, E2_refined,
+ subtractor_output_analyzer_.ConvergedFilters());
+
+ erl_estimator_.Update(
+ subtractor_output_analyzer_.ConvergedFilters(),
+ render_buffer.Spectrum(delay_state_.MinDirectPathFilterDelay()), Y2);
+
+ // Detect and flag echo saturation.
+ if (config_.ep_strength.echo_can_saturate) {
+ saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
+ UsableLinearEstimate(), subtractor_output,
+ max_echo_path_gain);
+ } else {
+ RTC_DCHECK(!saturation_detector_.SaturatedEcho());
+ }
+
+ // Update the decision on whether to use the initial state parameter set.
+ initial_state_.Update(active_render, SaturatedCapture());
+
+ // Detect whether the transparent mode should be activated.
+ if (transparent_state_) {
+ transparent_state_->Update(delay_state_.MinDirectPathFilterDelay(),
+ any_filter_consistent, any_filter_converged,
+ all_filters_diverged, active_render,
+ SaturatedCapture());
+ }
+
+ // Analyze the quality of the filter.
+ filter_quality_state_.Update(active_render, TransparentModeActive(),
+ SaturatedCapture(), external_delay,
+ any_filter_converged);
+
+ // Update the reverb estimate.
+ const bool stationary_block =
+ config_.echo_audibility.use_stationarity_properties &&
+ echo_audibility_.IsBlockStationary();
+
+ reverb_model_estimator_.Update(
+ filter_analyzer_.GetAdjustedFilters(),
+ adaptive_filter_frequency_responses,
+ erle_estimator_.GetInstLinearQualityEstimates(),
+ delay_state_.DirectPathFilterDelays(),
+ filter_quality_state_.UsableLinearFilterOutputs(), stationary_block);
+
+ erle_estimator_.Dump(data_dumper_);
+ reverb_model_estimator_.Dump(data_dumper_.get());
+ data_dumper_->DumpRaw("aec3_active_render", active_render);
+ data_dumper_->DumpRaw("aec3_erl", Erl());
+ data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
+ data_dumper_->DumpRaw("aec3_erle", Erle()[0]);
+ data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
+ data_dumper_->DumpRaw("aec3_transparent_mode", TransparentModeActive());
+ data_dumper_->DumpRaw("aec3_filter_delay",
+ filter_analyzer_.MinFilterDelayBlocks());
+
+ data_dumper_->DumpRaw("aec3_any_filter_consistent", any_filter_consistent);
+ data_dumper_->DumpRaw("aec3_initial_state",
+ initial_state_.InitialStateActive());
+ data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
+ data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho());
+ data_dumper_->DumpRaw("aec3_any_filter_converged", any_filter_converged);
+ data_dumper_->DumpRaw("aec3_all_filters_diverged", all_filters_diverged);
+
+ data_dumper_->DumpRaw("aec3_external_delay_avaliable",
+ external_delay ? 1 : 0);
+ data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
+ GetReverbFrequencyResponse());
+}
+
+AecState::InitialState::InitialState(const EchoCanceller3Config& config)
+ : conservative_initial_phase_(config.filter.conservative_initial_phase),
+ initial_state_seconds_(config.filter.initial_state_seconds) {
+ Reset();
+}
+void AecState::InitialState::InitialState::Reset() {
+ initial_state_ = true;
+ strong_not_saturated_render_blocks_ = 0;
+}
+void AecState::InitialState::InitialState::Update(bool active_render,
+ bool saturated_capture) {
+ strong_not_saturated_render_blocks_ +=
+ active_render && !saturated_capture ? 1 : 0;
+
+ // Flag whether the initial state is still active.
+ bool prev_initial_state = initial_state_;
+ if (conservative_initial_phase_) {
+ initial_state_ =
+ strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond;
+ } else {
+ initial_state_ = strong_not_saturated_render_blocks_ <
+ initial_state_seconds_ * kNumBlocksPerSecond;
+ }
+
+ // Flag whether the transition from the initial state has started.
+ transition_triggered_ = !initial_state_ && prev_initial_state;
+}
+
+AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : delay_headroom_blocks_(config.delay.delay_headroom_samples / kBlockSize),
+ filter_delays_blocks_(num_capture_channels, delay_headroom_blocks_),
+ min_filter_delay_(delay_headroom_blocks_) {}
+
+void AecState::FilterDelay::Update(
+ rtc::ArrayView<const int> analyzer_filter_delay_estimates_blocks,
+ const absl::optional<DelayEstimate>& external_delay,
+ size_t blocks_with_proper_filter_adaptation) {
+ // Update the delay based on the external delay.
+ if (external_delay &&
+ (!external_delay_ || external_delay_->delay != external_delay->delay)) {
+ external_delay_ = external_delay;
+ external_delay_reported_ = true;
+ }
+
+ // Override the estimated delay if it is not certain that the filter has had
+ // time to converge.
+ const bool delay_estimator_may_not_have_converged =
+ blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond;
+ if (delay_estimator_may_not_have_converged && external_delay_) {
+ const int delay_guess = delay_headroom_blocks_;
+ std::fill(filter_delays_blocks_.begin(), filter_delays_blocks_.end(),
+ delay_guess);
+ } else {
+ RTC_DCHECK_EQ(filter_delays_blocks_.size(),
+ analyzer_filter_delay_estimates_blocks.size());
+ std::copy(analyzer_filter_delay_estimates_blocks.begin(),
+ analyzer_filter_delay_estimates_blocks.end(),
+ filter_delays_blocks_.begin());
+ }
+
+ min_filter_delay_ = *std::min_element(filter_delays_blocks_.begin(),
+ filter_delays_blocks_.end());
+}
+
+AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer(
+ const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : use_linear_filter_(config.filter.use_linear_filter),
+ usable_linear_filter_estimates_(num_capture_channels, false) {}
+
+void AecState::FilteringQualityAnalyzer::Reset() {
+ std::fill(usable_linear_filter_estimates_.begin(),
+ usable_linear_filter_estimates_.end(), false);
+ overall_usable_linear_estimates_ = false;
+ filter_update_blocks_since_reset_ = 0;
+}
+
+void AecState::FilteringQualityAnalyzer::Update(
+ bool active_render,
+ bool transparent_mode,
+ bool saturated_capture,
+ const absl::optional<DelayEstimate>& external_delay,
+ bool any_filter_converged) {
+ // Update blocks counter.
+ const bool filter_update = active_render && !saturated_capture;
+ filter_update_blocks_since_reset_ += filter_update ? 1 : 0;
+ filter_update_blocks_since_start_ += filter_update ? 1 : 0;
+
+ // Store convergence flag when observed.
+ convergence_seen_ = convergence_seen_ || any_filter_converged;
+
+ // Verify requirements for achieving a decent filter. The requirements for
+ // filter adaptation at call startup are more restrictive than after an
+ // in-call reset.
+ const bool sufficient_data_to_converge_at_startup =
+ filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f;
+ const bool sufficient_data_to_converge_at_reset =
+ sufficient_data_to_converge_at_startup &&
+ filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f;
+
+ // The linear filter can only be used if it has had time to converge.
+ overall_usable_linear_estimates_ = sufficient_data_to_converge_at_startup &&
+ sufficient_data_to_converge_at_reset;
+
+ // The linear filter can only be used if an external delay or convergence have
+ // been identified
+ overall_usable_linear_estimates_ =
+ overall_usable_linear_estimates_ && (external_delay || convergence_seen_);
+
+ // If transparent mode is on, deactivate usign the linear filter.
+ overall_usable_linear_estimates_ =
+ overall_usable_linear_estimates_ && !transparent_mode;
+
+ if (use_linear_filter_) {
+ std::fill(usable_linear_filter_estimates_.begin(),
+ usable_linear_filter_estimates_.end(),
+ overall_usable_linear_estimates_);
+ }
+}
+
+void AecState::SaturationDetector::Update(
+ rtc::ArrayView<const std::vector<float>> x,
+ bool saturated_capture,
+ bool usable_linear_estimate,
+ rtc::ArrayView<const SubtractorOutput> subtractor_output,
+ float echo_path_gain) {
+ saturated_echo_ = false;
+ if (!saturated_capture) {
+ return;
+ }
+
+ if (usable_linear_estimate) {
+ constexpr float kSaturationThreshold = 20000.f;
+ for (size_t ch = 0; ch < subtractor_output.size(); ++ch) {
+ saturated_echo_ =
+ saturated_echo_ ||
+ (subtractor_output[ch].s_refined_max_abs > kSaturationThreshold ||
+ subtractor_output[ch].s_coarse_max_abs > kSaturationThreshold);
+ }
+ } else {
+ float max_sample = 0.f;
+ for (auto& channel : x) {
+ for (float sample : channel) {
+ max_sample = std::max(max_sample, fabsf(sample));
+ }
+ }
+
+ const float kMargin = 10.f;
+ float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
+ saturated_echo_ = saturated_echo_ || peak_echo_amplitude > 32000;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/aec_state.h b/webrtc/modules/audio_processing/aec3/aec_state.h
new file mode 100644
index 0000000..5b40e95
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/aec_state.h
@@ -0,0 +1,294 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/delay_estimate.h"
+#include "modules/audio_processing/aec3/echo_audibility.h"
+#include "modules/audio_processing/aec3/echo_path_variability.h"
+#include "modules/audio_processing/aec3/erl_estimator.h"
+#include "modules/audio_processing/aec3/erle_estimator.h"
+#include "modules/audio_processing/aec3/filter_analyzer.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/reverb_model_estimator.h"
+#include "modules/audio_processing/aec3/subtractor_output.h"
+#include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
+#include "modules/audio_processing/aec3/transparent_mode.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+
+// Handles the state and the conditions for the echo removal functionality.
+class AecState {
+ public:
+ AecState(const EchoCanceller3Config& config, size_t num_capture_channels);
+ ~AecState();
+
+ // Returns whether the echo subtractor can be used to determine the residual
+ // echo.
+ bool UsableLinearEstimate() const {
+ return filter_quality_state_.LinearFilterUsable() &&
+ config_.filter.use_linear_filter;
+ }
+
+ // Returns whether the echo subtractor output should be used as output.
+ bool UseLinearFilterOutput() const {
+ return filter_quality_state_.LinearFilterUsable() &&
+ config_.filter.use_linear_filter;
+ }
+
+ // Returns whether the render signal is currently active.
+ bool ActiveRender() const { return blocks_with_active_render_ > 200; }
+
+ // Returns the appropriate scaling of the residual echo to match the
+ // audibility.
+ void GetResidualEchoScaling(rtc::ArrayView<float> residual_scaling) const;
+
+ // Returns whether the stationary properties of the signals are used in the
+ // aec.
+ bool UseStationarityProperties() const {
+ return config_.echo_audibility.use_stationarity_properties;
+ }
+
+ // Returns the ERLE.
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
+ return erle_estimator_.Erle();
+ }
+
+ // Returns an offset to apply to the estimation of the residual echo
+ // computation. Returning nullopt means that no offset should be used, while
+ // any other value will be applied as a multiplier to the estimated residual
+ // echo.
+ absl::optional<float> ErleUncertainty() const;
+
+ // Returns the fullband ERLE estimate in log2 units.
+ float FullBandErleLog2() const { return erle_estimator_.FullbandErleLog2(); }
+
+ // Returns the ERL.
+ const std::array<float, kFftLengthBy2Plus1>& Erl() const {
+ return erl_estimator_.Erl();
+ }
+
+ // Returns the time-domain ERL.
+ float ErlTimeDomain() const { return erl_estimator_.ErlTimeDomain(); }
+
+ // Returns the delay estimate based on the linear filter.
+ int MinDirectPathFilterDelay() const {
+ return delay_state_.MinDirectPathFilterDelay();
+ }
+
+ // Returns whether the capture signal is saturated.
+ bool SaturatedCapture() const { return capture_signal_saturation_; }
+
+ // Returns whether the echo signal is saturated.
+ bool SaturatedEcho() const { return saturation_detector_.SaturatedEcho(); }
+
+ // Updates the capture signal saturation.
+ void UpdateCaptureSaturation(bool capture_signal_saturation) {
+ capture_signal_saturation_ = capture_signal_saturation;
+ }
+
+ // Returns whether the transparent mode is active
+ bool TransparentModeActive() const {
+ return transparent_state_ && transparent_state_->Active();
+ }
+
+ // Takes appropriate action at an echo path change.
+ void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
+
+ // Returns the decay factor for the echo reverberation.
+ float ReverbDecay() const { return reverb_model_estimator_.ReverbDecay(); }
+
+ // Return the frequency response of the reverberant echo.
+ rtc::ArrayView<const float> GetReverbFrequencyResponse() const {
+ return reverb_model_estimator_.GetReverbFrequencyResponse();
+ }
+
+ // Returns whether the transition for going out of the initial stated has
+ // been triggered.
+ bool TransitionTriggered() const {
+ return initial_state_.TransitionTriggered();
+ }
+
+ // Updates the aec state.
+ // TODO(bugs.webrtc.org/10913): Compute multi-channel ERL.
+ void Update(
+ const absl::optional<DelayEstimate>& external_delay,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ adaptive_filter_frequency_responses,
+ rtc::ArrayView<const std::vector<float>>
+ adaptive_filter_impulse_responses,
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2_refined,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const SubtractorOutput> subtractor_output);
+
+ // Returns filter length in blocks.
+ int FilterLengthBlocks() const {
+ // All filters have the same length, so arbitrarily return channel 0 length.
+ return filter_analyzer_.FilterLengthBlocks();
+ }
+
+ private:
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const EchoCanceller3Config config_;
+ const size_t num_capture_channels_;
+ const bool deactivate_initial_state_reset_at_echo_path_change_;
+ const bool full_reset_at_echo_path_change_;
+ const bool subtractor_analyzer_reset_at_echo_path_change_;
+
+ // Class for controlling the transition from the intial state, which in turn
+ // controls when the filter parameters for the initial state should be used.
+ class InitialState {
+ public:
+ explicit InitialState(const EchoCanceller3Config& config);
+ // Resets the state to again begin in the initial state.
+ void Reset();
+
+ // Updates the state based on new data.
+ void Update(bool active_render, bool saturated_capture);
+
+ // Returns whether the initial state is active or not.
+ bool InitialStateActive() const { return initial_state_; }
+
+ // Returns that the transition from the initial state has was started.
+ bool TransitionTriggered() const { return transition_triggered_; }
+
+ private:
+ const bool conservative_initial_phase_;
+ const float initial_state_seconds_;
+ bool transition_triggered_ = false;
+ bool initial_state_ = true;
+ size_t strong_not_saturated_render_blocks_ = 0;
+ } initial_state_;
+
+ // Class for choosing the direct-path delay relative to the beginning of the
+ // filter, as well as any other data related to the delay used within
+ // AecState.
+ class FilterDelay {
+ public:
+ FilterDelay(const EchoCanceller3Config& config,
+ size_t num_capture_channels);
+
+ // Returns whether an external delay has been reported to the AecState (from
+ // the delay estimator).
+ bool ExternalDelayReported() const { return external_delay_reported_; }
+
+ // Returns the delay in blocks relative to the beginning of the filter that
+ // corresponds to the direct path of the echo.
+ rtc::ArrayView<const int> DirectPathFilterDelays() const {
+ return filter_delays_blocks_;
+ }
+
+ // Returns the minimum delay among the direct path delays relative to the
+ // beginning of the filter
+ int MinDirectPathFilterDelay() const { return min_filter_delay_; }
+
+ // Updates the delay estimates based on new data.
+ void Update(
+ rtc::ArrayView<const int> analyzer_filter_delay_estimates_blocks,
+ const absl::optional<DelayEstimate>& external_delay,
+ size_t blocks_with_proper_filter_adaptation);
+
+ private:
+ const int delay_headroom_blocks_;
+ bool external_delay_reported_ = false;
+ std::vector<int> filter_delays_blocks_;
+ int min_filter_delay_;
+ absl::optional<DelayEstimate> external_delay_;
+ } delay_state_;
+
+ // Classifier for toggling transparent mode when there is no echo.
+ std::unique_ptr<TransparentMode> transparent_state_;
+
+ // Class for analyzing how well the linear filter is, and can be expected to,
+ // perform on the current signals. The purpose of this is for using to
+ // select the echo suppression functionality as well as the input to the echo
+ // suppressor.
+ class FilteringQualityAnalyzer {
+ public:
+ FilteringQualityAnalyzer(const EchoCanceller3Config& config,
+ size_t num_capture_channels);
+
+ // Returns whether the linear filter can be used for the echo
+ // canceller output.
+ bool LinearFilterUsable() const { return overall_usable_linear_estimates_; }
+
+ // Returns whether an individual filter output can be used for the echo
+ // canceller output.
+ const std::vector<bool>& UsableLinearFilterOutputs() const {
+ return usable_linear_filter_estimates_;
+ }
+
+ // Resets the state of the analyzer.
+ void Reset();
+
+ // Updates the analysis based on new data.
+ void Update(bool active_render,
+ bool transparent_mode,
+ bool saturated_capture,
+ const absl::optional<DelayEstimate>& external_delay,
+ bool any_filter_converged);
+
+ private:
+ const bool use_linear_filter_;
+ bool overall_usable_linear_estimates_ = false;
+ size_t filter_update_blocks_since_reset_ = 0;
+ size_t filter_update_blocks_since_start_ = 0;
+ bool convergence_seen_ = false;
+ std::vector<bool> usable_linear_filter_estimates_;
+ } filter_quality_state_;
+
+ // Class for detecting whether the echo is to be considered to be
+ // saturated.
+ class SaturationDetector {
+ public:
+ // Returns whether the echo is to be considered saturated.
+ bool SaturatedEcho() const { return saturated_echo_; }
+
+ // Updates the detection decision based on new data.
+ void Update(rtc::ArrayView<const std::vector<float>> x,
+ bool saturated_capture,
+ bool usable_linear_estimate,
+ rtc::ArrayView<const SubtractorOutput> subtractor_output,
+ float echo_path_gain);
+
+ private:
+ bool saturated_echo_ = false;
+ } saturation_detector_;
+
+ ErlEstimator erl_estimator_;
+ ErleEstimator erle_estimator_;
+ size_t strong_not_saturated_render_blocks_ = 0;
+ size_t blocks_with_active_render_ = 0;
+ bool capture_signal_saturation_ = false;
+ FilterAnalyzer filter_analyzer_;
+ EchoAudibility echo_audibility_;
+ ReverbModelEstimator reverb_model_estimator_;
+ ReverbModel avg_render_reverb_;
+ SubtractorOutputAnalyzer subtractor_output_analyzer_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
diff --git a/webrtc/modules/audio_processing/aec3/alignment_mixer.cc b/webrtc/modules/audio_processing/aec3/alignment_mixer.cc
new file mode 100644
index 0000000..87488d2
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/alignment_mixer.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/audio_processing/aec3/alignment_mixer.h"
+
+#include <algorithm>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+AlignmentMixer::MixingVariant ChooseMixingVariant(bool downmix,
+ bool adaptive_selection,
+ int num_channels) {
+ RTC_DCHECK(!(adaptive_selection && downmix));
+ RTC_DCHECK_LT(0, num_channels);
+
+ if (num_channels == 1) {
+ return AlignmentMixer::MixingVariant::kFixed;
+ }
+ if (downmix) {
+ return AlignmentMixer::MixingVariant::kDownmix;
+ }
+ if (adaptive_selection) {
+ return AlignmentMixer::MixingVariant::kAdaptive;
+ }
+ return AlignmentMixer::MixingVariant::kFixed;
+}
+
+} // namespace
+
+AlignmentMixer::AlignmentMixer(
+ size_t num_channels,
+ const EchoCanceller3Config::Delay::AlignmentMixing& config)
+ : AlignmentMixer(num_channels,
+ config.downmix,
+ config.adaptive_selection,
+ config.activity_power_threshold,
+ config.prefer_first_two_channels) {}
+
+AlignmentMixer::AlignmentMixer(size_t num_channels,
+ bool downmix,
+ bool adaptive_selection,
+ float activity_power_threshold,
+ bool prefer_first_two_channels)
+ : num_channels_(num_channels),
+ one_by_num_channels_(1.f / num_channels_),
+ excitation_energy_threshold_(kBlockSize * activity_power_threshold),
+ prefer_first_two_channels_(prefer_first_two_channels),
+ selection_variant_(
+ ChooseMixingVariant(downmix, adaptive_selection, num_channels_)) {
+ if (selection_variant_ == MixingVariant::kAdaptive) {
+ std::fill(strong_block_counters_.begin(), strong_block_counters_.end(), 0);
+ cumulative_energies_.resize(num_channels_);
+ std::fill(cumulative_energies_.begin(), cumulative_energies_.end(), 0.f);
+ }
+}
+
+void AlignmentMixer::ProduceOutput(rtc::ArrayView<const std::vector<float>> x,
+ rtc::ArrayView<float, kBlockSize> y) {
+ RTC_DCHECK_EQ(x.size(), num_channels_);
+ if (selection_variant_ == MixingVariant::kDownmix) {
+ Downmix(x, y);
+ return;
+ }
+
+ int ch = selection_variant_ == MixingVariant::kFixed ? 0 : SelectChannel(x);
+
+ RTC_DCHECK_GE(x.size(), ch);
+ std::copy(x[ch].begin(), x[ch].end(), y.begin());
+}
+
+void AlignmentMixer::Downmix(rtc::ArrayView<const std::vector<float>> x,
+ rtc::ArrayView<float, kBlockSize> y) const {
+ RTC_DCHECK_EQ(x.size(), num_channels_);
+ RTC_DCHECK_GE(num_channels_, 2);
+ std::copy(x[0].begin(), x[0].end(), y.begin());
+ for (size_t ch = 1; ch < num_channels_; ++ch) {
+ for (size_t i = 0; i < kBlockSize; ++i) {
+ y[i] += x[ch][i];
+ }
+ }
+
+ for (size_t i = 0; i < kBlockSize; ++i) {
+ y[i] *= one_by_num_channels_;
+ }
+}
+
+int AlignmentMixer::SelectChannel(rtc::ArrayView<const std::vector<float>> x) {
+ RTC_DCHECK_EQ(x.size(), num_channels_);
+ RTC_DCHECK_GE(num_channels_, 2);
+ RTC_DCHECK_EQ(cumulative_energies_.size(), num_channels_);
+
+ constexpr size_t kBlocksToChooseLeftOrRight =
+ static_cast<size_t>(0.5f * kNumBlocksPerSecond);
+ const bool good_signal_in_left_or_right =
+ prefer_first_two_channels_ &&
+ (strong_block_counters_[0] > kBlocksToChooseLeftOrRight ||
+ strong_block_counters_[1] > kBlocksToChooseLeftOrRight);
+
+ const int num_ch_to_analyze =
+ good_signal_in_left_or_right ? 2 : num_channels_;
+
+ constexpr int kNumBlocksBeforeEnergySmoothing = 60 * kNumBlocksPerSecond;
+ ++block_counter_;
+
+ for (int ch = 0; ch < num_ch_to_analyze; ++ch) {
+ RTC_DCHECK_EQ(x[ch].size(), kBlockSize);
+ float x2_sum = 0.f;
+ for (size_t i = 0; i < kBlockSize; ++i) {
+ x2_sum += x[ch][i] * x[ch][i];
+ }
+
+ if (ch < 2 && x2_sum > excitation_energy_threshold_) {
+ ++strong_block_counters_[ch];
+ }
+
+ if (block_counter_ <= kNumBlocksBeforeEnergySmoothing) {
+ cumulative_energies_[ch] += x2_sum;
+ } else {
+ constexpr float kSmoothing = 1.f / (10 * kNumBlocksPerSecond);
+ cumulative_energies_[ch] +=
+ kSmoothing * (x2_sum - cumulative_energies_[ch]);
+ }
+ }
+
+ // Normalize the energies to allow the energy computations to from now be
+ // based on smoothing.
+ if (block_counter_ == kNumBlocksBeforeEnergySmoothing) {
+ constexpr float kOneByNumBlocksBeforeEnergySmoothing =
+ 1.f / kNumBlocksBeforeEnergySmoothing;
+ for (int ch = 0; ch < num_ch_to_analyze; ++ch) {
+ cumulative_energies_[ch] *= kOneByNumBlocksBeforeEnergySmoothing;
+ }
+ }
+
+ int strongest_ch = 0;
+ for (int ch = 0; ch < num_ch_to_analyze; ++ch) {
+ if (cumulative_energies_[ch] > cumulative_energies_[strongest_ch]) {
+ strongest_ch = ch;
+ }
+ }
+
+ if ((good_signal_in_left_or_right && selected_channel_ > 1) ||
+ cumulative_energies_[strongest_ch] >
+ 2.f * cumulative_energies_[selected_channel_]) {
+ selected_channel_ = strongest_ch;
+ }
+
+ return selected_channel_;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/alignment_mixer.h b/webrtc/modules/audio_processing/aec3/alignment_mixer.h
new file mode 100644
index 0000000..682aec9
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/alignment_mixer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_ALIGNMENT_MIXER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ALIGNMENT_MIXER_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// Performs channel conversion to mono for the purpose of providing a decent
+// mono input for the delay estimation. This is achieved by analyzing all
+// incoming channels and produce one single channel output.
+class AlignmentMixer {
+ public:
+ AlignmentMixer(size_t num_channels,
+ const EchoCanceller3Config::Delay::AlignmentMixing& config);
+
+ AlignmentMixer(size_t num_channels,
+ bool downmix,
+ bool adaptive_selection,
+ float excitation_limit,
+ bool prefer_first_two_channels);
+
+ void ProduceOutput(rtc::ArrayView<const std::vector<float>> x,
+ rtc::ArrayView<float, kBlockSize> y);
+
+ enum class MixingVariant { kDownmix, kAdaptive, kFixed };
+
+ private:
+ const size_t num_channels_;
+ const float one_by_num_channels_;
+ const float excitation_energy_threshold_;
+ const bool prefer_first_two_channels_;
+ const MixingVariant selection_variant_;
+ std::array<size_t, 2> strong_block_counters_;
+ std::vector<float> cumulative_energies_;
+ int selected_channel_ = 0;
+ size_t block_counter_ = 0;
+
+ void Downmix(const rtc::ArrayView<const std::vector<float>> x,
+ rtc::ArrayView<float, kBlockSize> y) const;
+ int SelectChannel(rtc::ArrayView<const std::vector<float>> x);
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ALIGNMENT_MIXER_H_
diff --git a/webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.cc b/webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.cc
new file mode 100644
index 0000000..45f56a5
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/api_call_jitter_metrics.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+namespace {
+
+bool TimeToReportMetrics(int frames_since_last_report) {
+ constexpr int kNumFramesPerSecond = 100;
+ constexpr int kReportingIntervalFrames = 10 * kNumFramesPerSecond;
+ return frames_since_last_report == kReportingIntervalFrames;
+}
+
+} // namespace
+
+ApiCallJitterMetrics::Jitter::Jitter()
+ : max_(0), min_(std::numeric_limits<int>::max()) {}
+
+void ApiCallJitterMetrics::Jitter::Update(int num_api_calls_in_a_row) {
+ min_ = std::min(min_, num_api_calls_in_a_row);
+ max_ = std::max(max_, num_api_calls_in_a_row);
+}
+
+void ApiCallJitterMetrics::Jitter::Reset() {
+ min_ = std::numeric_limits<int>::max();
+ max_ = 0;
+}
+
+void ApiCallJitterMetrics::Reset() {
+ render_jitter_.Reset();
+ capture_jitter_.Reset();
+ num_api_calls_in_a_row_ = 0;
+ frames_since_last_report_ = 0;
+ last_call_was_render_ = false;
+ proper_call_observed_ = false;
+}
+
+void ApiCallJitterMetrics::ReportRenderCall() {
+ if (!last_call_was_render_) {
+ // If the previous call was a capture and a proper call has been observed
+ // (containing both render and capture data), storing the last number of
+ // capture calls into the metrics.
+ if (proper_call_observed_) {
+ capture_jitter_.Update(num_api_calls_in_a_row_);
+ }
+
+ // Reset the call counter to start counting render calls.
+ num_api_calls_in_a_row_ = 0;
+ }
+ ++num_api_calls_in_a_row_;
+ last_call_was_render_ = true;
+}
+
+void ApiCallJitterMetrics::ReportCaptureCall() {
+ if (last_call_was_render_) {
+ // If the previous call was a render and a proper call has been observed
+ // (containing both render and capture data), storing the last number of
+ // render calls into the metrics.
+ if (proper_call_observed_) {
+ render_jitter_.Update(num_api_calls_in_a_row_);
+ }
+ // Reset the call counter to start counting capture calls.
+ num_api_calls_in_a_row_ = 0;
+
+ // If this statement is reached, at least one render and one capture call
+ // have been observed.
+ proper_call_observed_ = true;
+ }
+ ++num_api_calls_in_a_row_;
+ last_call_was_render_ = false;
+
+ // Only report and update jitter metrics for when a proper call, containing
+ // both render and capture data, has been observed.
+ if (proper_call_observed_ &&
+ TimeToReportMetrics(++frames_since_last_report_)) {
+ // Report jitter, where the base basic unit is frames.
+ constexpr int kMaxJitterToReport = 50;
+
+ // Report max and min jitter for render and capture, in units of 20 ms.
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.MaxRenderJitter",
+ std::min(kMaxJitterToReport, render_jitter().max()), 1,
+ kMaxJitterToReport, kMaxJitterToReport);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.MinRenderJitter",
+ std::min(kMaxJitterToReport, render_jitter().min()), 1,
+ kMaxJitterToReport, kMaxJitterToReport);
+
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.MaxCaptureJitter",
+ std::min(kMaxJitterToReport, capture_jitter().max()), 1,
+ kMaxJitterToReport, kMaxJitterToReport);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.MinCaptureJitter",
+ std::min(kMaxJitterToReport, capture_jitter().min()), 1,
+ kMaxJitterToReport, kMaxJitterToReport);
+
+ frames_since_last_report_ = 0;
+ Reset();
+ }
+}
+
+bool ApiCallJitterMetrics::WillReportMetricsAtNextCapture() const {
+ return TimeToReportMetrics(frames_since_last_report_ + 1);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.h b/webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.h
new file mode 100644
index 0000000..dd1fa82
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/api_call_jitter_metrics.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_API_CALL_JITTER_METRICS_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_API_CALL_JITTER_METRICS_H_
+
+namespace webrtc {
+
+// Stores data for reporting metrics on the API call jitter.
+class ApiCallJitterMetrics {
+ public:
+ class Jitter {
+ public:
+ Jitter();
+ void Update(int num_api_calls_in_a_row);
+ void Reset();
+
+ int min() const { return min_; }
+ int max() const { return max_; }
+
+ private:
+ int max_;
+ int min_;
+ };
+
+ ApiCallJitterMetrics() { Reset(); }
+
+ // Update metrics for render API call.
+ void ReportRenderCall();
+
+ // Update and periodically report metrics for capture API call.
+ void ReportCaptureCall();
+
+ // Methods used only for testing.
+ const Jitter& render_jitter() const { return render_jitter_; }
+ const Jitter& capture_jitter() const { return capture_jitter_; }
+ bool WillReportMetricsAtNextCapture() const;
+
+ private:
+ void Reset();
+
+ Jitter render_jitter_;
+ Jitter capture_jitter_;
+
+ int num_api_calls_in_a_row_ = 0;
+ int frames_since_last_report_ = 0;
+ bool last_call_was_render_ = false;
+ bool proper_call_observed_ = false;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_API_CALL_JITTER_METRICS_H_
diff --git a/webrtc/modules/audio_processing/aec3/block_buffer.cc b/webrtc/modules/audio_processing/aec3/block_buffer.cc
new file mode 100644
index 0000000..77ce3de
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_buffer.cc
@@ -0,0 +1,39 @@
+/*
+ * 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/audio_processing/aec3/block_buffer.h"
+
+#include <algorithm>
+
+namespace webrtc {
+
+BlockBuffer::BlockBuffer(size_t size,
+ size_t num_bands,
+ size_t num_channels,
+ size_t frame_length)
+ : size(static_cast<int>(size)),
+ buffer(size,
+ std::vector<std::vector<std::vector<float>>>(
+ num_bands,
+ std::vector<std::vector<float>>(
+ num_channels,
+ std::vector<float>(frame_length, 0.f)))) {
+ for (auto& block : buffer) {
+ for (auto& band : block) {
+ for (auto& channel : band) {
+ std::fill(channel.begin(), channel.end(), 0.f);
+ }
+ }
+ }
+}
+
+BlockBuffer::~BlockBuffer() = default;
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/block_buffer.h b/webrtc/modules/audio_processing/aec3/block_buffer.h
new file mode 100644
index 0000000..b28d659
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_buffer.h
@@ -0,0 +1,62 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_BLOCK_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_BUFFER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// Struct for bundling a circular buffer of two dimensional vector objects
+// together with the read and write indices.
+struct BlockBuffer {
+ BlockBuffer(size_t size,
+ size_t num_bands,
+ size_t num_channels,
+ size_t frame_length);
+ ~BlockBuffer();
+
+ int IncIndex(int index) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return index < size - 1 ? index + 1 : 0;
+ }
+
+ int DecIndex(int index) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return index > 0 ? index - 1 : size - 1;
+ }
+
+ int OffsetIndex(int index, int offset) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ RTC_DCHECK_GE(size, offset);
+ return (size + index + offset) % size;
+ }
+
+ void UpdateWriteIndex(int offset) { write = OffsetIndex(write, offset); }
+ void IncWriteIndex() { write = IncIndex(write); }
+ void DecWriteIndex() { write = DecIndex(write); }
+ void UpdateReadIndex(int offset) { read = OffsetIndex(read, offset); }
+ void IncReadIndex() { read = IncIndex(read); }
+ void DecReadIndex() { read = DecIndex(read); }
+
+ const int size;
+ std::vector<std::vector<std::vector<std::vector<float>>>> buffer;
+ int write = 0;
+ int read = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/aec3/block_delay_buffer.cc b/webrtc/modules/audio_processing/aec3/block_delay_buffer.cc
new file mode 100644
index 0000000..b9eb3c9
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_delay_buffer.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/audio_processing/aec3/block_delay_buffer.h"
+
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+BlockDelayBuffer::BlockDelayBuffer(size_t num_channels,
+ size_t num_bands,
+ size_t frame_length,
+ size_t delay_samples)
+ : frame_length_(frame_length),
+ delay_(delay_samples),
+ buf_(num_channels,
+ std::vector<std::vector<float>>(num_bands,
+ std::vector<float>(delay_, 0.f))) {}
+
+BlockDelayBuffer::~BlockDelayBuffer() = default;
+
+void BlockDelayBuffer::DelaySignal(AudioBuffer* frame) {
+ RTC_DCHECK_EQ(buf_.size(), frame->num_channels());
+ if (delay_ == 0) {
+ return;
+ }
+
+ const size_t num_bands = buf_[0].size();
+ const size_t num_channels = buf_.size();
+
+ const size_t i_start = last_insert_;
+ size_t i = 0;
+ for (size_t ch = 0; ch < num_channels; ++ch) {
+ RTC_DCHECK_EQ(buf_[ch].size(), frame->num_bands());
+ RTC_DCHECK_EQ(buf_[ch].size(), num_bands);
+ rtc::ArrayView<float* const> frame_ch(frame->split_bands(ch), num_bands);
+
+ for (size_t band = 0; band < num_bands; ++band) {
+ RTC_DCHECK_EQ(delay_, buf_[ch][band].size());
+ i = i_start;
+
+ for (size_t k = 0; k < frame_length_; ++k) {
+ const float tmp = buf_[ch][band][i];
+ buf_[ch][band][i] = frame_ch[band][k];
+ frame_ch[band][k] = tmp;
+
+ i = i < delay_ - 1 ? i + 1 : 0;
+ }
+ }
+ }
+
+ last_insert_ = i;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/block_delay_buffer.h b/webrtc/modules/audio_processing/aec3/block_delay_buffer.h
new file mode 100644
index 0000000..711a790
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_delay_buffer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_DELAY_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_DELAY_BUFFER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "modules/audio_processing/audio_buffer.h"
+
+namespace webrtc {
+
+// Class for applying a fixed delay to the samples in a signal partitioned using
+// the audiobuffer band-splitting scheme.
+class BlockDelayBuffer {
+ public:
+ BlockDelayBuffer(size_t num_channels,
+ size_t num_bands,
+ size_t frame_length,
+ size_t delay_samples);
+ ~BlockDelayBuffer();
+
+ // Delays the samples by the specified delay.
+ void DelaySignal(AudioBuffer* frame);
+
+ private:
+ const size_t frame_length_;
+ const size_t delay_;
+ std::vector<std::vector<std::vector<float>>> buf_;
+ size_t last_insert_ = 0;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_DELAY_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/aec3/block_framer.cc b/webrtc/modules/audio_processing/aec3/block_framer.cc
new file mode 100644
index 0000000..8241ce6
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_framer.cc
@@ -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.
+ */
+
+#include "modules/audio_processing/aec3/block_framer.h"
+
+#include <algorithm>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+BlockFramer::BlockFramer(size_t num_bands, size_t num_channels)
+ : num_bands_(num_bands),
+ num_channels_(num_channels),
+ buffer_(num_bands_,
+ std::vector<std::vector<float>>(
+ num_channels,
+ std::vector<float>(kBlockSize, 0.f))) {
+ RTC_DCHECK_LT(0, num_bands);
+ RTC_DCHECK_LT(0, num_channels);
+}
+
+BlockFramer::~BlockFramer() = default;
+
+// All the constants are chosen so that the buffer is either empty or has enough
+// samples for InsertBlockAndExtractSubFrame to produce a frame. In order to
+// achieve this, the InsertBlockAndExtractSubFrame and InsertBlock methods need
+// to be called in the correct order.
+void BlockFramer::InsertBlock(
+ const std::vector<std::vector<std::vector<float>>>& block) {
+ RTC_DCHECK_EQ(num_bands_, block.size());
+ for (size_t band = 0; band < num_bands_; ++band) {
+ RTC_DCHECK_EQ(num_channels_, block[band].size());
+ for (size_t channel = 0; channel < num_channels_; ++channel) {
+ RTC_DCHECK_EQ(kBlockSize, block[band][channel].size());
+ RTC_DCHECK_EQ(0, buffer_[band][channel].size());
+
+ buffer_[band][channel].insert(buffer_[band][channel].begin(),
+ block[band][channel].begin(),
+ block[band][channel].end());
+ }
+ }
+}
+
+void BlockFramer::InsertBlockAndExtractSubFrame(
+ const std::vector<std::vector<std::vector<float>>>& block,
+ std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame) {
+ RTC_DCHECK(sub_frame);
+ RTC_DCHECK_EQ(num_bands_, block.size());
+ RTC_DCHECK_EQ(num_bands_, sub_frame->size());
+ for (size_t band = 0; band < num_bands_; ++band) {
+ RTC_DCHECK_EQ(num_channels_, block[band].size());
+ RTC_DCHECK_EQ(num_channels_, (*sub_frame)[0].size());
+ for (size_t channel = 0; channel < num_channels_; ++channel) {
+ RTC_DCHECK_LE(kSubFrameLength,
+ buffer_[band][channel].size() + kBlockSize);
+ RTC_DCHECK_EQ(kBlockSize, block[band][channel].size());
+ RTC_DCHECK_GE(kBlockSize, buffer_[band][channel].size());
+ RTC_DCHECK_EQ(kSubFrameLength, (*sub_frame)[band][channel].size());
+
+ const int samples_to_frame =
+ kSubFrameLength - buffer_[band][channel].size();
+ std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(),
+ (*sub_frame)[band][channel].begin());
+ std::copy(
+ block[band][channel].begin(),
+ block[band][channel].begin() + samples_to_frame,
+ (*sub_frame)[band][channel].begin() + buffer_[band][channel].size());
+ buffer_[band][channel].clear();
+ buffer_[band][channel].insert(
+ buffer_[band][channel].begin(),
+ block[band][channel].begin() + samples_to_frame,
+ block[band][channel].end());
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/block_framer.h b/webrtc/modules/audio_processing/aec3/block_framer.h
new file mode 100644
index 0000000..1d37866
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_framer.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_AUDIO_PROCESSING_AEC3_BLOCK_FRAMER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_FRAMER_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// Class for producing frames consisting of 2 subframes of 80 samples each
+// from 64 sample blocks. The class is designed to work together with the
+// FrameBlocker class which performs the reverse conversion. Used together with
+// that, this class produces output frames are the same rate as frames are
+// received by the FrameBlocker class. Note that the internal buffers will
+// overrun if any other rate of packets insertion is used.
+class BlockFramer {
+ public:
+ BlockFramer(size_t num_bands, size_t num_channels);
+ ~BlockFramer();
+ BlockFramer(const BlockFramer&) = delete;
+ BlockFramer& operator=(const BlockFramer&) = delete;
+
+ // Adds a 64 sample block into the data that will form the next output frame.
+ void InsertBlock(const std::vector<std::vector<std::vector<float>>>& block);
+ // Adds a 64 sample block and extracts an 80 sample subframe.
+ void InsertBlockAndExtractSubFrame(
+ const std::vector<std::vector<std::vector<float>>>& block,
+ std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame);
+
+ private:
+ const size_t num_bands_;
+ const size_t num_channels_;
+ std::vector<std::vector<std::vector<float>>> buffer_;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_FRAMER_H_
diff --git a/webrtc/modules/audio_processing/aec3/block_processor.cc b/webrtc/modules/audio_processing/aec3/block_processor.cc
new file mode 100644
index 0000000..f2f3261
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_processor.cc
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/audio_processing/aec3/block_processor.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "api/audio/echo_control.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/block_processor_metrics.h"
+#include "modules/audio_processing/aec3/delay_estimate.h"
+#include "modules/audio_processing/aec3/echo_path_variability.h"
+#include "modules/audio_processing/aec3/echo_remover.h"
+#include "modules/audio_processing/aec3/render_delay_buffer.h"
+#include "modules/audio_processing/aec3/render_delay_controller.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace {
+
+enum class BlockProcessorApiCall { kCapture, kRender };
+
+class BlockProcessorImpl final : public BlockProcessor {
+ public:
+ BlockProcessorImpl(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ std::unique_ptr<RenderDelayBuffer> render_buffer,
+ std::unique_ptr<RenderDelayController> delay_controller,
+ std::unique_ptr<EchoRemover> echo_remover);
+
+ BlockProcessorImpl() = delete;
+
+ ~BlockProcessorImpl() override;
+
+ void ProcessCapture(
+ bool echo_path_gain_change,
+ bool capture_signal_saturation,
+ std::vector<std::vector<std::vector<float>>>* linear_output,
+ std::vector<std::vector<std::vector<float>>>* capture_block) override;
+
+ void BufferRender(
+ const std::vector<std::vector<std::vector<float>>>& block) override;
+
+ void UpdateEchoLeakageStatus(bool leakage_detected) override;
+
+ void GetMetrics(EchoControl::Metrics* metrics) const override;
+
+ void SetAudioBufferDelay(int delay_ms) override;
+
+ private:
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const EchoCanceller3Config config_;
+ bool capture_properly_started_ = false;
+ bool render_properly_started_ = false;
+ const size_t sample_rate_hz_;
+ std::unique_ptr<RenderDelayBuffer> render_buffer_;
+ std::unique_ptr<RenderDelayController> delay_controller_;
+ std::unique_ptr<EchoRemover> echo_remover_;
+ BlockProcessorMetrics metrics_;
+ RenderDelayBuffer::BufferingEvent render_event_;
+ size_t capture_call_counter_ = 0;
+ absl::optional<DelayEstimate> estimated_delay_;
+};
+
+int BlockProcessorImpl::instance_count_ = 0;
+
+BlockProcessorImpl::BlockProcessorImpl(
+ const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ std::unique_ptr<RenderDelayBuffer> render_buffer,
+ std::unique_ptr<RenderDelayController> delay_controller,
+ std::unique_ptr<EchoRemover> echo_remover)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ config_(config),
+ sample_rate_hz_(sample_rate_hz),
+ render_buffer_(std::move(render_buffer)),
+ delay_controller_(std::move(delay_controller)),
+ echo_remover_(std::move(echo_remover)),
+ render_event_(RenderDelayBuffer::BufferingEvent::kNone) {
+ RTC_DCHECK(ValidFullBandRate(sample_rate_hz_));
+}
+
+BlockProcessorImpl::~BlockProcessorImpl() = default;
+
+void BlockProcessorImpl::ProcessCapture(
+ bool echo_path_gain_change,
+ bool capture_signal_saturation,
+ std::vector<std::vector<std::vector<float>>>* linear_output,
+ std::vector<std::vector<std::vector<float>>>* capture_block) {
+ RTC_DCHECK(capture_block);
+ RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), capture_block->size());
+ RTC_DCHECK_EQ(kBlockSize, (*capture_block)[0][0].size());
+
+ capture_call_counter_++;
+
+ data_dumper_->DumpRaw("aec3_processblock_call_order",
+ static_cast<int>(BlockProcessorApiCall::kCapture));
+ data_dumper_->DumpWav("aec3_processblock_capture_input", kBlockSize,
+ &(*capture_block)[0][0][0], 16000, 1);
+
+ if (render_properly_started_) {
+ if (!capture_properly_started_) {
+ capture_properly_started_ = true;
+ render_buffer_->Reset();
+ if (delay_controller_)
+ delay_controller_->Reset(true);
+ }
+ } else {
+ // If no render data has yet arrived, do not process the capture signal.
+ render_buffer_->HandleSkippedCaptureProcessing();
+ return;
+ }
+
+ EchoPathVariability echo_path_variability(
+ echo_path_gain_change, EchoPathVariability::DelayAdjustment::kNone,
+ false);
+
+ if (render_event_ == RenderDelayBuffer::BufferingEvent::kRenderOverrun &&
+ render_properly_started_) {
+ echo_path_variability.delay_change =
+ EchoPathVariability::DelayAdjustment::kBufferFlush;
+ if (delay_controller_)
+ delay_controller_->Reset(true);
+ RTC_LOG(LS_WARNING) << "Reset due to render buffer overrun at block "
+ << capture_call_counter_;
+ }
+ render_event_ = RenderDelayBuffer::BufferingEvent::kNone;
+
+ // Update the render buffers with any newly arrived render blocks and prepare
+ // the render buffers for reading the render data corresponding to the current
+ // capture block.
+ RenderDelayBuffer::BufferingEvent buffer_event =
+ render_buffer_->PrepareCaptureProcessing();
+ // Reset the delay controller at render buffer underrun.
+ if (buffer_event == RenderDelayBuffer::BufferingEvent::kRenderUnderrun) {
+ if (delay_controller_)
+ delay_controller_->Reset(false);
+ }
+
+ data_dumper_->DumpWav("aec3_processblock_capture_input2", kBlockSize,
+ &(*capture_block)[0][0][0], 16000, 1);
+
+ bool has_delay_estimator = !config_.delay.use_external_delay_estimator;
+ if (has_delay_estimator) {
+ RTC_DCHECK(delay_controller_);
+ // Compute and apply the render delay required to achieve proper signal
+ // alignment.
+ estimated_delay_ = delay_controller_->GetDelay(
+ render_buffer_->GetDownsampledRenderBuffer(), render_buffer_->Delay(),
+ (*capture_block)[0]);
+
+ if (estimated_delay_) {
+ bool delay_change =
+ render_buffer_->AlignFromDelay(estimated_delay_->delay);
+ if (delay_change) {
+ rtc::LoggingSeverity log_level =
+ config_.delay.log_warning_on_delay_changes ? rtc::LS_WARNING
+ : rtc::LS_INFO;
+ RTC_LOG_V(log_level) << "Delay changed to " << estimated_delay_->delay
+ << " at block " << capture_call_counter_;
+ echo_path_variability.delay_change =
+ EchoPathVariability::DelayAdjustment::kNewDetectedDelay;
+ }
+ }
+
+ echo_path_variability.clock_drift = delay_controller_->HasClockdrift();
+
+ } else {
+ render_buffer_->AlignFromExternalDelay();
+ }
+
+ // Remove the echo from the capture signal.
+ if (has_delay_estimator || render_buffer_->HasReceivedBufferDelay()) {
+ echo_remover_->ProcessCapture(
+ echo_path_variability, capture_signal_saturation, estimated_delay_,
+ render_buffer_->GetRenderBuffer(), linear_output, capture_block);
+ }
+
+ // Update the metrics.
+ metrics_.UpdateCapture(false);
+}
+
+void BlockProcessorImpl::BufferRender(
+ const std::vector<std::vector<std::vector<float>>>& block) {
+ RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), block.size());
+ RTC_DCHECK_EQ(kBlockSize, block[0][0].size());
+ data_dumper_->DumpRaw("aec3_processblock_call_order",
+ static_cast<int>(BlockProcessorApiCall::kRender));
+ data_dumper_->DumpWav("aec3_processblock_render_input", kBlockSize,
+ &block[0][0][0], 16000, 1);
+ data_dumper_->DumpWav("aec3_processblock_render_input2", kBlockSize,
+ &block[0][0][0], 16000, 1);
+
+ render_event_ = render_buffer_->Insert(block);
+
+ metrics_.UpdateRender(render_event_ !=
+ RenderDelayBuffer::BufferingEvent::kNone);
+
+ render_properly_started_ = true;
+ if (delay_controller_)
+ delay_controller_->LogRenderCall();
+}
+
+void BlockProcessorImpl::UpdateEchoLeakageStatus(bool leakage_detected) {
+ echo_remover_->UpdateEchoLeakageStatus(leakage_detected);
+}
+
+void BlockProcessorImpl::GetMetrics(EchoControl::Metrics* metrics) const {
+ echo_remover_->GetMetrics(metrics);
+ constexpr int block_size_ms = 4;
+ absl::optional<size_t> delay = render_buffer_->Delay();
+ metrics->delay_ms = delay ? static_cast<int>(*delay) * block_size_ms : 0;
+}
+
+void BlockProcessorImpl::SetAudioBufferDelay(int delay_ms) {
+ render_buffer_->SetAudioBufferDelay(delay_ms);
+}
+
+} // namespace
+
+BlockProcessor* BlockProcessor::Create(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels) {
+ std::unique_ptr<RenderDelayBuffer> render_buffer(
+ RenderDelayBuffer::Create(config, sample_rate_hz, num_render_channels));
+ std::unique_ptr<RenderDelayController> delay_controller;
+ if (!config.delay.use_external_delay_estimator) {
+ delay_controller.reset(RenderDelayController::Create(config, sample_rate_hz,
+ num_capture_channels));
+ }
+ std::unique_ptr<EchoRemover> echo_remover(EchoRemover::Create(
+ config, sample_rate_hz, num_render_channels, num_capture_channels));
+ return Create(config, sample_rate_hz, num_render_channels,
+ num_capture_channels, std::move(render_buffer),
+ std::move(delay_controller), std::move(echo_remover));
+}
+
+BlockProcessor* BlockProcessor::Create(
+ const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ std::unique_ptr<RenderDelayBuffer> render_buffer) {
+ std::unique_ptr<RenderDelayController> delay_controller;
+ if (!config.delay.use_external_delay_estimator) {
+ delay_controller.reset(RenderDelayController::Create(config, sample_rate_hz,
+ num_capture_channels));
+ }
+ std::unique_ptr<EchoRemover> echo_remover(EchoRemover::Create(
+ config, sample_rate_hz, num_render_channels, num_capture_channels));
+ return Create(config, sample_rate_hz, num_render_channels,
+ num_capture_channels, std::move(render_buffer),
+ std::move(delay_controller), std::move(echo_remover));
+}
+
+BlockProcessor* BlockProcessor::Create(
+ const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ std::unique_ptr<RenderDelayBuffer> render_buffer,
+ std::unique_ptr<RenderDelayController> delay_controller,
+ std::unique_ptr<EchoRemover> echo_remover) {
+ return new BlockProcessorImpl(config, sample_rate_hz, num_render_channels,
+ num_capture_channels, std::move(render_buffer),
+ std::move(delay_controller),
+ std::move(echo_remover));
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/block_processor.h b/webrtc/modules/audio_processing/aec3/block_processor.h
new file mode 100644
index 0000000..9bb0cf1
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_processor.h
@@ -0,0 +1,76 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+#include "api/audio/echo_canceller3_config.h"
+#include "api/audio/echo_control.h"
+#include "modules/audio_processing/aec3/echo_remover.h"
+#include "modules/audio_processing/aec3/render_delay_buffer.h"
+#include "modules/audio_processing/aec3/render_delay_controller.h"
+
+namespace webrtc {
+
+// Class for performing echo cancellation on 64 sample blocks of audio data.
+class BlockProcessor {
+ public:
+ static BlockProcessor* Create(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels);
+ // Only used for testing purposes.
+ static BlockProcessor* Create(
+ const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ std::unique_ptr<RenderDelayBuffer> render_buffer);
+ static BlockProcessor* Create(
+ const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ std::unique_ptr<RenderDelayBuffer> render_buffer,
+ std::unique_ptr<RenderDelayController> delay_controller,
+ std::unique_ptr<EchoRemover> echo_remover);
+
+ virtual ~BlockProcessor() = default;
+
+ // Get current metrics.
+ virtual void GetMetrics(EchoControl::Metrics* metrics) const = 0;
+
+ // Provides an optional external estimate of the audio buffer delay.
+ virtual void SetAudioBufferDelay(int delay_ms) = 0;
+
+ // Processes a block of capture data.
+ virtual void ProcessCapture(
+ bool echo_path_gain_change,
+ bool capture_signal_saturation,
+ std::vector<std::vector<std::vector<float>>>* linear_output,
+ std::vector<std::vector<std::vector<float>>>* capture_block) = 0;
+
+ // Buffers a block of render data supplied by a FrameBlocker object.
+ virtual void BufferRender(
+ const std::vector<std::vector<std::vector<float>>>& render_block) = 0;
+
+ // Reports whether echo leakage has been detected in the echo canceller
+ // output.
+ virtual void UpdateEchoLeakageStatus(bool leakage_detected) = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/block_processor_metrics.cc b/webrtc/modules/audio_processing/aec3/block_processor_metrics.cc
new file mode 100644
index 0000000..deac1fc
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_processor_metrics.cc
@@ -0,0 +1,104 @@
+/*
+ * 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/audio_processing/aec3/block_processor_metrics.h"
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+
+namespace {
+
+enum class RenderUnderrunCategory {
+ kNone,
+ kFew,
+ kSeveral,
+ kMany,
+ kConstant,
+ kNumCategories
+};
+
+enum class RenderOverrunCategory {
+ kNone,
+ kFew,
+ kSeveral,
+ kMany,
+ kConstant,
+ kNumCategories
+};
+
+} // namespace
+
+void BlockProcessorMetrics::UpdateCapture(bool underrun) {
+ ++capture_block_counter_;
+ if (underrun) {
+ ++render_buffer_underruns_;
+ }
+
+ if (capture_block_counter_ == kMetricsReportingIntervalBlocks) {
+ metrics_reported_ = true;
+
+ RenderUnderrunCategory underrun_category;
+ if (render_buffer_underruns_ == 0) {
+ underrun_category = RenderUnderrunCategory::kNone;
+ } else if (render_buffer_underruns_ > (capture_block_counter_ >> 1)) {
+ underrun_category = RenderUnderrunCategory::kConstant;
+ } else if (render_buffer_underruns_ > 100) {
+ underrun_category = RenderUnderrunCategory::kMany;
+ } else if (render_buffer_underruns_ > 10) {
+ underrun_category = RenderUnderrunCategory::kSeveral;
+ } else {
+ underrun_category = RenderUnderrunCategory::kFew;
+ }
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Audio.EchoCanceller.RenderUnderruns",
+ static_cast<int>(underrun_category),
+ static_cast<int>(RenderUnderrunCategory::kNumCategories));
+
+ RenderOverrunCategory overrun_category;
+ if (render_buffer_overruns_ == 0) {
+ overrun_category = RenderOverrunCategory::kNone;
+ } else if (render_buffer_overruns_ > (buffer_render_calls_ >> 1)) {
+ overrun_category = RenderOverrunCategory::kConstant;
+ } else if (render_buffer_overruns_ > 100) {
+ overrun_category = RenderOverrunCategory::kMany;
+ } else if (render_buffer_overruns_ > 10) {
+ overrun_category = RenderOverrunCategory::kSeveral;
+ } else {
+ overrun_category = RenderOverrunCategory::kFew;
+ }
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Audio.EchoCanceller.RenderOverruns",
+ static_cast<int>(overrun_category),
+ static_cast<int>(RenderOverrunCategory::kNumCategories));
+
+ ResetMetrics();
+ capture_block_counter_ = 0;
+ } else {
+ metrics_reported_ = false;
+ }
+}
+
+void BlockProcessorMetrics::UpdateRender(bool overrun) {
+ ++buffer_render_calls_;
+ if (overrun) {
+ ++render_buffer_overruns_;
+ }
+}
+
+void BlockProcessorMetrics::ResetMetrics() {
+ render_buffer_underruns_ = 0;
+ render_buffer_overruns_ = 0;
+ buffer_render_calls_ = 0;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/block_processor_metrics.h b/webrtc/modules/audio_processing/aec3/block_processor_metrics.h
new file mode 100644
index 0000000..4ba0536
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/block_processor_metrics.h
@@ -0,0 +1,47 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_METRICS_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_METRICS_H_
+
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Handles the reporting of metrics for the block_processor.
+class BlockProcessorMetrics {
+ public:
+ BlockProcessorMetrics() = default;
+
+ // Updates the metric with new capture data.
+ void UpdateCapture(bool underrun);
+
+ // Updates the metric with new render data.
+ void UpdateRender(bool overrun);
+
+ // Returns true if the metrics have just been reported, otherwise false.
+ bool MetricsReported() { return metrics_reported_; }
+
+ private:
+ // Resets the metrics.
+ void ResetMetrics();
+
+ int capture_block_counter_ = 0;
+ bool metrics_reported_ = false;
+ int render_buffer_underruns_ = 0;
+ int render_buffer_overruns_ = 0;
+ int buffer_render_calls_ = 0;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(BlockProcessorMetrics);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_PROCESSOR_METRICS_H_
diff --git a/webrtc/modules/audio_processing/aec3/clockdrift_detector.cc b/webrtc/modules/audio_processing/aec3/clockdrift_detector.cc
new file mode 100644
index 0000000..2c49b79
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/clockdrift_detector.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/audio_processing/aec3/clockdrift_detector.h"
+
+namespace webrtc {
+
+ClockdriftDetector::ClockdriftDetector()
+ : level_(Level::kNone), stability_counter_(0) {
+ delay_history_.fill(0);
+}
+
+ClockdriftDetector::~ClockdriftDetector() = default;
+
+void ClockdriftDetector::Update(int delay_estimate) {
+ if (delay_estimate == delay_history_[0]) {
+ // Reset clockdrift level if delay estimate is stable for 7500 blocks (30
+ // seconds).
+ if (++stability_counter_ > 7500)
+ level_ = Level::kNone;
+ return;
+ }
+
+ stability_counter_ = 0;
+ const int d1 = delay_history_[0] - delay_estimate;
+ const int d2 = delay_history_[1] - delay_estimate;
+ const int d3 = delay_history_[2] - delay_estimate;
+
+ // Patterns recognized as positive clockdrift:
+ // [x-3], x-2, x-1, x.
+ // [x-3], x-1, x-2, x.
+ const bool probable_drift_up =
+ (d1 == -1 && d2 == -2) || (d1 == -2 && d2 == -1);
+ const bool drift_up = probable_drift_up && d3 == -3;
+
+ // Patterns recognized as negative clockdrift:
+ // [x+3], x+2, x+1, x.
+ // [x+3], x+1, x+2, x.
+ const bool probable_drift_down = (d1 == 1 && d2 == 2) || (d1 == 2 && d2 == 1);
+ const bool drift_down = probable_drift_down && d3 == 3;
+
+ // Set clockdrift level.
+ if (drift_up || drift_down) {
+ level_ = Level::kVerified;
+ } else if ((probable_drift_up || probable_drift_down) &&
+ level_ == Level::kNone) {
+ level_ = Level::kProbable;
+ }
+
+ // Shift delay history one step.
+ delay_history_[2] = delay_history_[1];
+ delay_history_[1] = delay_history_[0];
+ delay_history_[0] = delay_estimate;
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/clockdrift_detector.h b/webrtc/modules/audio_processing/aec3/clockdrift_detector.h
new file mode 100644
index 0000000..2ba90bb
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/clockdrift_detector.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_CLOCKDRIFT_DETECTOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_CLOCKDRIFT_DETECTOR_H_
+
+#include <stddef.h>
+
+#include <array>
+
+namespace webrtc {
+
+class ApmDataDumper;
+struct DownsampledRenderBuffer;
+struct EchoCanceller3Config;
+
+// Detects clockdrift by analyzing the estimated delay.
+class ClockdriftDetector {
+ public:
+ enum class Level { kNone, kProbable, kVerified, kNumCategories };
+ ClockdriftDetector();
+ ~ClockdriftDetector();
+ void Update(int delay_estimate);
+ Level ClockdriftLevel() const { return level_; }
+
+ private:
+ std::array<int, 3> delay_history_;
+ Level level_;
+ size_t stability_counter_;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_CLOCKDRIFT_DETECTOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.cc b/webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.cc
new file mode 100644
index 0000000..f4fb74d
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.cc
@@ -0,0 +1,103 @@
+/*
+ * 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/audio_processing/aec3/coarse_filter_update_gain.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+CoarseFilterUpdateGain::CoarseFilterUpdateGain(
+ const EchoCanceller3Config::Filter::CoarseConfiguration& config,
+ size_t config_change_duration_blocks)
+ : config_change_duration_blocks_(
+ static_cast<int>(config_change_duration_blocks)) {
+ SetConfig(config, true);
+ RTC_DCHECK_LT(0, config_change_duration_blocks_);
+ one_by_config_change_duration_blocks_ = 1.f / config_change_duration_blocks_;
+}
+
+void CoarseFilterUpdateGain::HandleEchoPathChange() {
+ poor_signal_excitation_counter_ = 0;
+ call_counter_ = 0;
+}
+
+void CoarseFilterUpdateGain::Compute(
+ const std::array<float, kFftLengthBy2Plus1>& render_power,
+ const RenderSignalAnalyzer& render_signal_analyzer,
+ const FftData& E_coarse,
+ size_t size_partitions,
+ bool saturated_capture_signal,
+ FftData* G) {
+ RTC_DCHECK(G);
+ ++call_counter_;
+
+ UpdateCurrentConfig();
+
+ if (render_signal_analyzer.PoorSignalExcitation()) {
+ poor_signal_excitation_counter_ = 0;
+ }
+
+ // Do not update the filter if the render is not sufficiently excited.
+ if (++poor_signal_excitation_counter_ < size_partitions ||
+ saturated_capture_signal || call_counter_ <= size_partitions) {
+ G->re.fill(0.f);
+ G->im.fill(0.f);
+ return;
+ }
+
+ // Compute mu.
+ std::array<float, kFftLengthBy2Plus1> mu;
+ const auto& X2 = render_power;
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ if (X2[k] > current_config_.noise_gate) {
+ mu[k] = current_config_.rate / X2[k];
+ } else {
+ mu[k] = 0.f;
+ }
+ }
+
+ // Avoid updating the filter close to narrow bands in the render signals.
+ render_signal_analyzer.MaskRegionsAroundNarrowBands(&mu);
+
+ // G = mu * E * X2.
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ G->re[k] = mu[k] * E_coarse.re[k];
+ G->im[k] = mu[k] * E_coarse.im[k];
+ }
+}
+
+void CoarseFilterUpdateGain::UpdateCurrentConfig() {
+ RTC_DCHECK_GE(config_change_duration_blocks_, config_change_counter_);
+ if (config_change_counter_ > 0) {
+ if (--config_change_counter_ > 0) {
+ auto average = [](float from, float to, float from_weight) {
+ return from * from_weight + to * (1.f - from_weight);
+ };
+
+ float change_factor =
+ config_change_counter_ * one_by_config_change_duration_blocks_;
+
+ current_config_.rate =
+ average(old_target_config_.rate, target_config_.rate, change_factor);
+ current_config_.noise_gate =
+ average(old_target_config_.noise_gate, target_config_.noise_gate,
+ change_factor);
+ } else {
+ current_config_ = old_target_config_ = target_config_;
+ }
+ }
+ RTC_DCHECK_LE(0, config_change_counter_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.h b/webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.h
new file mode 100644
index 0000000..a1a1399
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/coarse_filter_update_gain.h
@@ -0,0 +1,74 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_COARSE_FILTER_UPDATE_GAIN_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_COARSE_FILTER_UPDATE_GAIN_H_
+
+#include <stddef.h>
+
+#include <array>
+
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "modules/audio_processing/aec3/render_signal_analyzer.h"
+
+namespace webrtc {
+
+// Provides functionality for computing the fixed gain for the coarse filter.
+class CoarseFilterUpdateGain {
+ public:
+ explicit CoarseFilterUpdateGain(
+ const EchoCanceller3Config::Filter::CoarseConfiguration& config,
+ size_t config_change_duration_blocks);
+
+ // Takes action in the case of a known echo path change.
+ void HandleEchoPathChange();
+
+ // Computes the gain.
+ void Compute(const std::array<float, kFftLengthBy2Plus1>& render_power,
+ const RenderSignalAnalyzer& render_signal_analyzer,
+ const FftData& E_coarse,
+ size_t size_partitions,
+ bool saturated_capture_signal,
+ FftData* G);
+
+ // Sets a new config.
+ void SetConfig(
+ const EchoCanceller3Config::Filter::CoarseConfiguration& config,
+ bool immediate_effect) {
+ if (immediate_effect) {
+ old_target_config_ = current_config_ = target_config_ = config;
+ config_change_counter_ = 0;
+ } else {
+ old_target_config_ = current_config_;
+ target_config_ = config;
+ config_change_counter_ = config_change_duration_blocks_;
+ }
+ }
+
+ private:
+ EchoCanceller3Config::Filter::CoarseConfiguration current_config_;
+ EchoCanceller3Config::Filter::CoarseConfiguration target_config_;
+ EchoCanceller3Config::Filter::CoarseConfiguration old_target_config_;
+ const int config_change_duration_blocks_;
+ float one_by_config_change_duration_blocks_;
+ // TODO(peah): Check whether this counter should instead be initialized to a
+ // large value.
+ size_t poor_signal_excitation_counter_ = 0;
+ size_t call_counter_ = 0;
+ int config_change_counter_ = 0;
+
+ void UpdateCurrentConfig();
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_COARSE_FILTER_UPDATE_GAIN_H_
diff --git a/webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc b/webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc
new file mode 100644
index 0000000..de5227c
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/comfort_noise_generator.cc
@@ -0,0 +1,186 @@
+/*
+ * 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/audio_processing/aec3/comfort_noise_generator.h"
+
+// Defines WEBRTC_ARCH_X86_FAMILY, used below.
+#include "rtc_base/system/arch.h"
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#include <emmintrin.h>
+#endif
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <cstdint>
+#include <functional>
+#include <numeric>
+
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "modules/audio_processing/aec3/vector_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Computes the noise floor value that matches a WGN input of noise_floor_dbfs.
+float GetNoiseFloorFactor(float noise_floor_dbfs) {
+ // kdBfsNormalization = 20.f*log10(32768.f).
+ constexpr float kdBfsNormalization = 90.30899869919436f;
+ return 64.f * powf(10.f, (kdBfsNormalization + noise_floor_dbfs) * 0.1f);
+}
+
+// Table of sqrt(2) * sin(2*pi*i/32).
+constexpr float kSqrt2Sin[32] = {
+ +0.0000000f, +0.2758994f, +0.5411961f, +0.7856950f, +1.0000000f,
+ +1.1758756f, +1.3065630f, +1.3870398f, +1.4142136f, +1.3870398f,
+ +1.3065630f, +1.1758756f, +1.0000000f, +0.7856950f, +0.5411961f,
+ +0.2758994f, +0.0000000f, -0.2758994f, -0.5411961f, -0.7856950f,
+ -1.0000000f, -1.1758756f, -1.3065630f, -1.3870398f, -1.4142136f,
+ -1.3870398f, -1.3065630f, -1.1758756f, -1.0000000f, -0.7856950f,
+ -0.5411961f, -0.2758994f};
+
+void GenerateComfortNoise(Aec3Optimization optimization,
+ const std::array<float, kFftLengthBy2Plus1>& N2,
+ uint32_t* seed,
+ FftData* lower_band_noise,
+ FftData* upper_band_noise) {
+ FftData* N_low = lower_band_noise;
+ FftData* N_high = upper_band_noise;
+
+ // Compute square root spectrum.
+ std::array<float, kFftLengthBy2Plus1> N;
+ std::copy(N2.begin(), N2.end(), N.begin());
+ aec3::VectorMath(optimization).Sqrt(N);
+
+ // Compute the noise level for the upper bands.
+ constexpr float kOneByNumBands = 1.f / (kFftLengthBy2Plus1 / 2 + 1);
+ constexpr int kFftLengthBy2Plus1By2 = kFftLengthBy2Plus1 / 2;
+ const float high_band_noise_level =
+ std::accumulate(N.begin() + kFftLengthBy2Plus1By2, N.end(), 0.f) *
+ kOneByNumBands;
+
+ // The analysis and synthesis windowing cause loss of power when
+ // cross-fading the noise where frames are completely uncorrelated
+ // (generated with random phase), hence the factor sqrt(2).
+ // This is not the case for the speech signal where the input is overlapping
+ // (strong correlation).
+ N_low->re[0] = N_low->re[kFftLengthBy2] = N_high->re[0] =
+ N_high->re[kFftLengthBy2] = 0.f;
+ for (size_t k = 1; k < kFftLengthBy2; k++) {
+ constexpr int kIndexMask = 32 - 1;
+ // Generate a random 31-bit integer.
+ seed[0] = (seed[0] * 69069 + 1) & (0x80000000 - 1);
+ // Convert to a 5-bit index.
+ int i = seed[0] >> 26;
+
+ // y = sqrt(2) * sin(a)
+ const float x = kSqrt2Sin[i];
+ // x = sqrt(2) * cos(a) = sqrt(2) * sin(a + pi/2)
+ const float y = kSqrt2Sin[(i + 8) & kIndexMask];
+
+ // Form low-frequency noise via spectral shaping.
+ N_low->re[k] = N[k] * x;
+ N_low->im[k] = N[k] * y;
+
+ // Form the high-frequency noise via simple levelling.
+ N_high->re[k] = high_band_noise_level * x;
+ N_high->im[k] = high_band_noise_level * y;
+ }
+}
+
+} // namespace
+
+ComfortNoiseGenerator::ComfortNoiseGenerator(const EchoCanceller3Config& config,
+ Aec3Optimization optimization,
+ size_t num_capture_channels)
+ : optimization_(optimization),
+ seed_(42),
+ num_capture_channels_(num_capture_channels),
+ noise_floor_(GetNoiseFloorFactor(config.comfort_noise.noise_floor_dbfs)),
+ N2_initial_(
+ std::make_unique<std::vector<std::array<float, kFftLengthBy2Plus1>>>(
+ num_capture_channels_)),
+ Y2_smoothed_(num_capture_channels_),
+ N2_(num_capture_channels_) {
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ (*N2_initial_)[ch].fill(0.f);
+ Y2_smoothed_[ch].fill(0.f);
+ N2_[ch].fill(1.0e6f);
+ }
+}
+
+ComfortNoiseGenerator::~ComfortNoiseGenerator() = default;
+
+void ComfortNoiseGenerator::Compute(
+ bool saturated_capture,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ capture_spectrum,
+ rtc::ArrayView<FftData> lower_band_noise,
+ rtc::ArrayView<FftData> upper_band_noise) {
+ const auto& Y2 = capture_spectrum;
+
+ if (!saturated_capture) {
+ // Smooth Y2.
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ std::transform(Y2_smoothed_[ch].begin(), Y2_smoothed_[ch].end(),
+ Y2[ch].begin(), Y2_smoothed_[ch].begin(),
+ [](float a, float b) { return a + 0.1f * (b - a); });
+ }
+
+ if (N2_counter_ > 50) {
+ // Update N2 from Y2_smoothed.
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ std::transform(N2_[ch].begin(), N2_[ch].end(), Y2_smoothed_[ch].begin(),
+ N2_[ch].begin(), [](float a, float b) {
+ return b < a ? (0.9f * b + 0.1f * a) * 1.0002f
+ : a * 1.0002f;
+ });
+ }
+ }
+
+ if (N2_initial_) {
+ if (++N2_counter_ == 1000) {
+ N2_initial_.reset();
+ } else {
+ // Compute the N2_initial from N2.
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ std::transform(N2_[ch].begin(), N2_[ch].end(),
+ (*N2_initial_)[ch].begin(), (*N2_initial_)[ch].begin(),
+ [](float a, float b) {
+ return a > b ? b + 0.001f * (a - b) : a;
+ });
+ }
+ }
+ }
+
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ for (auto& n : N2_[ch]) {
+ n = std::max(n, noise_floor_);
+ }
+ if (N2_initial_) {
+ for (auto& n : (*N2_initial_)[ch]) {
+ n = std::max(n, noise_floor_);
+ }
+ }
+ }
+ }
+
+ // Choose N2 estimate to use.
+ const auto& N2 = N2_initial_ ? (*N2_initial_) : N2_;
+
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ GenerateComfortNoise(optimization_, N2[ch], &seed_, &lower_band_noise[ch],
+ &upper_band_noise[ch]);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/comfort_noise_generator.h b/webrtc/modules/audio_processing/aec3/comfort_noise_generator.h
new file mode 100644
index 0000000..16eaf35
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/comfort_noise_generator.h
@@ -0,0 +1,78 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_COMFORT_NOISE_GENERATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_COMFORT_NOISE_GENERATOR_H_
+
+#include <stdint.h>
+
+#include <array>
+#include <memory>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec_state.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+namespace aec3 {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+
+void EstimateComfortNoise_SSE2(const std::array<float, kFftLengthBy2Plus1>& N2,
+ uint32_t* seed,
+ FftData* lower_band_noise,
+ FftData* upper_band_noise);
+#endif
+void EstimateComfortNoise(const std::array<float, kFftLengthBy2Plus1>& N2,
+ uint32_t* seed,
+ FftData* lower_band_noise,
+ FftData* upper_band_noise);
+
+} // namespace aec3
+
+// Generates the comfort noise.
+class ComfortNoiseGenerator {
+ public:
+ ComfortNoiseGenerator(const EchoCanceller3Config& config,
+ Aec3Optimization optimization,
+ size_t num_capture_channels);
+ ComfortNoiseGenerator() = delete;
+ ~ComfortNoiseGenerator();
+ ComfortNoiseGenerator(const ComfortNoiseGenerator&) = delete;
+
+ // Computes the comfort noise.
+ void Compute(bool saturated_capture,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ capture_spectrum,
+ rtc::ArrayView<FftData> lower_band_noise,
+ rtc::ArrayView<FftData> upper_band_noise);
+
+ // Returns the estimate of the background noise spectrum.
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> NoiseSpectrum()
+ const {
+ return N2_;
+ }
+
+ private:
+ const Aec3Optimization optimization_;
+ uint32_t seed_;
+ const size_t num_capture_channels_;
+ const float noise_floor_;
+ std::unique_ptr<std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ N2_initial_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> Y2_smoothed_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> N2_;
+ int N2_counter_ = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_COMFORT_NOISE_GENERATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/decimator.cc b/webrtc/modules/audio_processing/aec3/decimator.cc
new file mode 100644
index 0000000..bd03237
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/decimator.cc
@@ -0,0 +1,91 @@
+/*
+ * 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/audio_processing/aec3/decimator.h"
+
+#include <array>
+#include <vector>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+// signal.butter(2, 3400/8000.0, 'lowpass', analog=False)
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetLowPassFilterDS2() {
+ return std::vector<CascadedBiQuadFilter::BiQuadParam>{
+ {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f},
+ {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f},
+ {{-1.f, 0.f}, {0.13833231f, 0.40743176f}, 0.22711796393486466f}};
+}
+
+// signal.ellip(6, 1, 40, 1800/8000, btype='lowpass', analog=False)
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetLowPassFilterDS4() {
+ return std::vector<CascadedBiQuadFilter::BiQuadParam>{
+ {{-0.08873842f, 0.99605496f}, {0.75916227f, 0.23841065f}, 0.26250696827f},
+ {{0.62273832f, 0.78243018f}, {0.74892112f, 0.5410152f}, 0.26250696827f},
+ {{0.71107693f, 0.70311421f}, {0.74895534f, 0.63924616f}, 0.26250696827f}};
+}
+
+// signal.cheby1(1, 6, [1000/8000, 2000/8000], btype='bandpass', analog=False)
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetBandPassFilterDS8() {
+ return std::vector<CascadedBiQuadFilter::BiQuadParam>{
+ {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true},
+ {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true},
+ {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true},
+ {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true},
+ {{1.f, 0.f}, {0.7601815f, 0.46423542f}, 0.10330478266505948f, true}};
+}
+
+// signal.butter(2, 1000/8000.0, 'highpass', analog=False)
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetHighPassFilter() {
+ return std::vector<CascadedBiQuadFilter::BiQuadParam>{
+ {{1.f, 0.f}, {0.72712179f, 0.21296904f}, 0.7570763753338849f}};
+}
+
+const std::vector<CascadedBiQuadFilter::BiQuadParam> GetPassThroughFilter() {
+ return std::vector<CascadedBiQuadFilter::BiQuadParam>{};
+}
+} // namespace
+
+Decimator::Decimator(size_t down_sampling_factor)
+ : down_sampling_factor_(down_sampling_factor),
+ anti_aliasing_filter_(down_sampling_factor_ == 4
+ ? GetLowPassFilterDS4()
+ : (down_sampling_factor_ == 8
+ ? GetBandPassFilterDS8()
+ : GetLowPassFilterDS2())),
+ noise_reduction_filter_(down_sampling_factor_ == 8
+ ? GetPassThroughFilter()
+ : GetHighPassFilter()) {
+ RTC_DCHECK(down_sampling_factor_ == 2 || down_sampling_factor_ == 4 ||
+ down_sampling_factor_ == 8);
+}
+
+void Decimator::Decimate(rtc::ArrayView<const float> in,
+ rtc::ArrayView<float> out) {
+ RTC_DCHECK_EQ(kBlockSize, in.size());
+ RTC_DCHECK_EQ(kBlockSize / down_sampling_factor_, out.size());
+ std::array<float, kBlockSize> x;
+
+ // Limit the frequency content of the signal to avoid aliasing.
+ anti_aliasing_filter_.Process(in, x);
+
+ // Reduce the impact of near-end noise.
+ noise_reduction_filter_.Process(x);
+
+ // Downsample the signal.
+ for (size_t j = 0, k = 0; j < out.size(); ++j, k += down_sampling_factor_) {
+ RTC_DCHECK_GT(kBlockSize, k);
+ out[j] = x[k];
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/decimator.h b/webrtc/modules/audio_processing/aec3/decimator.h
new file mode 100644
index 0000000..3ccd292
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/decimator.h
@@ -0,0 +1,41 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_DECIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_DECIMATOR_H_
+
+#include <array>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/utility/cascaded_biquad_filter.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Provides functionality for decimating a signal.
+class Decimator {
+ public:
+ explicit Decimator(size_t down_sampling_factor);
+
+ // Downsamples the signal.
+ void Decimate(rtc::ArrayView<const float> in, rtc::ArrayView<float> out);
+
+ private:
+ const size_t down_sampling_factor_;
+ CascadedBiQuadFilter anti_aliasing_filter_;
+ CascadedBiQuadFilter noise_reduction_filter_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(Decimator);
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_DECIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/delay_estimate.h b/webrtc/modules/audio_processing/aec3/delay_estimate.h
new file mode 100644
index 0000000..ea5dd27
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/delay_estimate.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_
+
+namespace webrtc {
+
+// Stores delay_estimates.
+struct DelayEstimate {
+ enum class Quality { kCoarse, kRefined };
+
+ DelayEstimate(Quality quality, size_t delay)
+ : quality(quality), delay(delay) {}
+
+ Quality quality;
+ size_t delay;
+ size_t blocks_since_last_change = 0;
+ size_t blocks_since_last_update = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_
diff --git a/webrtc/modules/audio_processing/aec3/dominant_nearend_detector.cc b/webrtc/modules/audio_processing/aec3/dominant_nearend_detector.cc
new file mode 100644
index 0000000..40073cf
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/dominant_nearend_detector.cc
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/dominant_nearend_detector.h"
+
+#include <numeric>
+
+namespace webrtc {
+DominantNearendDetector::DominantNearendDetector(
+ const EchoCanceller3Config::Suppressor::DominantNearendDetection& config,
+ size_t num_capture_channels)
+ : enr_threshold_(config.enr_threshold),
+ enr_exit_threshold_(config.enr_exit_threshold),
+ snr_threshold_(config.snr_threshold),
+ hold_duration_(config.hold_duration),
+ trigger_threshold_(config.trigger_threshold),
+ use_during_initial_phase_(config.use_during_initial_phase),
+ num_capture_channels_(num_capture_channels),
+ trigger_counters_(num_capture_channels_),
+ hold_counters_(num_capture_channels_) {}
+
+void DominantNearendDetector::Update(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ nearend_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ residual_echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ bool initial_state) {
+ nearend_state_ = false;
+
+ auto low_frequency_energy = [](rtc::ArrayView<const float> spectrum) {
+ RTC_DCHECK_LE(16, spectrum.size());
+ return std::accumulate(spectrum.begin() + 1, spectrum.begin() + 16, 0.f);
+ };
+
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ const float ne_sum = low_frequency_energy(nearend_spectrum[ch]);
+ const float echo_sum = low_frequency_energy(residual_echo_spectrum[ch]);
+ const float noise_sum = low_frequency_energy(comfort_noise_spectrum[ch]);
+
+ // Detect strong active nearend if the nearend is sufficiently stronger than
+ // the echo and the nearend noise.
+ if ((!initial_state || use_during_initial_phase_) &&
+ echo_sum < enr_threshold_ * ne_sum &&
+ ne_sum > snr_threshold_ * noise_sum) {
+ if (++trigger_counters_[ch] >= trigger_threshold_) {
+ // After a period of strong active nearend activity, flag nearend mode.
+ hold_counters_[ch] = hold_duration_;
+ trigger_counters_[ch] = trigger_threshold_;
+ }
+ } else {
+ // Forget previously detected strong active nearend activity.
+ trigger_counters_[ch] = std::max(0, trigger_counters_[ch] - 1);
+ }
+
+ // Exit nearend-state early at strong echo.
+ if (echo_sum > enr_exit_threshold_ * ne_sum &&
+ echo_sum > snr_threshold_ * noise_sum) {
+ hold_counters_[ch] = 0;
+ }
+
+ // Remain in any nearend mode for a certain duration.
+ hold_counters_[ch] = std::max(0, hold_counters_[ch] - 1);
+ nearend_state_ = nearend_state_ || hold_counters_[ch] > 0;
+ }
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/dominant_nearend_detector.h b/webrtc/modules/audio_processing/aec3/dominant_nearend_detector.h
new file mode 100644
index 0000000..046d148
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/dominant_nearend_detector.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_DOMINANT_NEAREND_DETECTOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_DOMINANT_NEAREND_DETECTOR_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/nearend_detector.h"
+
+namespace webrtc {
+// Class for selecting whether the suppressor is in the nearend or echo state.
+class DominantNearendDetector : public NearendDetector {
+ public:
+ DominantNearendDetector(
+ const EchoCanceller3Config::Suppressor::DominantNearendDetection& config,
+ size_t num_capture_channels);
+
+ // Returns whether the current state is the nearend state.
+ bool IsNearendState() const override { return nearend_state_; }
+
+ // Updates the state selection based on latest spectral estimates.
+ void Update(rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ nearend_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ residual_echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ bool initial_state) override;
+
+ private:
+ const float enr_threshold_;
+ const float enr_exit_threshold_;
+ const float snr_threshold_;
+ const int hold_duration_;
+ const int trigger_threshold_;
+ const bool use_during_initial_phase_;
+ const size_t num_capture_channels_;
+
+ bool nearend_state_ = false;
+ std::vector<int> trigger_counters_;
+ std::vector<int> hold_counters_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_DOMINANT_NEAREND_DETECTOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/downsampled_render_buffer.cc b/webrtc/modules/audio_processing/aec3/downsampled_render_buffer.cc
new file mode 100644
index 0000000..c105911
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/downsampled_render_buffer.cc
@@ -0,0 +1,25 @@
+/*
+ * 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/audio_processing/aec3/downsampled_render_buffer.h"
+
+#include <algorithm>
+
+namespace webrtc {
+
+DownsampledRenderBuffer::DownsampledRenderBuffer(size_t downsampled_buffer_size)
+ : size(static_cast<int>(downsampled_buffer_size)),
+ buffer(downsampled_buffer_size, 0.f) {
+ std::fill(buffer.begin(), buffer.end(), 0.f);
+}
+
+DownsampledRenderBuffer::~DownsampledRenderBuffer() = default;
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/downsampled_render_buffer.h b/webrtc/modules/audio_processing/aec3/downsampled_render_buffer.h
new file mode 100644
index 0000000..fbdc9b4
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/downsampled_render_buffer.h
@@ -0,0 +1,58 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_DOWNSAMPLED_RENDER_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_DOWNSAMPLED_RENDER_BUFFER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// Holds the circular buffer of the downsampled render data.
+struct DownsampledRenderBuffer {
+ explicit DownsampledRenderBuffer(size_t downsampled_buffer_size);
+ ~DownsampledRenderBuffer();
+
+ int IncIndex(int index) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return index < size - 1 ? index + 1 : 0;
+ }
+
+ int DecIndex(int index) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return index > 0 ? index - 1 : size - 1;
+ }
+
+ int OffsetIndex(int index, int offset) const {
+ RTC_DCHECK_GE(buffer.size(), offset);
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return (size + index + offset) % size;
+ }
+
+ void UpdateWriteIndex(int offset) { write = OffsetIndex(write, offset); }
+ void IncWriteIndex() { write = IncIndex(write); }
+ void DecWriteIndex() { write = DecIndex(write); }
+ void UpdateReadIndex(int offset) { read = OffsetIndex(read, offset); }
+ void IncReadIndex() { read = IncIndex(read); }
+ void DecReadIndex() { read = DecIndex(read); }
+
+ const int size;
+ std::vector<float> buffer;
+ int write = 0;
+ int read = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_DOWNSAMPLED_RENDER_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/aec3/echo_audibility.cc b/webrtc/modules/audio_processing/aec3/echo_audibility.cc
new file mode 100644
index 0000000..6ae414e
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_audibility.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/echo_audibility.h"
+
+#include <algorithm>
+#include <cmath>
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/block_buffer.h"
+#include "modules/audio_processing/aec3/spectrum_buffer.h"
+#include "modules/audio_processing/aec3/stationarity_estimator.h"
+
+namespace webrtc {
+
+EchoAudibility::EchoAudibility(bool use_render_stationarity_at_init)
+ : use_render_stationarity_at_init_(use_render_stationarity_at_init) {
+ Reset();
+}
+
+EchoAudibility::~EchoAudibility() = default;
+
+void EchoAudibility::Update(const RenderBuffer& render_buffer,
+ rtc::ArrayView<const float> average_reverb,
+ int delay_blocks,
+ bool external_delay_seen) {
+ UpdateRenderNoiseEstimator(render_buffer.GetSpectrumBuffer(),
+ render_buffer.GetBlockBuffer(),
+ external_delay_seen);
+
+ if (external_delay_seen || use_render_stationarity_at_init_) {
+ UpdateRenderStationarityFlags(render_buffer, average_reverb, delay_blocks);
+ }
+}
+
+void EchoAudibility::Reset() {
+ render_stationarity_.Reset();
+ non_zero_render_seen_ = false;
+ render_spectrum_write_prev_ = absl::nullopt;
+}
+
+void EchoAudibility::UpdateRenderStationarityFlags(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const float> average_reverb,
+ int min_channel_delay_blocks) {
+ const SpectrumBuffer& spectrum_buffer = render_buffer.GetSpectrumBuffer();
+ int idx_at_delay = spectrum_buffer.OffsetIndex(spectrum_buffer.read,
+ min_channel_delay_blocks);
+
+ int num_lookahead = render_buffer.Headroom() - min_channel_delay_blocks + 1;
+ num_lookahead = std::max(0, num_lookahead);
+
+ render_stationarity_.UpdateStationarityFlags(spectrum_buffer, average_reverb,
+ idx_at_delay, num_lookahead);
+}
+
+void EchoAudibility::UpdateRenderNoiseEstimator(
+ const SpectrumBuffer& spectrum_buffer,
+ const BlockBuffer& block_buffer,
+ bool external_delay_seen) {
+ if (!render_spectrum_write_prev_) {
+ render_spectrum_write_prev_ = spectrum_buffer.write;
+ render_block_write_prev_ = block_buffer.write;
+ return;
+ }
+ int render_spectrum_write_current = spectrum_buffer.write;
+ if (!non_zero_render_seen_ && !external_delay_seen) {
+ non_zero_render_seen_ = !IsRenderTooLow(block_buffer);
+ }
+ if (non_zero_render_seen_) {
+ for (int idx = render_spectrum_write_prev_.value();
+ idx != render_spectrum_write_current;
+ idx = spectrum_buffer.DecIndex(idx)) {
+ render_stationarity_.UpdateNoiseEstimator(spectrum_buffer.buffer[idx]);
+ }
+ }
+ render_spectrum_write_prev_ = render_spectrum_write_current;
+}
+
+bool EchoAudibility::IsRenderTooLow(const BlockBuffer& block_buffer) {
+ const int num_render_channels =
+ static_cast<int>(block_buffer.buffer[0][0].size());
+ bool too_low = false;
+ const int render_block_write_current = block_buffer.write;
+ if (render_block_write_current == render_block_write_prev_) {
+ too_low = true;
+ } else {
+ for (int idx = render_block_write_prev_; idx != render_block_write_current;
+ idx = block_buffer.IncIndex(idx)) {
+ float max_abs_over_channels = 0.f;
+ for (int ch = 0; ch < num_render_channels; ++ch) {
+ auto block = block_buffer.buffer[idx][0][ch];
+ auto r = std::minmax_element(block.cbegin(), block.cend());
+ float max_abs_channel =
+ std::max(std::fabs(*r.first), std::fabs(*r.second));
+ max_abs_over_channels =
+ std::max(max_abs_over_channels, max_abs_channel);
+ }
+ if (max_abs_over_channels < 10.f) {
+ too_low = true; // Discards all blocks if one of them is too low.
+ break;
+ }
+ }
+ }
+ render_block_write_prev_ = render_block_write_current;
+ return too_low;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/echo_audibility.h b/webrtc/modules/audio_processing/aec3/echo_audibility.h
new file mode 100644
index 0000000..1ffc017
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_audibility.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_AUDIBILITY_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ECHO_AUDIBILITY_H_
+
+#include <stddef.h>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/block_buffer.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/spectrum_buffer.h"
+#include "modules/audio_processing/aec3/stationarity_estimator.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class EchoAudibility {
+ public:
+ explicit EchoAudibility(bool use_render_stationarity_at_init);
+ ~EchoAudibility();
+
+ EchoAudibility(const EchoAudibility&) = delete;
+ EchoAudibility& operator=(const EchoAudibility&) = delete;
+
+ // Feed new render data to the echo audibility estimator.
+ void Update(const RenderBuffer& render_buffer,
+ rtc::ArrayView<const float> average_reverb,
+ int min_channel_delay_blocks,
+ bool external_delay_seen);
+ // Get the residual echo scaling.
+ void GetResidualEchoScaling(bool filter_has_had_time_to_converge,
+ rtc::ArrayView<float> residual_scaling) const {
+ for (size_t band = 0; band < residual_scaling.size(); ++band) {
+ if (render_stationarity_.IsBandStationary(band) &&
+ (filter_has_had_time_to_converge ||
+ use_render_stationarity_at_init_)) {
+ residual_scaling[band] = 0.f;
+ } else {
+ residual_scaling[band] = 1.0f;
+ }
+ }
+ }
+
+ // Returns true if the current render block is estimated as stationary.
+ bool IsBlockStationary() const {
+ return render_stationarity_.IsBlockStationary();
+ }
+
+ private:
+ // Reset the EchoAudibility class.
+ void Reset();
+
+ // Updates the render stationarity flags for the current frame.
+ void UpdateRenderStationarityFlags(const RenderBuffer& render_buffer,
+ rtc::ArrayView<const float> average_reverb,
+ int delay_blocks);
+
+ // Updates the noise estimator with the new render data since the previous
+ // call to this method.
+ void UpdateRenderNoiseEstimator(const SpectrumBuffer& spectrum_buffer,
+ const BlockBuffer& block_buffer,
+ bool external_delay_seen);
+
+ // Returns a bool being true if the render signal contains just close to zero
+ // values.
+ bool IsRenderTooLow(const BlockBuffer& block_buffer);
+
+ absl::optional<int> render_spectrum_write_prev_;
+ int render_block_write_prev_;
+ bool non_zero_render_seen_;
+ const bool use_render_stationarity_at_init_;
+ StationarityEstimator render_stationarity_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_AUDIBILITY_H_
diff --git a/webrtc/modules/audio_processing/aec3/echo_canceller3.cc b/webrtc/modules/audio_processing/aec3/echo_canceller3.cc
new file mode 100644
index 0000000..d2847df
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_canceller3.cc
@@ -0,0 +1,868 @@
+/*
+ * 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/audio_processing/aec3/echo_canceller3.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/high_pass_filter.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/experiments/field_trial_parser.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+
+namespace {
+
+enum class EchoCanceller3ApiCall { kCapture, kRender };
+
+bool DetectSaturation(rtc::ArrayView<const float> y) {
+ for (auto y_k : y) {
+ if (y_k >= 32700.0f || y_k <= -32700.0f) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Retrieves a value from a field trial if it is available. If no value is
+// present, the default value is returned. If the retrieved value is beyond the
+// specified limits, the default value is returned instead.
+void RetrieveFieldTrialValue(const char* trial_name,
+ float min,
+ float max,
+ float* value_to_update) {
+ const std::string field_trial_str = field_trial::FindFullName(trial_name);
+
+ FieldTrialParameter<double> field_trial_param(/*key=*/"", *value_to_update);
+
+ ParseFieldTrial({&field_trial_param}, field_trial_str);
+ float field_trial_value = static_cast<float>(field_trial_param.Get());
+
+ if (field_trial_value >= min && field_trial_value <= max) {
+ *value_to_update = field_trial_value;
+ }
+}
+
+void RetrieveFieldTrialValue(const char* trial_name,
+ int min,
+ int max,
+ int* value_to_update) {
+ const std::string field_trial_str = field_trial::FindFullName(trial_name);
+
+ FieldTrialParameter<int> field_trial_param(/*key=*/"", *value_to_update);
+
+ ParseFieldTrial({&field_trial_param}, field_trial_str);
+ float field_trial_value = field_trial_param.Get();
+
+ if (field_trial_value >= min && field_trial_value <= max) {
+ *value_to_update = field_trial_value;
+ }
+}
+
+void FillSubFrameView(
+ AudioBuffer* frame,
+ size_t sub_frame_index,
+ std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame_view) {
+ RTC_DCHECK_GE(1, sub_frame_index);
+ RTC_DCHECK_LE(0, sub_frame_index);
+ RTC_DCHECK_EQ(frame->num_bands(), sub_frame_view->size());
+ RTC_DCHECK_EQ(frame->num_channels(), (*sub_frame_view)[0].size());
+ for (size_t band = 0; band < sub_frame_view->size(); ++band) {
+ for (size_t channel = 0; channel < (*sub_frame_view)[0].size(); ++channel) {
+ (*sub_frame_view)[band][channel] = rtc::ArrayView<float>(
+ &frame->split_bands(channel)[band][sub_frame_index * kSubFrameLength],
+ kSubFrameLength);
+ }
+ }
+}
+
+void FillSubFrameView(
+ std::vector<std::vector<std::vector<float>>>* frame,
+ size_t sub_frame_index,
+ std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame_view) {
+ RTC_DCHECK_GE(1, sub_frame_index);
+ RTC_DCHECK_EQ(frame->size(), sub_frame_view->size());
+ RTC_DCHECK_EQ((*frame)[0].size(), (*sub_frame_view)[0].size());
+ for (size_t band = 0; band < frame->size(); ++band) {
+ for (size_t channel = 0; channel < (*frame)[band].size(); ++channel) {
+ (*sub_frame_view)[band][channel] = rtc::ArrayView<float>(
+ &(*frame)[band][channel][sub_frame_index * kSubFrameLength],
+ kSubFrameLength);
+ }
+ }
+}
+
+void ProcessCaptureFrameContent(
+ AudioBuffer* linear_output,
+ AudioBuffer* capture,
+ bool level_change,
+ bool saturated_microphone_signal,
+ size_t sub_frame_index,
+ FrameBlocker* capture_blocker,
+ BlockFramer* linear_output_framer,
+ BlockFramer* output_framer,
+ BlockProcessor* block_processor,
+ std::vector<std::vector<std::vector<float>>>* linear_output_block,
+ std::vector<std::vector<rtc::ArrayView<float>>>*
+ linear_output_sub_frame_view,
+ std::vector<std::vector<std::vector<float>>>* capture_block,
+ std::vector<std::vector<rtc::ArrayView<float>>>* capture_sub_frame_view) {
+ FillSubFrameView(capture, sub_frame_index, capture_sub_frame_view);
+
+ if (linear_output) {
+ RTC_DCHECK(linear_output_framer);
+ RTC_DCHECK(linear_output_block);
+ RTC_DCHECK(linear_output_sub_frame_view);
+ FillSubFrameView(linear_output, sub_frame_index,
+ linear_output_sub_frame_view);
+ }
+
+ capture_blocker->InsertSubFrameAndExtractBlock(*capture_sub_frame_view,
+ capture_block);
+ block_processor->ProcessCapture(level_change, saturated_microphone_signal,
+ linear_output_block, capture_block);
+ output_framer->InsertBlockAndExtractSubFrame(*capture_block,
+ capture_sub_frame_view);
+
+ if (linear_output) {
+ RTC_DCHECK(linear_output_framer);
+ linear_output_framer->InsertBlockAndExtractSubFrame(
+ *linear_output_block, linear_output_sub_frame_view);
+ }
+}
+
+void ProcessRemainingCaptureFrameContent(
+ bool level_change,
+ bool saturated_microphone_signal,
+ FrameBlocker* capture_blocker,
+ BlockFramer* linear_output_framer,
+ BlockFramer* output_framer,
+ BlockProcessor* block_processor,
+ std::vector<std::vector<std::vector<float>>>* linear_output_block,
+ std::vector<std::vector<std::vector<float>>>* block) {
+ if (!capture_blocker->IsBlockAvailable()) {
+ return;
+ }
+
+ capture_blocker->ExtractBlock(block);
+ block_processor->ProcessCapture(level_change, saturated_microphone_signal,
+ linear_output_block, block);
+ output_framer->InsertBlock(*block);
+
+ if (linear_output_framer) {
+ RTC_DCHECK(linear_output_block);
+ linear_output_framer->InsertBlock(*linear_output_block);
+ }
+}
+
+void BufferRenderFrameContent(
+ std::vector<std::vector<std::vector<float>>>* render_frame,
+ size_t sub_frame_index,
+ FrameBlocker* render_blocker,
+ BlockProcessor* block_processor,
+ std::vector<std::vector<std::vector<float>>>* block,
+ std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame_view) {
+ FillSubFrameView(render_frame, sub_frame_index, sub_frame_view);
+ render_blocker->InsertSubFrameAndExtractBlock(*sub_frame_view, block);
+ block_processor->BufferRender(*block);
+}
+
+void BufferRemainingRenderFrameContent(
+ FrameBlocker* render_blocker,
+ BlockProcessor* block_processor,
+ std::vector<std::vector<std::vector<float>>>* block) {
+ if (!render_blocker->IsBlockAvailable()) {
+ return;
+ }
+ render_blocker->ExtractBlock(block);
+ block_processor->BufferRender(*block);
+}
+
+void CopyBufferIntoFrame(const AudioBuffer& buffer,
+ size_t num_bands,
+ size_t num_channels,
+ std::vector<std::vector<std::vector<float>>>* frame) {
+ RTC_DCHECK_EQ(num_bands, frame->size());
+ RTC_DCHECK_EQ(num_channels, (*frame)[0].size());
+ RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, (*frame)[0][0].size());
+ for (size_t band = 0; band < num_bands; ++band) {
+ for (size_t channel = 0; channel < num_channels; ++channel) {
+ rtc::ArrayView<const float> buffer_view(
+ &buffer.split_bands_const(channel)[band][0],
+ AudioBuffer::kSplitBandSize);
+ std::copy(buffer_view.begin(), buffer_view.end(),
+ (*frame)[band][channel].begin());
+ }
+ }
+}
+
+} // namespace
+
+// TODO(webrtc:5298): Move this to a separate file.
+EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
+ EchoCanceller3Config adjusted_cfg = config;
+
+ if (field_trial::IsEnabled("WebRTC-Aec3AntiHowlingMinimizationKillSwitch")) {
+ adjusted_cfg.suppressor.high_bands_suppression
+ .anti_howling_activation_threshold = 25.f;
+ adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain = 0.01f;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3UseShortConfigChangeDuration")) {
+ adjusted_cfg.filter.config_change_duration_blocks = 10;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3UseZeroInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = 0.f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3UseDot1SecondsInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = .1f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3UseDot2SecondsInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = .2f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3UseDot3SecondsInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = .3f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3UseDot6SecondsInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = .6f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3UseDot9SecondsInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = .9f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3Use1Dot2SecondsInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = 1.2f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3Use1Dot6SecondsInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = 1.6f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3Use2Dot0SecondsInitialStateDuration")) {
+ adjusted_cfg.filter.initial_state_seconds = 2.0f;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3EchoSaturationDetectionKillSwitch")) {
+ adjusted_cfg.ep_strength.echo_can_saturate = false;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3UseDot2ReverbDefaultLen")) {
+ adjusted_cfg.ep_strength.default_len = 0.2f;
+ } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot3ReverbDefaultLen")) {
+ adjusted_cfg.ep_strength.default_len = 0.3f;
+ } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot4ReverbDefaultLen")) {
+ adjusted_cfg.ep_strength.default_len = 0.4f;
+ } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot5ReverbDefaultLen")) {
+ adjusted_cfg.ep_strength.default_len = 0.5f;
+ } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot6ReverbDefaultLen")) {
+ adjusted_cfg.ep_strength.default_len = 0.6f;
+ } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot7ReverbDefaultLen")) {
+ adjusted_cfg.ep_strength.default_len = 0.7f;
+ } else if (field_trial::IsEnabled("WebRTC-Aec3UseDot8ReverbDefaultLen")) {
+ adjusted_cfg.ep_strength.default_len = 0.8f;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3ShortHeadroomKillSwitch")) {
+ // Two blocks headroom.
+ adjusted_cfg.delay.delay_headroom_samples = kBlockSize * 2;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3ClampInstQualityToZeroKillSwitch")) {
+ adjusted_cfg.erle.clamp_quality_estimate_to_zero = false;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3ClampInstQualityToOneKillSwitch")) {
+ adjusted_cfg.erle.clamp_quality_estimate_to_one = false;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3OnsetDetectionKillSwitch")) {
+ adjusted_cfg.erle.onset_detection = false;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceRenderDelayEstimationDownmixing")) {
+ adjusted_cfg.delay.render_alignment_mixing.downmix = true;
+ adjusted_cfg.delay.render_alignment_mixing.adaptive_selection = false;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceCaptureDelayEstimationDownmixing")) {
+ adjusted_cfg.delay.capture_alignment_mixing.downmix = true;
+ adjusted_cfg.delay.capture_alignment_mixing.adaptive_selection = false;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceCaptureDelayEstimationLeftRightPrioritization")) {
+ adjusted_cfg.delay.capture_alignment_mixing.prefer_first_two_channels =
+ true;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-"
+ "Aec3RenderDelayEstimationLeftRightPrioritizationKillSwitch")) {
+ adjusted_cfg.delay.capture_alignment_mixing.prefer_first_two_channels =
+ false;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3SensitiveDominantNearendActivation")) {
+ adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = 0.5f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3VerySensitiveDominantNearendActivation")) {
+ adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold = 0.75f;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3TransparentAntiHowlingGain")) {
+ adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain = 1.f;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceMoreTransparentNormalSuppressorTuning")) {
+ adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent = 0.4f;
+ adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress = 0.5f;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceMoreTransparentNearendSuppressorTuning")) {
+ adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent = 1.29f;
+ adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress = 1.3f;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceMoreTransparentNormalSuppressorHfTuning")) {
+ adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent = 0.3f;
+ adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress = 0.4f;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceMoreTransparentNearendSuppressorHfTuning")) {
+ adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent = 1.09f;
+ adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress = 1.1f;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceRapidlyAdjustingNormalSuppressorTunings")) {
+ adjusted_cfg.suppressor.normal_tuning.max_inc_factor = 2.5f;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceRapidlyAdjustingNearendSuppressorTunings")) {
+ adjusted_cfg.suppressor.nearend_tuning.max_inc_factor = 2.5f;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceSlowlyAdjustingNormalSuppressorTunings")) {
+ adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf = .2f;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceSlowlyAdjustingNearendSuppressorTunings")) {
+ adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf = .2f;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3EnforceStationarityProperties")) {
+ adjusted_cfg.echo_audibility.use_stationarity_properties = true;
+ }
+
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceStationarityPropertiesAtInit")) {
+ adjusted_cfg.echo_audibility.use_stationarity_properties_at_init = true;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3EnforceLowActiveRenderLimit")) {
+ adjusted_cfg.render_levels.active_render_limit = 50.f;
+ } else if (field_trial::IsEnabled(
+ "WebRTC-Aec3EnforceVeryLowActiveRenderLimit")) {
+ adjusted_cfg.render_levels.active_render_limit = 30.f;
+ }
+
+ if (field_trial::IsEnabled("WebRTC-Aec3NonlinearModeReverbKillSwitch")) {
+ adjusted_cfg.echo_model.model_reverb_in_nonlinear_mode = false;
+ }
+
+ // Field-trial based override for the whole suppressor tuning.
+ const std::string suppressor_tuning_override_trial_name =
+ field_trial::FindFullName("WebRTC-Aec3SuppressorTuningOverride");
+
+ FieldTrialParameter<double> nearend_tuning_mask_lf_enr_transparent(
+ "nearend_tuning_mask_lf_enr_transparent",
+ adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent);
+ FieldTrialParameter<double> nearend_tuning_mask_lf_enr_suppress(
+ "nearend_tuning_mask_lf_enr_suppress",
+ adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress);
+ FieldTrialParameter<double> nearend_tuning_mask_hf_enr_transparent(
+ "nearend_tuning_mask_hf_enr_transparent",
+ adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent);
+ FieldTrialParameter<double> nearend_tuning_mask_hf_enr_suppress(
+ "nearend_tuning_mask_hf_enr_suppress",
+ adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress);
+ FieldTrialParameter<double> nearend_tuning_max_inc_factor(
+ "nearend_tuning_max_inc_factor",
+ adjusted_cfg.suppressor.nearend_tuning.max_inc_factor);
+ FieldTrialParameter<double> nearend_tuning_max_dec_factor_lf(
+ "nearend_tuning_max_dec_factor_lf",
+ adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf);
+ FieldTrialParameter<double> normal_tuning_mask_lf_enr_transparent(
+ "normal_tuning_mask_lf_enr_transparent",
+ adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent);
+ FieldTrialParameter<double> normal_tuning_mask_lf_enr_suppress(
+ "normal_tuning_mask_lf_enr_suppress",
+ adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress);
+ FieldTrialParameter<double> normal_tuning_mask_hf_enr_transparent(
+ "normal_tuning_mask_hf_enr_transparent",
+ adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent);
+ FieldTrialParameter<double> normal_tuning_mask_hf_enr_suppress(
+ "normal_tuning_mask_hf_enr_suppress",
+ adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress);
+ FieldTrialParameter<double> normal_tuning_max_inc_factor(
+ "normal_tuning_max_inc_factor",
+ adjusted_cfg.suppressor.normal_tuning.max_inc_factor);
+ FieldTrialParameter<double> normal_tuning_max_dec_factor_lf(
+ "normal_tuning_max_dec_factor_lf",
+ adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf);
+ FieldTrialParameter<double> dominant_nearend_detection_enr_threshold(
+ "dominant_nearend_detection_enr_threshold",
+ adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold);
+ FieldTrialParameter<double> dominant_nearend_detection_enr_exit_threshold(
+ "dominant_nearend_detection_enr_exit_threshold",
+ adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold);
+ FieldTrialParameter<double> dominant_nearend_detection_snr_threshold(
+ "dominant_nearend_detection_snr_threshold",
+ adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold);
+ FieldTrialParameter<int> dominant_nearend_detection_hold_duration(
+ "dominant_nearend_detection_hold_duration",
+ adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration);
+ FieldTrialParameter<int> dominant_nearend_detection_trigger_threshold(
+ "dominant_nearend_detection_trigger_threshold",
+ adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold);
+ FieldTrialParameter<double> ep_strength_default_len(
+ "ep_strength_default_len", adjusted_cfg.ep_strength.default_len);
+
+ ParseFieldTrial(
+ {&nearend_tuning_mask_lf_enr_transparent,
+ &nearend_tuning_mask_lf_enr_suppress,
+ &nearend_tuning_mask_hf_enr_transparent,
+ &nearend_tuning_mask_hf_enr_suppress, &nearend_tuning_max_inc_factor,
+ &nearend_tuning_max_dec_factor_lf,
+ &normal_tuning_mask_lf_enr_transparent,
+ &normal_tuning_mask_lf_enr_suppress,
+ &normal_tuning_mask_hf_enr_transparent,
+ &normal_tuning_mask_hf_enr_suppress, &normal_tuning_max_inc_factor,
+ &normal_tuning_max_dec_factor_lf,
+ &dominant_nearend_detection_enr_threshold,
+ &dominant_nearend_detection_enr_exit_threshold,
+ &dominant_nearend_detection_snr_threshold,
+ &dominant_nearend_detection_hold_duration,
+ &dominant_nearend_detection_trigger_threshold, &ep_strength_default_len},
+ suppressor_tuning_override_trial_name);
+
+ adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent =
+ static_cast<float>(nearend_tuning_mask_lf_enr_transparent.Get());
+ adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress =
+ static_cast<float>(nearend_tuning_mask_lf_enr_suppress.Get());
+ adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent =
+ static_cast<float>(nearend_tuning_mask_hf_enr_transparent.Get());
+ adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress =
+ static_cast<float>(nearend_tuning_mask_hf_enr_suppress.Get());
+ adjusted_cfg.suppressor.nearend_tuning.max_inc_factor =
+ static_cast<float>(nearend_tuning_max_inc_factor.Get());
+ adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf =
+ static_cast<float>(nearend_tuning_max_dec_factor_lf.Get());
+ adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent =
+ static_cast<float>(normal_tuning_mask_lf_enr_transparent.Get());
+ adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress =
+ static_cast<float>(normal_tuning_mask_lf_enr_suppress.Get());
+ adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent =
+ static_cast<float>(normal_tuning_mask_hf_enr_transparent.Get());
+ adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress =
+ static_cast<float>(normal_tuning_mask_hf_enr_suppress.Get());
+ adjusted_cfg.suppressor.normal_tuning.max_inc_factor =
+ static_cast<float>(normal_tuning_max_inc_factor.Get());
+ adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf =
+ static_cast<float>(normal_tuning_max_dec_factor_lf.Get());
+ adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold =
+ static_cast<float>(dominant_nearend_detection_enr_threshold.Get());
+ adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold =
+ static_cast<float>(dominant_nearend_detection_enr_exit_threshold.Get());
+ adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold =
+ static_cast<float>(dominant_nearend_detection_snr_threshold.Get());
+ adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration =
+ dominant_nearend_detection_hold_duration.Get();
+ adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold =
+ dominant_nearend_detection_trigger_threshold.Get();
+ adjusted_cfg.ep_strength.default_len =
+ static_cast<float>(ep_strength_default_len.Get());
+
+ // Field trial-based overrides of individual suppressor parameters.
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNearendLfMaskTransparentOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNearendLfMaskSuppressOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_suppress);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNearendHfMaskTransparentOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_transparent);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNearendHfMaskSuppressOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.nearend_tuning.mask_hf.enr_suppress);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNearendMaxIncFactorOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.nearend_tuning.max_inc_factor);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNearendMaxDecFactorLfOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.nearend_tuning.max_dec_factor_lf);
+
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNormalLfMaskTransparentOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_transparent);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNormalLfMaskSuppressOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.normal_tuning.mask_lf.enr_suppress);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNormalHfMaskTransparentOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_transparent);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNormalHfMaskSuppressOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.normal_tuning.mask_hf.enr_suppress);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNormalMaxIncFactorOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.normal_tuning.max_inc_factor);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorNormalMaxDecFactorLfOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.normal_tuning.max_dec_factor_lf);
+
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorDominantNearendEnrThresholdOverride", 0.f, 100.f,
+ &adjusted_cfg.suppressor.dominant_nearend_detection.enr_threshold);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorDominantNearendEnrExitThresholdOverride", 0.f,
+ 100.f,
+ &adjusted_cfg.suppressor.dominant_nearend_detection.enr_exit_threshold);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorDominantNearendSnrThresholdOverride", 0.f, 100.f,
+ &adjusted_cfg.suppressor.dominant_nearend_detection.snr_threshold);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorDominantNearendHoldDurationOverride", 0, 1000,
+ &adjusted_cfg.suppressor.dominant_nearend_detection.hold_duration);
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorDominantNearendTriggerThresholdOverride", 0, 1000,
+ &adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold);
+
+ RetrieveFieldTrialValue(
+ "WebRTC-Aec3SuppressorAntiHowlingGainOverride", 0.f, 10.f,
+ &adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain);
+
+ RetrieveFieldTrialValue("WebRTC-Aec3SuppressorEpStrengthDefaultLenOverride",
+ -1.f, 1.f, &adjusted_cfg.ep_strength.default_len);
+
+ return adjusted_cfg;
+}
+
+class EchoCanceller3::RenderWriter {
+ public:
+ RenderWriter(ApmDataDumper* data_dumper,
+ SwapQueue<std::vector<std::vector<std::vector<float>>>,
+ Aec3RenderQueueItemVerifier>* render_transfer_queue,
+ size_t num_bands,
+ size_t num_channels);
+
+ RenderWriter() = delete;
+ RenderWriter(const RenderWriter&) = delete;
+ RenderWriter& operator=(const RenderWriter&) = delete;
+
+ ~RenderWriter();
+ void Insert(const AudioBuffer& input);
+
+ private:
+ ApmDataDumper* data_dumper_;
+ const size_t num_bands_;
+ const size_t num_channels_;
+ HighPassFilter high_pass_filter_;
+ std::vector<std::vector<std::vector<float>>> render_queue_input_frame_;
+ SwapQueue<std::vector<std::vector<std::vector<float>>>,
+ Aec3RenderQueueItemVerifier>* render_transfer_queue_;
+};
+
+EchoCanceller3::RenderWriter::RenderWriter(
+ ApmDataDumper* data_dumper,
+ SwapQueue<std::vector<std::vector<std::vector<float>>>,
+ Aec3RenderQueueItemVerifier>* render_transfer_queue,
+ size_t num_bands,
+ size_t num_channels)
+ : data_dumper_(data_dumper),
+ num_bands_(num_bands),
+ num_channels_(num_channels),
+ high_pass_filter_(16000, num_channels),
+ render_queue_input_frame_(
+ num_bands_,
+ std::vector<std::vector<float>>(
+ num_channels_,
+ std::vector<float>(AudioBuffer::kSplitBandSize, 0.f))),
+ render_transfer_queue_(render_transfer_queue) {
+ RTC_DCHECK(data_dumper);
+}
+
+EchoCanceller3::RenderWriter::~RenderWriter() = default;
+
+void EchoCanceller3::RenderWriter::Insert(const AudioBuffer& input) {
+ RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, input.num_frames_per_band());
+ RTC_DCHECK_EQ(num_bands_, input.num_bands());
+ RTC_DCHECK_EQ(num_channels_, input.num_channels());
+
+ // TODO(bugs.webrtc.org/8759) Temporary work-around.
+ if (num_bands_ != input.num_bands())
+ return;
+
+ data_dumper_->DumpWav("aec3_render_input", AudioBuffer::kSplitBandSize,
+ &input.split_bands_const(0)[0][0], 16000, 1);
+
+ CopyBufferIntoFrame(input, num_bands_, num_channels_,
+ &render_queue_input_frame_);
+ high_pass_filter_.Process(&render_queue_input_frame_[0]);
+
+ static_cast<void>(render_transfer_queue_->Insert(&render_queue_input_frame_));
+}
+
+int EchoCanceller3::instance_count_ = 0;
+
+EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels)
+ : EchoCanceller3(AdjustConfig(config),
+ sample_rate_hz,
+ num_render_channels,
+ num_capture_channels,
+ std::unique_ptr<BlockProcessor>(
+ BlockProcessor::Create(AdjustConfig(config),
+ sample_rate_hz,
+ num_render_channels,
+ num_capture_channels))) {}
+EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ std::unique_ptr<BlockProcessor> block_processor)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ config_(config),
+ sample_rate_hz_(sample_rate_hz),
+ num_bands_(NumBandsForRate(sample_rate_hz_)),
+ num_render_channels_(num_render_channels),
+ num_capture_channels_(num_capture_channels),
+ output_framer_(num_bands_, num_capture_channels_),
+ capture_blocker_(num_bands_, num_capture_channels_),
+ render_blocker_(num_bands_, num_render_channels_),
+ render_transfer_queue_(
+ kRenderTransferQueueSizeFrames,
+ std::vector<std::vector<std::vector<float>>>(
+ num_bands_,
+ std::vector<std::vector<float>>(
+ num_render_channels_,
+ std::vector<float>(AudioBuffer::kSplitBandSize, 0.f))),
+ Aec3RenderQueueItemVerifier(num_bands_,
+ num_render_channels_,
+ AudioBuffer::kSplitBandSize)),
+ block_processor_(std::move(block_processor)),
+ render_queue_output_frame_(
+ num_bands_,
+ std::vector<std::vector<float>>(
+ num_render_channels_,
+ std::vector<float>(AudioBuffer::kSplitBandSize, 0.f))),
+ render_block_(
+ num_bands_,
+ std::vector<std::vector<float>>(num_render_channels_,
+ std::vector<float>(kBlockSize, 0.f))),
+ capture_block_(
+ num_bands_,
+ std::vector<std::vector<float>>(num_capture_channels_,
+ std::vector<float>(kBlockSize, 0.f))),
+ render_sub_frame_view_(
+ num_bands_,
+ std::vector<rtc::ArrayView<float>>(num_render_channels_)),
+ capture_sub_frame_view_(
+ num_bands_,
+ std::vector<rtc::ArrayView<float>>(num_capture_channels_)) {
+ RTC_DCHECK(ValidFullBandRate(sample_rate_hz_));
+
+ if (config_.delay.fixed_capture_delay_samples > 0) {
+ block_delay_buffer_.reset(new BlockDelayBuffer(
+ num_capture_channels_, num_bands_, AudioBuffer::kSplitBandSize,
+ config_.delay.fixed_capture_delay_samples));
+ }
+
+ render_writer_.reset(new RenderWriter(data_dumper_.get(),
+ &render_transfer_queue_, num_bands_,
+ num_render_channels_));
+
+ RTC_DCHECK_EQ(num_bands_, std::max(sample_rate_hz_, 16000) / 16000);
+ RTC_DCHECK_GE(kMaxNumBands, num_bands_);
+
+ if (config_.filter.export_linear_aec_output) {
+ linear_output_framer_.reset(new BlockFramer(1, num_capture_channels_));
+ linear_output_block_ =
+ std::make_unique<std::vector<std::vector<std::vector<float>>>>(
+ 1, std::vector<std::vector<float>>(
+ num_capture_channels_, std::vector<float>(kBlockSize, 0.f)));
+ linear_output_sub_frame_view_ =
+ std::vector<std::vector<rtc::ArrayView<float>>>(
+ 1, std::vector<rtc::ArrayView<float>>(num_capture_channels_));
+ }
+}
+
+EchoCanceller3::~EchoCanceller3() = default;
+
+void EchoCanceller3::AnalyzeRender(const AudioBuffer& render) {
+ RTC_DCHECK_RUNS_SERIALIZED(&render_race_checker_);
+
+ RTC_DCHECK_EQ(render.num_channels(), num_render_channels_);
+ data_dumper_->DumpRaw("aec3_call_order",
+ static_cast<int>(EchoCanceller3ApiCall::kRender));
+
+ return render_writer_->Insert(render);
+}
+
+void EchoCanceller3::AnalyzeCapture(const AudioBuffer& capture) {
+ RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
+ data_dumper_->DumpWav("aec3_capture_analyze_input", capture.num_frames(),
+ capture.channels_const()[0], sample_rate_hz_, 1);
+ saturated_microphone_signal_ = false;
+ for (size_t channel = 0; channel < capture.num_channels(); ++channel) {
+ saturated_microphone_signal_ |=
+ DetectSaturation(rtc::ArrayView<const float>(
+ capture.channels_const()[channel], capture.num_frames()));
+ if (saturated_microphone_signal_) {
+ break;
+ }
+ }
+}
+
+void EchoCanceller3::ProcessCapture(AudioBuffer* capture, bool level_change) {
+ ProcessCapture(capture, nullptr, level_change);
+}
+
+void EchoCanceller3::ProcessCapture(AudioBuffer* capture,
+ AudioBuffer* linear_output,
+ bool level_change) {
+ RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
+ RTC_DCHECK(capture);
+ RTC_DCHECK_EQ(num_bands_, capture->num_bands());
+ RTC_DCHECK_EQ(AudioBuffer::kSplitBandSize, capture->num_frames_per_band());
+ RTC_DCHECK_EQ(capture->num_channels(), num_capture_channels_);
+ data_dumper_->DumpRaw("aec3_call_order",
+ static_cast<int>(EchoCanceller3ApiCall::kCapture));
+
+ if (linear_output && !linear_output_framer_) {
+ RTC_LOG(LS_ERROR) << "Trying to retrieve the linear AEC output without "
+ "properly configuring AEC3.";
+ RTC_NOTREACHED();
+ }
+
+ // Report capture call in the metrics and periodically update API call
+ // metrics.
+ api_call_metrics_.ReportCaptureCall();
+
+ // Optionally delay the capture signal.
+ if (config_.delay.fixed_capture_delay_samples > 0) {
+ RTC_DCHECK(block_delay_buffer_);
+ block_delay_buffer_->DelaySignal(capture);
+ }
+
+ rtc::ArrayView<float> capture_lower_band = rtc::ArrayView<float>(
+ &capture->split_bands(0)[0][0], AudioBuffer::kSplitBandSize);
+
+ data_dumper_->DumpWav("aec3_capture_input", capture_lower_band, 16000, 1);
+
+ EmptyRenderQueue();
+
+ ProcessCaptureFrameContent(linear_output, capture, level_change,
+ saturated_microphone_signal_, 0, &capture_blocker_,
+ linear_output_framer_.get(), &output_framer_,
+ block_processor_.get(), linear_output_block_.get(),
+ &linear_output_sub_frame_view_, &capture_block_,
+ &capture_sub_frame_view_);
+
+ ProcessCaptureFrameContent(linear_output, capture, level_change,
+ saturated_microphone_signal_, 1, &capture_blocker_,
+ linear_output_framer_.get(), &output_framer_,
+ block_processor_.get(), linear_output_block_.get(),
+ &linear_output_sub_frame_view_, &capture_block_,
+ &capture_sub_frame_view_);
+
+ ProcessRemainingCaptureFrameContent(
+ level_change, saturated_microphone_signal_, &capture_blocker_,
+ linear_output_framer_.get(), &output_framer_, block_processor_.get(),
+ linear_output_block_.get(), &capture_block_);
+
+ data_dumper_->DumpWav("aec3_capture_output", AudioBuffer::kSplitBandSize,
+ &capture->split_bands(0)[0][0], 16000, 1);
+}
+
+EchoControl::Metrics EchoCanceller3::GetMetrics() const {
+ RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
+ Metrics metrics;
+ block_processor_->GetMetrics(&metrics);
+ return metrics;
+}
+
+void EchoCanceller3::SetAudioBufferDelay(int delay_ms) {
+ RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
+ block_processor_->SetAudioBufferDelay(delay_ms);
+}
+
+bool EchoCanceller3::ActiveProcessing() const {
+ return true;
+}
+
+EchoCanceller3Config EchoCanceller3::CreateDefaultConfig(
+ size_t num_render_channels,
+ size_t num_capture_channels) {
+ EchoCanceller3Config cfg;
+ if (num_render_channels > 1) {
+ // Use shorter and more rapidly adapting coarse filter to compensate for
+ // thge increased number of total filter parameters to adapt.
+ cfg.filter.coarse.length_blocks = 11;
+ cfg.filter.coarse.rate = 0.95f;
+ cfg.filter.coarse_initial.length_blocks = 11;
+ cfg.filter.coarse_initial.rate = 0.95f;
+
+ // Use more concervative suppressor behavior for non-nearend speech.
+ cfg.suppressor.normal_tuning.max_dec_factor_lf = 0.35f;
+ cfg.suppressor.normal_tuning.max_inc_factor = 1.5f;
+ }
+ return cfg;
+}
+
+void EchoCanceller3::EmptyRenderQueue() {
+ RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
+ bool frame_to_buffer =
+ render_transfer_queue_.Remove(&render_queue_output_frame_);
+ while (frame_to_buffer) {
+ // Report render call in the metrics.
+ api_call_metrics_.ReportRenderCall();
+
+ BufferRenderFrameContent(&render_queue_output_frame_, 0, &render_blocker_,
+ block_processor_.get(), &render_block_,
+ &render_sub_frame_view_);
+
+ BufferRenderFrameContent(&render_queue_output_frame_, 1, &render_blocker_,
+ block_processor_.get(), &render_block_,
+ &render_sub_frame_view_);
+
+ BufferRemainingRenderFrameContent(&render_blocker_, block_processor_.get(),
+ &render_block_);
+
+ frame_to_buffer =
+ render_transfer_queue_.Remove(&render_queue_output_frame_);
+ }
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/echo_canceller3.h b/webrtc/modules/audio_processing/aec3/echo_canceller3.h
new file mode 100644
index 0000000..bacd5df
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_canceller3.h
@@ -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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_CANCELLER3_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ECHO_CANCELLER3_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "api/audio/echo_control.h"
+#include "modules/audio_processing/aec3/api_call_jitter_metrics.h"
+#include "modules/audio_processing/aec3/block_delay_buffer.h"
+#include "modules/audio_processing/aec3/block_framer.h"
+#include "modules/audio_processing/aec3/block_processor.h"
+#include "modules/audio_processing/aec3/frame_blocker.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/race_checker.h"
+#include "rtc_base/swap_queue.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+// Method for adjusting config parameter dependencies.
+// Only to be used externally to AEC3 for testing purposes.
+// TODO(webrtc:5298): Move this to a separate file.
+EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config);
+
+// Functor for verifying the invariance of the frames being put into the render
+// queue.
+class Aec3RenderQueueItemVerifier {
+ public:
+ Aec3RenderQueueItemVerifier(size_t num_bands,
+ size_t num_channels,
+ size_t frame_length)
+ : num_bands_(num_bands),
+ num_channels_(num_channels),
+ frame_length_(frame_length) {}
+
+ bool operator()(const std::vector<std::vector<std::vector<float>>>& v) const {
+ if (v.size() != num_bands_) {
+ return false;
+ }
+ for (const auto& band : v) {
+ if (band.size() != num_channels_) {
+ return false;
+ }
+ for (const auto& channel : band) {
+ if (channel.size() != frame_length_) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private:
+ const size_t num_bands_;
+ const size_t num_channels_;
+ const size_t frame_length_;
+};
+
+// Main class for the echo canceller3.
+// It does 4 things:
+// -Receives 10 ms frames of band-split audio.
+// -Provides the lower level echo canceller functionality with
+// blocks of 64 samples of audio data.
+// -Partially handles the jitter in the render and capture API
+// call sequence.
+//
+// The class is supposed to be used in a non-concurrent manner apart from the
+// AnalyzeRender call which can be called concurrently with the other methods.
+class EchoCanceller3 : public EchoControl {
+ public:
+ // Normal c-tor to use.
+ EchoCanceller3(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels);
+ // Testing c-tor that is used only for testing purposes.
+ EchoCanceller3(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ std::unique_ptr<BlockProcessor> block_processor);
+ ~EchoCanceller3() override;
+ EchoCanceller3(const EchoCanceller3&) = delete;
+ EchoCanceller3& operator=(const EchoCanceller3&) = delete;
+
+ // Analyzes and stores an internal copy of the split-band domain render
+ // signal.
+ void AnalyzeRender(AudioBuffer* render) override { AnalyzeRender(*render); }
+ // Analyzes the full-band domain capture signal to detect signal saturation.
+ void AnalyzeCapture(AudioBuffer* capture) override {
+ AnalyzeCapture(*capture);
+ }
+ // Processes the split-band domain capture signal in order to remove any echo
+ // present in the signal.
+ void ProcessCapture(AudioBuffer* capture, bool level_change) override;
+ // As above, but also returns the linear filter output.
+ void ProcessCapture(AudioBuffer* capture,
+ AudioBuffer* linear_output,
+ bool level_change) override;
+ // Collect current metrics from the echo canceller.
+ Metrics GetMetrics() const override;
+ // Provides an optional external estimate of the audio buffer delay.
+ void SetAudioBufferDelay(int delay_ms) override;
+
+ bool ActiveProcessing() const override;
+
+ // Signals whether an external detector has detected echo leakage from the
+ // echo canceller.
+ // Note that in the case echo leakage has been flagged, it should be unflagged
+ // once it is no longer occurring.
+ void UpdateEchoLeakageStatus(bool leakage_detected) {
+ RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
+ block_processor_->UpdateEchoLeakageStatus(leakage_detected);
+ }
+
+ // Produces a default configuration that is suitable for a certain combination
+ // of render and capture channels.
+ static EchoCanceller3Config CreateDefaultConfig(size_t num_render_channels,
+ size_t num_capture_channels);
+
+ private:
+ class RenderWriter;
+
+ // Empties the render SwapQueue.
+ void EmptyRenderQueue();
+
+ // Analyzes and stores an internal copy of the split-band domain render
+ // signal.
+ void AnalyzeRender(const AudioBuffer& render);
+ // Analyzes the full-band domain capture signal to detect signal saturation.
+ void AnalyzeCapture(const AudioBuffer& capture);
+
+ rtc::RaceChecker capture_race_checker_;
+ rtc::RaceChecker render_race_checker_;
+
+ // State that is accessed by the AnalyzeRender call.
+ std::unique_ptr<RenderWriter> render_writer_
+ RTC_GUARDED_BY(render_race_checker_);
+
+ // State that may be accessed by the capture thread.
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const EchoCanceller3Config config_;
+ const int sample_rate_hz_;
+ const int num_bands_;
+ const size_t num_render_channels_;
+ const size_t num_capture_channels_;
+ std::unique_ptr<BlockFramer> linear_output_framer_
+ RTC_GUARDED_BY(capture_race_checker_);
+ BlockFramer output_framer_ RTC_GUARDED_BY(capture_race_checker_);
+ FrameBlocker capture_blocker_ RTC_GUARDED_BY(capture_race_checker_);
+ FrameBlocker render_blocker_ RTC_GUARDED_BY(capture_race_checker_);
+ SwapQueue<std::vector<std::vector<std::vector<float>>>,
+ Aec3RenderQueueItemVerifier>
+ render_transfer_queue_;
+ std::unique_ptr<BlockProcessor> block_processor_
+ RTC_GUARDED_BY(capture_race_checker_);
+ std::vector<std::vector<std::vector<float>>> render_queue_output_frame_
+ RTC_GUARDED_BY(capture_race_checker_);
+ bool saturated_microphone_signal_ RTC_GUARDED_BY(capture_race_checker_) =
+ false;
+ std::vector<std::vector<std::vector<float>>> render_block_
+ RTC_GUARDED_BY(capture_race_checker_);
+ std::unique_ptr<std::vector<std::vector<std::vector<float>>>>
+ linear_output_block_ RTC_GUARDED_BY(capture_race_checker_);
+ std::vector<std::vector<std::vector<float>>> capture_block_
+ RTC_GUARDED_BY(capture_race_checker_);
+ std::vector<std::vector<rtc::ArrayView<float>>> render_sub_frame_view_
+ RTC_GUARDED_BY(capture_race_checker_);
+ std::vector<std::vector<rtc::ArrayView<float>>> linear_output_sub_frame_view_
+ RTC_GUARDED_BY(capture_race_checker_);
+ std::vector<std::vector<rtc::ArrayView<float>>> capture_sub_frame_view_
+ RTC_GUARDED_BY(capture_race_checker_);
+ std::unique_ptr<BlockDelayBuffer> block_delay_buffer_
+ RTC_GUARDED_BY(capture_race_checker_);
+ ApiCallJitterMetrics api_call_metrics_ RTC_GUARDED_BY(capture_race_checker_);
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_CANCELLER3_H_
diff --git a/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.cc b/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.cc
new file mode 100644
index 0000000..2c987f9
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.cc
@@ -0,0 +1,125 @@
+/*
+ * 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/audio_processing/aec3/echo_path_delay_estimator.h"
+
+#include <array>
+
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+EchoPathDelayEstimator::EchoPathDelayEstimator(
+ ApmDataDumper* data_dumper,
+ const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : data_dumper_(data_dumper),
+ down_sampling_factor_(config.delay.down_sampling_factor),
+ sub_block_size_(down_sampling_factor_ != 0
+ ? kBlockSize / down_sampling_factor_
+ : kBlockSize),
+ capture_mixer_(num_capture_channels,
+ config.delay.capture_alignment_mixing),
+ capture_decimator_(down_sampling_factor_),
+ matched_filter_(
+ data_dumper_,
+ DetectOptimization(),
+ sub_block_size_,
+ kMatchedFilterWindowSizeSubBlocks,
+ config.delay.num_filters,
+ kMatchedFilterAlignmentShiftSizeSubBlocks,
+ config.delay.down_sampling_factor == 8
+ ? config.render_levels.poor_excitation_render_limit_ds8
+ : config.render_levels.poor_excitation_render_limit,
+ config.delay.delay_estimate_smoothing,
+ config.delay.delay_candidate_detection_threshold),
+ matched_filter_lag_aggregator_(data_dumper_,
+ matched_filter_.GetMaxFilterLag(),
+ config.delay.delay_selection_thresholds) {
+ RTC_DCHECK(data_dumper);
+ RTC_DCHECK(down_sampling_factor_ > 0);
+}
+
+EchoPathDelayEstimator::~EchoPathDelayEstimator() = default;
+
+void EchoPathDelayEstimator::Reset(bool reset_delay_confidence) {
+ Reset(true, reset_delay_confidence);
+}
+
+absl::optional<DelayEstimate> EchoPathDelayEstimator::EstimateDelay(
+ const DownsampledRenderBuffer& render_buffer,
+ const std::vector<std::vector<float>>& capture) {
+ RTC_DCHECK_EQ(kBlockSize, capture[0].size());
+
+ std::array<float, kBlockSize> downsampled_capture_data;
+ rtc::ArrayView<float> downsampled_capture(downsampled_capture_data.data(),
+ sub_block_size_);
+
+ std::array<float, kBlockSize> downmixed_capture;
+ capture_mixer_.ProduceOutput(capture, downmixed_capture);
+ capture_decimator_.Decimate(downmixed_capture, downsampled_capture);
+ data_dumper_->DumpWav("aec3_capture_decimator_output",
+ downsampled_capture.size(), downsampled_capture.data(),
+ 16000 / down_sampling_factor_, 1);
+ matched_filter_.Update(render_buffer, downsampled_capture);
+
+ absl::optional<DelayEstimate> aggregated_matched_filter_lag =
+ matched_filter_lag_aggregator_.Aggregate(
+ matched_filter_.GetLagEstimates());
+
+ // Run clockdrift detection.
+ if (aggregated_matched_filter_lag &&
+ (*aggregated_matched_filter_lag).quality ==
+ DelayEstimate::Quality::kRefined)
+ clockdrift_detector_.Update((*aggregated_matched_filter_lag).delay);
+
+ // TODO(peah): Move this logging outside of this class once EchoCanceller3
+ // development is done.
+ data_dumper_->DumpRaw(
+ "aec3_echo_path_delay_estimator_delay",
+ aggregated_matched_filter_lag
+ ? static_cast<int>(aggregated_matched_filter_lag->delay *
+ down_sampling_factor_)
+ : -1);
+
+ // Return the detected delay in samples as the aggregated matched filter lag
+ // compensated by the down sampling factor for the signal being correlated.
+ if (aggregated_matched_filter_lag) {
+ aggregated_matched_filter_lag->delay *= down_sampling_factor_;
+ }
+
+ if (old_aggregated_lag_ && aggregated_matched_filter_lag &&
+ old_aggregated_lag_->delay == aggregated_matched_filter_lag->delay) {
+ ++consistent_estimate_counter_;
+ } else {
+ consistent_estimate_counter_ = 0;
+ }
+ old_aggregated_lag_ = aggregated_matched_filter_lag;
+ constexpr size_t kNumBlocksPerSecondBy2 = kNumBlocksPerSecond / 2;
+ if (consistent_estimate_counter_ > kNumBlocksPerSecondBy2) {
+ Reset(false, false);
+ }
+
+ return aggregated_matched_filter_lag;
+}
+
+void EchoPathDelayEstimator::Reset(bool reset_lag_aggregator,
+ bool reset_delay_confidence) {
+ if (reset_lag_aggregator) {
+ matched_filter_lag_aggregator_.Reset(reset_delay_confidence);
+ }
+ matched_filter_.Reset();
+ old_aggregated_lag_ = absl::nullopt;
+ consistent_estimate_counter_ = 0;
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.h b/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.h
new file mode 100644
index 0000000..6c8c212
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.h
@@ -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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_DELAY_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_DELAY_ESTIMATOR_H_
+
+#include <stddef.h>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/alignment_mixer.h"
+#include "modules/audio_processing/aec3/clockdrift_detector.h"
+#include "modules/audio_processing/aec3/decimator.h"
+#include "modules/audio_processing/aec3/delay_estimate.h"
+#include "modules/audio_processing/aec3/matched_filter.h"
+#include "modules/audio_processing/aec3/matched_filter_lag_aggregator.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+struct DownsampledRenderBuffer;
+struct EchoCanceller3Config;
+
+// Estimates the delay of the echo path.
+class EchoPathDelayEstimator {
+ public:
+ EchoPathDelayEstimator(ApmDataDumper* data_dumper,
+ const EchoCanceller3Config& config,
+ size_t num_capture_channels);
+ ~EchoPathDelayEstimator();
+
+ // Resets the estimation. If the delay confidence is reset, the reset behavior
+ // is as if the call is restarted.
+ void Reset(bool reset_delay_confidence);
+
+ // Produce a delay estimate if such is avaliable.
+ absl::optional<DelayEstimate> EstimateDelay(
+ const DownsampledRenderBuffer& render_buffer,
+ const std::vector<std::vector<float>>& capture);
+
+ // Log delay estimator properties.
+ void LogDelayEstimationProperties(int sample_rate_hz, size_t shift) const {
+ matched_filter_.LogFilterProperties(sample_rate_hz, shift,
+ down_sampling_factor_);
+ }
+
+ // Returns the level of detected clockdrift.
+ ClockdriftDetector::Level Clockdrift() const {
+ return clockdrift_detector_.ClockdriftLevel();
+ }
+
+ private:
+ ApmDataDumper* const data_dumper_;
+ const size_t down_sampling_factor_;
+ const size_t sub_block_size_;
+ AlignmentMixer capture_mixer_;
+ Decimator capture_decimator_;
+ MatchedFilter matched_filter_;
+ MatchedFilterLagAggregator matched_filter_lag_aggregator_;
+ absl::optional<DelayEstimate> old_aggregated_lag_;
+ size_t consistent_estimate_counter_ = 0;
+ ClockdriftDetector clockdrift_detector_;
+
+ // Internal reset method with more granularity.
+ void Reset(bool reset_lag_aggregator, bool reset_delay_confidence);
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(EchoPathDelayEstimator);
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_DELAY_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/echo_path_variability.cc b/webrtc/modules/audio_processing/aec3/echo_path_variability.cc
new file mode 100644
index 0000000..0ae9cff
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_path_variability.cc
@@ -0,0 +1,22 @@
+/*
+ * 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/audio_processing/aec3/echo_path_variability.h"
+
+namespace webrtc {
+
+EchoPathVariability::EchoPathVariability(bool gain_change,
+ DelayAdjustment delay_change,
+ bool clock_drift)
+ : gain_change(gain_change),
+ delay_change(delay_change),
+ clock_drift(clock_drift) {}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/echo_path_variability.h b/webrtc/modules/audio_processing/aec3/echo_path_variability.h
new file mode 100644
index 0000000..78e4f64
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_path_variability.h
@@ -0,0 +1,37 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_ECHO_PATH_VARIABILITY_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_VARIABILITY_H_
+
+namespace webrtc {
+
+struct EchoPathVariability {
+ enum class DelayAdjustment {
+ kNone,
+ kBufferFlush,
+ kNewDetectedDelay
+ };
+
+ EchoPathVariability(bool gain_change,
+ DelayAdjustment delay_change,
+ bool clock_drift);
+
+ bool AudioPathChanged() const {
+ return gain_change || delay_change != DelayAdjustment::kNone;
+ }
+ bool gain_change;
+ DelayAdjustment delay_change;
+ bool clock_drift;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_PATH_VARIABILITY_H_
diff --git a/webrtc/modules/audio_processing/aec3/echo_remover.cc b/webrtc/modules/audio_processing/aec3/echo_remover.cc
new file mode 100644
index 0000000..a3cd22f
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_remover.cc
@@ -0,0 +1,500 @@
+/*
+ * 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/audio_processing/aec3/echo_remover.h"
+
+#include <math.h>
+#include <stddef.h>
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <memory>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec3_fft.h"
+#include "modules/audio_processing/aec3/aec_state.h"
+#include "modules/audio_processing/aec3/comfort_noise_generator.h"
+#include "modules/audio_processing/aec3/echo_path_variability.h"
+#include "modules/audio_processing/aec3/echo_remover_metrics.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/render_signal_analyzer.h"
+#include "modules/audio_processing/aec3/residual_echo_estimator.h"
+#include "modules/audio_processing/aec3/subtractor.h"
+#include "modules/audio_processing/aec3/subtractor_output.h"
+#include "modules/audio_processing/aec3/suppression_filter.h"
+#include "modules/audio_processing/aec3/suppression_gain.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+namespace {
+
+// Maximum number of channels for which the capture channel data is stored on
+// the stack. If the number of channels are larger than this, they are stored
+// using scratch memory that is pre-allocated on the heap. The reason for this
+// partitioning is not to waste heap space for handling the more common numbers
+// of channels, while at the same time not limiting the support for higher
+// numbers of channels by enforcing the capture channel data to be stored on the
+// stack using a fixed maximum value.
+constexpr size_t kMaxNumChannelsOnStack = 2;
+
+// Chooses the number of channels to store on the heap when that is required due
+// to the number of capture channels being larger than the pre-defined number
+// of channels to store on the stack.
+size_t NumChannelsOnHeap(size_t num_capture_channels) {
+ return num_capture_channels > kMaxNumChannelsOnStack ? num_capture_channels
+ : 0;
+}
+
+void LinearEchoPower(const FftData& E,
+ const FftData& Y,
+ std::array<float, kFftLengthBy2Plus1>* S2) {
+ for (size_t k = 0; k < E.re.size(); ++k) {
+ (*S2)[k] = (Y.re[k] - E.re[k]) * (Y.re[k] - E.re[k]) +
+ (Y.im[k] - E.im[k]) * (Y.im[k] - E.im[k]);
+ }
+}
+
+// Fades between two input signals using a fix-sized transition.
+void SignalTransition(rtc::ArrayView<const float> from,
+ rtc::ArrayView<const float> to,
+ rtc::ArrayView<float> out) {
+ if (from == to) {
+ RTC_DCHECK_EQ(to.size(), out.size());
+ std::copy(to.begin(), to.end(), out.begin());
+ } else {
+ constexpr size_t kTransitionSize = 30;
+ constexpr float kOneByTransitionSizePlusOne = 1.f / (kTransitionSize + 1);
+
+ RTC_DCHECK_EQ(from.size(), to.size());
+ RTC_DCHECK_EQ(from.size(), out.size());
+ RTC_DCHECK_LE(kTransitionSize, out.size());
+
+ for (size_t k = 0; k < kTransitionSize; ++k) {
+ float a = (k + 1) * kOneByTransitionSizePlusOne;
+ out[k] = a * to[k] + (1.f - a) * from[k];
+ }
+
+ std::copy(to.begin() + kTransitionSize, to.end(),
+ out.begin() + kTransitionSize);
+ }
+}
+
+// Computes a windowed (square root Hanning) padded FFT and updates the related
+// memory.
+void WindowedPaddedFft(const Aec3Fft& fft,
+ rtc::ArrayView<const float> v,
+ rtc::ArrayView<float> v_old,
+ FftData* V) {
+ fft.PaddedFft(v, v_old, Aec3Fft::Window::kSqrtHanning, V);
+ std::copy(v.begin(), v.end(), v_old.begin());
+}
+
+// Class for removing the echo from the capture signal.
+class EchoRemoverImpl final : public EchoRemover {
+ public:
+ EchoRemoverImpl(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels);
+ ~EchoRemoverImpl() override;
+ EchoRemoverImpl(const EchoRemoverImpl&) = delete;
+ EchoRemoverImpl& operator=(const EchoRemoverImpl&) = delete;
+
+ void GetMetrics(EchoControl::Metrics* metrics) const override;
+
+ // Removes the echo from a block of samples from the capture signal. The
+ // supplied render signal is assumed to be pre-aligned with the capture
+ // signal.
+ void ProcessCapture(
+ EchoPathVariability echo_path_variability,
+ bool capture_signal_saturation,
+ const absl::optional<DelayEstimate>& external_delay,
+ RenderBuffer* render_buffer,
+ std::vector<std::vector<std::vector<float>>>* linear_output,
+ std::vector<std::vector<std::vector<float>>>* capture) override;
+
+ // Updates the status on whether echo leakage is detected in the output of the
+ // echo remover.
+ void UpdateEchoLeakageStatus(bool leakage_detected) override {
+ echo_leakage_detected_ = leakage_detected;
+ }
+
+ private:
+ // Selects which of the coarse and refined linear filter outputs that is most
+ // appropriate to pass to the suppressor and forms the linear filter output by
+ // smoothly transition between those.
+ void FormLinearFilterOutput(const SubtractorOutput& subtractor_output,
+ rtc::ArrayView<float> output);
+
+ static int instance_count_;
+ const EchoCanceller3Config config_;
+ const Aec3Fft fft_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const Aec3Optimization optimization_;
+ const int sample_rate_hz_;
+ const size_t num_render_channels_;
+ const size_t num_capture_channels_;
+ const bool use_coarse_filter_output_;
+ Subtractor subtractor_;
+ SuppressionGain suppression_gain_;
+ ComfortNoiseGenerator cng_;
+ SuppressionFilter suppression_filter_;
+ RenderSignalAnalyzer render_signal_analyzer_;
+ ResidualEchoEstimator residual_echo_estimator_;
+ bool echo_leakage_detected_ = false;
+ AecState aec_state_;
+ EchoRemoverMetrics metrics_;
+ std::vector<std::array<float, kFftLengthBy2>> e_old_;
+ std::vector<std::array<float, kFftLengthBy2>> y_old_;
+ size_t block_counter_ = 0;
+ int gain_change_hangover_ = 0;
+ bool refined_filter_output_last_selected_ = true;
+
+ std::vector<std::array<float, kFftLengthBy2>> e_heap_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> Y2_heap_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> E2_heap_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> R2_heap_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> S2_linear_heap_;
+ std::vector<FftData> Y_heap_;
+ std::vector<FftData> E_heap_;
+ std::vector<FftData> comfort_noise_heap_;
+ std::vector<FftData> high_band_comfort_noise_heap_;
+ std::vector<SubtractorOutput> subtractor_output_heap_;
+};
+
+int EchoRemoverImpl::instance_count_ = 0;
+
+EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels)
+ : config_(config),
+ fft_(),
+ data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ optimization_(DetectOptimization()),
+ sample_rate_hz_(sample_rate_hz),
+ num_render_channels_(num_render_channels),
+ num_capture_channels_(num_capture_channels),
+ use_coarse_filter_output_(
+ config_.filter.enable_coarse_filter_output_usage),
+ subtractor_(config,
+ num_render_channels_,
+ num_capture_channels_,
+ data_dumper_.get(),
+ optimization_),
+ suppression_gain_(config_,
+ optimization_,
+ sample_rate_hz,
+ num_capture_channels),
+ cng_(config_, optimization_, num_capture_channels_),
+ suppression_filter_(optimization_,
+ sample_rate_hz_,
+ num_capture_channels_),
+ render_signal_analyzer_(config_),
+ residual_echo_estimator_(config_, num_render_channels),
+ aec_state_(config_, num_capture_channels_),
+ e_old_(num_capture_channels_, {0.f}),
+ y_old_(num_capture_channels_, {0.f}),
+ e_heap_(NumChannelsOnHeap(num_capture_channels_), {0.f}),
+ Y2_heap_(NumChannelsOnHeap(num_capture_channels_)),
+ E2_heap_(NumChannelsOnHeap(num_capture_channels_)),
+ R2_heap_(NumChannelsOnHeap(num_capture_channels_)),
+ S2_linear_heap_(NumChannelsOnHeap(num_capture_channels_)),
+ Y_heap_(NumChannelsOnHeap(num_capture_channels_)),
+ E_heap_(NumChannelsOnHeap(num_capture_channels_)),
+ comfort_noise_heap_(NumChannelsOnHeap(num_capture_channels_)),
+ high_band_comfort_noise_heap_(NumChannelsOnHeap(num_capture_channels_)),
+ subtractor_output_heap_(NumChannelsOnHeap(num_capture_channels_)) {
+ RTC_DCHECK(ValidFullBandRate(sample_rate_hz));
+}
+
+EchoRemoverImpl::~EchoRemoverImpl() = default;
+
+void EchoRemoverImpl::GetMetrics(EchoControl::Metrics* metrics) const {
+ // Echo return loss (ERL) is inverted to go from gain to attenuation.
+ metrics->echo_return_loss = -10.0 * std::log10(aec_state_.ErlTimeDomain());
+ metrics->echo_return_loss_enhancement =
+ Log2TodB(aec_state_.FullBandErleLog2());
+}
+
+void EchoRemoverImpl::ProcessCapture(
+ EchoPathVariability echo_path_variability,
+ bool capture_signal_saturation,
+ const absl::optional<DelayEstimate>& external_delay,
+ RenderBuffer* render_buffer,
+ std::vector<std::vector<std::vector<float>>>* linear_output,
+ std::vector<std::vector<std::vector<float>>>* capture) {
+ ++block_counter_;
+ const std::vector<std::vector<std::vector<float>>>& x =
+ render_buffer->Block(0);
+ std::vector<std::vector<std::vector<float>>>* y = capture;
+ RTC_DCHECK(render_buffer);
+ RTC_DCHECK(y);
+ RTC_DCHECK_EQ(x.size(), NumBandsForRate(sample_rate_hz_));
+ RTC_DCHECK_EQ(y->size(), NumBandsForRate(sample_rate_hz_));
+ RTC_DCHECK_EQ(x[0].size(), num_render_channels_);
+ RTC_DCHECK_EQ((*y)[0].size(), num_capture_channels_);
+ RTC_DCHECK_EQ(x[0][0].size(), kBlockSize);
+ RTC_DCHECK_EQ((*y)[0][0].size(), kBlockSize);
+
+ // Stack allocated data to use when the number of channels is low.
+ std::array<std::array<float, kFftLengthBy2>, kMaxNumChannelsOnStack> e_stack;
+ std::array<std::array<float, kFftLengthBy2Plus1>, kMaxNumChannelsOnStack>
+ Y2_stack;
+ std::array<std::array<float, kFftLengthBy2Plus1>, kMaxNumChannelsOnStack>
+ E2_stack;
+ std::array<std::array<float, kFftLengthBy2Plus1>, kMaxNumChannelsOnStack>
+ R2_stack;
+ std::array<std::array<float, kFftLengthBy2Plus1>, kMaxNumChannelsOnStack>
+ S2_linear_stack;
+ std::array<FftData, kMaxNumChannelsOnStack> Y_stack;
+ std::array<FftData, kMaxNumChannelsOnStack> E_stack;
+ std::array<FftData, kMaxNumChannelsOnStack> comfort_noise_stack;
+ std::array<FftData, kMaxNumChannelsOnStack> high_band_comfort_noise_stack;
+ std::array<SubtractorOutput, kMaxNumChannelsOnStack> subtractor_output_stack;
+
+ rtc::ArrayView<std::array<float, kFftLengthBy2>> e(e_stack.data(),
+ num_capture_channels_);
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> Y2(
+ Y2_stack.data(), num_capture_channels_);
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> E2(
+ E2_stack.data(), num_capture_channels_);
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2(
+ R2_stack.data(), num_capture_channels_);
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> S2_linear(
+ S2_linear_stack.data(), num_capture_channels_);
+ rtc::ArrayView<FftData> Y(Y_stack.data(), num_capture_channels_);
+ rtc::ArrayView<FftData> E(E_stack.data(), num_capture_channels_);
+ rtc::ArrayView<FftData> comfort_noise(comfort_noise_stack.data(),
+ num_capture_channels_);
+ rtc::ArrayView<FftData> high_band_comfort_noise(
+ high_band_comfort_noise_stack.data(), num_capture_channels_);
+ rtc::ArrayView<SubtractorOutput> subtractor_output(
+ subtractor_output_stack.data(), num_capture_channels_);
+ if (NumChannelsOnHeap(num_capture_channels_) > 0) {
+ // If the stack-allocated space is too small, use the heap for storing the
+ // microphone data.
+ e = rtc::ArrayView<std::array<float, kFftLengthBy2>>(e_heap_.data(),
+ num_capture_channels_);
+ Y2 = rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>>(
+ Y2_heap_.data(), num_capture_channels_);
+ E2 = rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>>(
+ E2_heap_.data(), num_capture_channels_);
+ R2 = rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>>(
+ R2_heap_.data(), num_capture_channels_);
+ S2_linear = rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>>(
+ S2_linear_heap_.data(), num_capture_channels_);
+ Y = rtc::ArrayView<FftData>(Y_heap_.data(), num_capture_channels_);
+ E = rtc::ArrayView<FftData>(E_heap_.data(), num_capture_channels_);
+ comfort_noise = rtc::ArrayView<FftData>(comfort_noise_heap_.data(),
+ num_capture_channels_);
+ high_band_comfort_noise = rtc::ArrayView<FftData>(
+ high_band_comfort_noise_heap_.data(), num_capture_channels_);
+ subtractor_output = rtc::ArrayView<SubtractorOutput>(
+ subtractor_output_heap_.data(), num_capture_channels_);
+ }
+
+ data_dumper_->DumpWav("aec3_echo_remover_capture_input", kBlockSize,
+ &(*y)[0][0][0], 16000, 1);
+ data_dumper_->DumpWav("aec3_echo_remover_render_input", kBlockSize,
+ &x[0][0][0], 16000, 1);
+ data_dumper_->DumpRaw("aec3_echo_remover_capture_input", (*y)[0][0]);
+ data_dumper_->DumpRaw("aec3_echo_remover_render_input", x[0][0]);
+
+ aec_state_.UpdateCaptureSaturation(capture_signal_saturation);
+
+ if (echo_path_variability.AudioPathChanged()) {
+ // Ensure that the gain change is only acted on once per frame.
+ if (echo_path_variability.gain_change) {
+ if (gain_change_hangover_ == 0) {
+ constexpr int kMaxBlocksPerFrame = 3;
+ gain_change_hangover_ = kMaxBlocksPerFrame;
+ rtc::LoggingSeverity log_level =
+ config_.delay.log_warning_on_delay_changes ? rtc::LS_WARNING
+ : rtc::LS_VERBOSE;
+ RTC_LOG_V(log_level)
+ << "Gain change detected at block " << block_counter_;
+ } else {
+ echo_path_variability.gain_change = false;
+ }
+ }
+
+ subtractor_.HandleEchoPathChange(echo_path_variability);
+ aec_state_.HandleEchoPathChange(echo_path_variability);
+
+ if (echo_path_variability.delay_change !=
+ EchoPathVariability::DelayAdjustment::kNone) {
+ suppression_gain_.SetInitialState(true);
+ }
+ }
+ if (gain_change_hangover_ > 0) {
+ --gain_change_hangover_;
+ }
+
+ // Analyze the render signal.
+ render_signal_analyzer_.Update(*render_buffer,
+ aec_state_.MinDirectPathFilterDelay());
+
+ // State transition.
+ if (aec_state_.TransitionTriggered()) {
+ subtractor_.ExitInitialState();
+ suppression_gain_.SetInitialState(false);
+ }
+
+ // Perform linear echo cancellation.
+ subtractor_.Process(*render_buffer, (*y)[0], render_signal_analyzer_,
+ aec_state_, subtractor_output);
+
+ // Compute spectra.
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ FormLinearFilterOutput(subtractor_output[ch], e[ch]);
+ WindowedPaddedFft(fft_, (*y)[0][ch], y_old_[ch], &Y[ch]);
+ WindowedPaddedFft(fft_, e[ch], e_old_[ch], &E[ch]);
+ LinearEchoPower(E[ch], Y[ch], &S2_linear[ch]);
+ Y[ch].Spectrum(optimization_, Y2[ch]);
+ E[ch].Spectrum(optimization_, E2[ch]);
+ }
+
+ // Optionally return the linear filter output.
+ if (linear_output) {
+ RTC_DCHECK_GE(1, linear_output->size());
+ RTC_DCHECK_EQ(num_capture_channels_, linear_output[0].size());
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ RTC_DCHECK_EQ(kBlockSize, (*linear_output)[0][ch].size());
+ std::copy(e[ch].begin(), e[ch].end(), (*linear_output)[0][ch].begin());
+ }
+ }
+
+ // Update the AEC state information.
+ aec_state_.Update(external_delay, subtractor_.FilterFrequencyResponses(),
+ subtractor_.FilterImpulseResponses(), *render_buffer, E2,
+ Y2, subtractor_output);
+
+ // Choose the linear output.
+ const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y;
+
+ data_dumper_->DumpWav("aec3_output_linear", kBlockSize, &(*y)[0][0][0], 16000,
+ 1);
+ data_dumper_->DumpWav("aec3_output_linear2", kBlockSize, &e[0][0], 16000, 1);
+
+ // Estimate the residual echo power.
+ residual_echo_estimator_.Estimate(aec_state_, *render_buffer, S2_linear, Y2,
+ R2);
+
+ // Estimate the comfort noise.
+ cng_.Compute(aec_state_.SaturatedCapture(), Y2, comfort_noise,
+ high_band_comfort_noise);
+
+ // Suppressor nearend estimate.
+ if (aec_state_.UsableLinearEstimate()) {
+ // E2 is bound by Y2.
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ std::transform(E2[ch].begin(), E2[ch].end(), Y2[ch].begin(),
+ E2[ch].begin(),
+ [](float a, float b) { return std::min(a, b); });
+ }
+ }
+ const auto& nearend_spectrum = aec_state_.UsableLinearEstimate() ? E2 : Y2;
+
+ // Suppressor echo estimate.
+ const auto& echo_spectrum =
+ aec_state_.UsableLinearEstimate() ? S2_linear : R2;
+
+ // Compute preferred gains.
+ float high_bands_gain;
+ std::array<float, kFftLengthBy2Plus1> G;
+ suppression_gain_.GetGain(nearend_spectrum, echo_spectrum, R2,
+ cng_.NoiseSpectrum(), render_signal_analyzer_,
+ aec_state_, x, &high_bands_gain, &G);
+
+ suppression_filter_.ApplyGain(comfort_noise, high_band_comfort_noise, G,
+ high_bands_gain, Y_fft, y);
+
+ // Update the metrics.
+ metrics_.Update(aec_state_, cng_.NoiseSpectrum()[0], G);
+
+ // Debug outputs for the purpose of development and analysis.
+ data_dumper_->DumpWav("aec3_echo_estimate", kBlockSize,
+ &subtractor_output[0].s_refined[0], 16000, 1);
+ data_dumper_->DumpRaw("aec3_output", (*y)[0][0]);
+ data_dumper_->DumpRaw("aec3_narrow_render",
+ render_signal_analyzer_.NarrowPeakBand() ? 1 : 0);
+ data_dumper_->DumpRaw("aec3_N2", cng_.NoiseSpectrum()[0]);
+ data_dumper_->DumpRaw("aec3_suppressor_gain", G);
+ data_dumper_->DumpWav("aec3_output",
+ rtc::ArrayView<const float>(&(*y)[0][0][0], kBlockSize),
+ 16000, 1);
+ data_dumper_->DumpRaw("aec3_using_subtractor_output[0]",
+ aec_state_.UseLinearFilterOutput() ? 1 : 0);
+ data_dumper_->DumpRaw("aec3_E2", E2[0]);
+ data_dumper_->DumpRaw("aec3_S2_linear", S2_linear[0]);
+ data_dumper_->DumpRaw("aec3_Y2", Y2[0]);
+ data_dumper_->DumpRaw(
+ "aec3_X2", render_buffer->Spectrum(
+ aec_state_.MinDirectPathFilterDelay())[/*channel=*/0]);
+ data_dumper_->DumpRaw("aec3_R2", R2[0]);
+ data_dumper_->DumpRaw("aec3_filter_delay",
+ aec_state_.MinDirectPathFilterDelay());
+ data_dumper_->DumpRaw("aec3_capture_saturation",
+ aec_state_.SaturatedCapture() ? 1 : 0);
+}
+
+void EchoRemoverImpl::FormLinearFilterOutput(
+ const SubtractorOutput& subtractor_output,
+ rtc::ArrayView<float> output) {
+ RTC_DCHECK_EQ(subtractor_output.e_refined.size(), output.size());
+ RTC_DCHECK_EQ(subtractor_output.e_coarse.size(), output.size());
+ bool use_refined_output = true;
+ if (use_coarse_filter_output_) {
+ // As the output of the refined adaptive filter generally should be better
+ // than the coarse filter output, add a margin and threshold for when
+ // choosing the coarse filter output.
+ if (subtractor_output.e2_coarse < 0.9f * subtractor_output.e2_refined &&
+ subtractor_output.y2 > 30.f * 30.f * kBlockSize &&
+ (subtractor_output.s2_refined > 60.f * 60.f * kBlockSize ||
+ subtractor_output.s2_coarse > 60.f * 60.f * kBlockSize)) {
+ use_refined_output = false;
+ } else {
+ // If the refined filter is diverged, choose the filter output that has
+ // the lowest power.
+ if (subtractor_output.e2_coarse < subtractor_output.e2_refined &&
+ subtractor_output.y2 < subtractor_output.e2_refined) {
+ use_refined_output = false;
+ }
+ }
+ }
+
+ SignalTransition(refined_filter_output_last_selected_
+ ? subtractor_output.e_refined
+ : subtractor_output.e_coarse,
+ use_refined_output ? subtractor_output.e_refined
+ : subtractor_output.e_coarse,
+ output);
+ refined_filter_output_last_selected_ = use_refined_output;
+}
+
+} // namespace
+
+EchoRemover* EchoRemover::Create(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels) {
+ return new EchoRemoverImpl(config, sample_rate_hz, num_render_channels,
+ num_capture_channels);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/echo_remover.h b/webrtc/modules/audio_processing/aec3/echo_remover.h
new file mode 100644
index 0000000..ef41646
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_remover.h
@@ -0,0 +1,55 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_H_
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "api/audio/echo_control.h"
+#include "modules/audio_processing/aec3/delay_estimate.h"
+#include "modules/audio_processing/aec3/echo_path_variability.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+
+namespace webrtc {
+
+// Class for removing the echo from the capture signal.
+class EchoRemover {
+ public:
+ static EchoRemover* Create(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels,
+ size_t num_capture_channels);
+ virtual ~EchoRemover() = default;
+
+ // Get current metrics.
+ virtual void GetMetrics(EchoControl::Metrics* metrics) const = 0;
+
+ // Removes the echo from a block of samples from the capture signal. The
+ // supplied render signal is assumed to be pre-aligned with the capture
+ // signal.
+ virtual void ProcessCapture(
+ EchoPathVariability echo_path_variability,
+ bool capture_signal_saturation,
+ const absl::optional<DelayEstimate>& external_delay,
+ RenderBuffer* render_buffer,
+ std::vector<std::vector<std::vector<float>>>* linear_output,
+ std::vector<std::vector<std::vector<float>>>* capture) = 0;
+
+ // Updates the status on whether echo leakage is detected in the output of the
+ // echo remover.
+ virtual void UpdateEchoLeakageStatus(bool leakage_detected) = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_H_
diff --git a/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc b/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc
new file mode 100644
index 0000000..4502f31
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc
@@ -0,0 +1,246 @@
+/*
+ * 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/audio_processing/aec3/echo_remover_metrics.h"
+
+#include <math.h>
+#include <stddef.h>
+
+#include <algorithm>
+#include <cmath>
+#include <numeric>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr float kOneByMetricsCollectionBlocks = 1.f / kMetricsCollectionBlocks;
+
+} // namespace
+
+EchoRemoverMetrics::DbMetric::DbMetric() : DbMetric(0.f, 0.f, 0.f) {}
+EchoRemoverMetrics::DbMetric::DbMetric(float sum_value,
+ float floor_value,
+ float ceil_value)
+ : sum_value(sum_value), floor_value(floor_value), ceil_value(ceil_value) {}
+
+void EchoRemoverMetrics::DbMetric::Update(float value) {
+ sum_value += value;
+ floor_value = std::min(floor_value, value);
+ ceil_value = std::max(ceil_value, value);
+}
+
+void EchoRemoverMetrics::DbMetric::UpdateInstant(float value) {
+ sum_value = value;
+ floor_value = std::min(floor_value, value);
+ ceil_value = std::max(ceil_value, value);
+}
+
+EchoRemoverMetrics::EchoRemoverMetrics() {
+ ResetMetrics();
+}
+
+void EchoRemoverMetrics::ResetMetrics() {
+ erl_.fill(DbMetric(0.f, 10000.f, 0.000f));
+ erl_time_domain_ = DbMetric(0.f, 10000.f, 0.000f);
+ erle_.fill(DbMetric(0.f, 0.f, 1000.f));
+ erle_time_domain_ = DbMetric(0.f, 0.f, 1000.f);
+ active_render_count_ = 0;
+ saturated_capture_ = false;
+}
+
+void EchoRemoverMetrics::Update(
+ const AecState& aec_state,
+ const std::array<float, kFftLengthBy2Plus1>& comfort_noise_spectrum,
+ const std::array<float, kFftLengthBy2Plus1>& suppressor_gain) {
+ metrics_reported_ = false;
+ if (++block_counter_ <= kMetricsCollectionBlocks) {
+ aec3::UpdateDbMetric(aec_state.Erl(), &erl_);
+ erl_time_domain_.UpdateInstant(aec_state.ErlTimeDomain());
+ aec3::UpdateDbMetric(aec_state.Erle()[0], &erle_);
+ erle_time_domain_.UpdateInstant(aec_state.FullBandErleLog2());
+ active_render_count_ += (aec_state.ActiveRender() ? 1 : 0);
+ saturated_capture_ = saturated_capture_ || aec_state.SaturatedCapture();
+ } else {
+ // Report the metrics over several frames in order to lower the impact of
+ // the logarithms involved on the computational complexity.
+ constexpr int kMetricsCollectionBlocksBy2 = kMetricsCollectionBlocks / 2;
+ switch (block_counter_) {
+ case kMetricsCollectionBlocks + 1:
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErleBand0.Average",
+ aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f,
+ kOneByMetricsCollectionBlocks,
+ erle_[0].sum_value),
+ 0, 19, 20);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErleBand0.Max",
+ aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f,
+ erle_[0].ceil_value),
+ 0, 19, 20);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErleBand0.Min",
+ aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f,
+ erle_[0].floor_value),
+ 0, 19, 20);
+ break;
+ case kMetricsCollectionBlocks + 2:
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErleBand1.Average",
+ aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f,
+ kOneByMetricsCollectionBlocks,
+ erle_[1].sum_value),
+ 0, 19, 20);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErleBand1.Max",
+ aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f,
+ erle_[1].ceil_value),
+ 0, 19, 20);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErleBand1.Min",
+ aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f,
+ erle_[1].floor_value),
+ 0, 19, 20);
+ break;
+ case kMetricsCollectionBlocks + 3:
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErlBand0.Average",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f,
+ kOneByMetricsCollectionBlocks,
+ erl_[0].sum_value),
+ 0, 59, 30);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErlBand0.Max",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
+ erl_[0].ceil_value),
+ 0, 59, 30);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErlBand0.Min",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
+ erl_[0].floor_value),
+ 0, 59, 30);
+ break;
+ case kMetricsCollectionBlocks + 4:
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErlBand1.Average",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f,
+ kOneByMetricsCollectionBlocks,
+ erl_[1].sum_value),
+ 0, 59, 30);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErlBand1.Max",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
+ erl_[1].ceil_value),
+ 0, 59, 30);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.ErlBand1.Min",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
+ erl_[1].floor_value),
+ 0, 59, 30);
+ break;
+ case kMetricsCollectionBlocks + 5:
+ RTC_HISTOGRAM_BOOLEAN(
+ "WebRTC.Audio.EchoCanceller.UsableLinearEstimate",
+ static_cast<int>(aec_state.UsableLinearEstimate() ? 1 : 0));
+ RTC_HISTOGRAM_BOOLEAN(
+ "WebRTC.Audio.EchoCanceller.ActiveRender",
+ static_cast<int>(
+ active_render_count_ > kMetricsCollectionBlocksBy2 ? 1 : 0));
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.FilterDelay",
+ aec_state.MinDirectPathFilterDelay(), 0, 30,
+ 31);
+ RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.EchoCanceller.CaptureSaturation",
+ static_cast<int>(saturated_capture_ ? 1 : 0));
+ break;
+ case kMetricsCollectionBlocks + 6:
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.Erl.Value",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
+ erl_time_domain_.sum_value),
+ 0, 59, 30);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.Erl.Max",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
+ erl_time_domain_.ceil_value),
+ 0, 59, 30);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.Erl.Min",
+ aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
+ erl_time_domain_.floor_value),
+ 0, 59, 30);
+ break;
+ case kMetricsCollectionBlocks + 7:
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.Erle.Value",
+ aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f,
+ erle_time_domain_.sum_value),
+ 0, 19, 20);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.Erle.Max",
+ aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f,
+ erle_time_domain_.ceil_value),
+ 0, 19, 20);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.EchoCanceller.Erle.Min",
+ aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f,
+ erle_time_domain_.floor_value),
+ 0, 19, 20);
+ metrics_reported_ = true;
+ RTC_DCHECK_EQ(kMetricsReportingIntervalBlocks, block_counter_);
+ block_counter_ = 0;
+ ResetMetrics();
+ break;
+ default:
+ RTC_NOTREACHED();
+ break;
+ }
+ }
+}
+
+namespace aec3 {
+
+void UpdateDbMetric(const std::array<float, kFftLengthBy2Plus1>& value,
+ std::array<EchoRemoverMetrics::DbMetric, 2>* statistic) {
+ RTC_DCHECK(statistic);
+ // Truncation is intended in the band width computation.
+ constexpr int kNumBands = 2;
+ constexpr int kBandWidth = 65 / kNumBands;
+ constexpr float kOneByBandWidth = 1.f / kBandWidth;
+ RTC_DCHECK_EQ(kNumBands, statistic->size());
+ RTC_DCHECK_EQ(65, value.size());
+ for (size_t k = 0; k < statistic->size(); ++k) {
+ float average_band =
+ std::accumulate(value.begin() + kBandWidth * k,
+ value.begin() + kBandWidth * (k + 1), 0.f) *
+ kOneByBandWidth;
+ (*statistic)[k].Update(average_band);
+ }
+}
+
+int TransformDbMetricForReporting(bool negate,
+ float min_value,
+ float max_value,
+ float offset,
+ float scaling,
+ float value) {
+ float new_value = 10.f * std::log10(value * scaling + 1e-10f) + offset;
+ if (negate) {
+ new_value = -new_value;
+ }
+ return static_cast<int>(rtc::SafeClamp(new_value, min_value, max_value));
+}
+
+} // namespace aec3
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/echo_remover_metrics.h b/webrtc/modules/audio_processing/aec3/echo_remover_metrics.h
new file mode 100644
index 0000000..77fd8cd
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/echo_remover_metrics.h
@@ -0,0 +1,81 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_METRICS_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_METRICS_H_
+
+#include <array>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec_state.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Handles the reporting of metrics for the echo remover.
+class EchoRemoverMetrics {
+ public:
+ struct DbMetric {
+ DbMetric();
+ DbMetric(float sum_value, float floor_value, float ceil_value);
+ void Update(float value);
+ void UpdateInstant(float value);
+ float sum_value;
+ float floor_value;
+ float ceil_value;
+ };
+
+ EchoRemoverMetrics();
+
+ // Updates the metric with new data.
+ void Update(
+ const AecState& aec_state,
+ const std::array<float, kFftLengthBy2Plus1>& comfort_noise_spectrum,
+ const std::array<float, kFftLengthBy2Plus1>& suppressor_gain);
+
+ // Returns true if the metrics have just been reported, otherwise false.
+ bool MetricsReported() { return metrics_reported_; }
+
+ private:
+ // Resets the metrics.
+ void ResetMetrics();
+
+ int block_counter_ = 0;
+ std::array<DbMetric, 2> erl_;
+ DbMetric erl_time_domain_;
+ std::array<DbMetric, 2> erle_;
+ DbMetric erle_time_domain_;
+ int active_render_count_ = 0;
+ bool saturated_capture_ = false;
+ bool metrics_reported_ = false;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(EchoRemoverMetrics);
+};
+
+namespace aec3 {
+
+// Updates a banded metric of type DbMetric with the values in the supplied
+// array.
+void UpdateDbMetric(const std::array<float, kFftLengthBy2Plus1>& value,
+ std::array<EchoRemoverMetrics::DbMetric, 2>* statistic);
+
+// Transforms a DbMetric from the linear domain into the logarithmic domain.
+int TransformDbMetricForReporting(bool negate,
+ float min_value,
+ float max_value,
+ float offset,
+ float scaling,
+ float value);
+
+} // namespace aec3
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ECHO_REMOVER_METRICS_H_
diff --git a/webrtc/modules/audio_processing/aec3/erl_estimator.cc b/webrtc/modules/audio_processing/aec3/erl_estimator.cc
new file mode 100644
index 0000000..01cc33c
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/erl_estimator.cc
@@ -0,0 +1,146 @@
+/*
+ * 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/audio_processing/aec3/erl_estimator.h"
+
+#include <algorithm>
+#include <numeric>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr float kMinErl = 0.01f;
+constexpr float kMaxErl = 1000.f;
+
+} // namespace
+
+ErlEstimator::ErlEstimator(size_t startup_phase_length_blocks_)
+ : startup_phase_length_blocks__(startup_phase_length_blocks_) {
+ erl_.fill(kMaxErl);
+ hold_counters_.fill(0);
+ erl_time_domain_ = kMaxErl;
+ hold_counter_time_domain_ = 0;
+}
+
+ErlEstimator::~ErlEstimator() = default;
+
+void ErlEstimator::Reset() {
+ blocks_since_reset_ = 0;
+}
+
+void ErlEstimator::Update(
+ const std::vector<bool>& converged_filters,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> render_spectra,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ capture_spectra) {
+ const size_t num_capture_channels = converged_filters.size();
+ RTC_DCHECK_EQ(capture_spectra.size(), num_capture_channels);
+
+ // Corresponds to WGN of power -46 dBFS.
+ constexpr float kX2Min = 44015068.0f;
+
+ const auto first_converged_iter =
+ std::find(converged_filters.begin(), converged_filters.end(), true);
+ const bool any_filter_converged =
+ first_converged_iter != converged_filters.end();
+
+ if (++blocks_since_reset_ < startup_phase_length_blocks__ ||
+ !any_filter_converged) {
+ return;
+ }
+
+ // Use the maximum spectrum across capture and the maximum across render.
+ std::array<float, kFftLengthBy2Plus1> max_capture_spectrum_data;
+ std::array<float, kFftLengthBy2Plus1> max_capture_spectrum =
+ capture_spectra[/*channel=*/0];
+ if (num_capture_channels > 1) {
+ // Initialize using the first channel with a converged filter.
+ const size_t first_converged =
+ std::distance(converged_filters.begin(), first_converged_iter);
+ RTC_DCHECK_GE(first_converged, 0);
+ RTC_DCHECK_LT(first_converged, num_capture_channels);
+ max_capture_spectrum_data = capture_spectra[first_converged];
+
+ for (size_t ch = first_converged + 1; ch < num_capture_channels; ++ch) {
+ if (!converged_filters[ch]) {
+ continue;
+ }
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ max_capture_spectrum_data[k] =
+ std::max(max_capture_spectrum_data[k], capture_spectra[ch][k]);
+ }
+ }
+ max_capture_spectrum = max_capture_spectrum_data;
+ }
+
+ const size_t num_render_channels = render_spectra.size();
+ std::array<float, kFftLengthBy2Plus1> max_render_spectrum_data;
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> max_render_spectrum =
+ render_spectra[/*channel=*/0];
+ if (num_render_channels > 1) {
+ std::copy(render_spectra[0].begin(), render_spectra[0].end(),
+ max_render_spectrum_data.begin());
+ for (size_t ch = 1; ch < num_render_channels; ++ch) {
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ max_render_spectrum_data[k] =
+ std::max(max_render_spectrum_data[k], render_spectra[ch][k]);
+ }
+ }
+ max_render_spectrum = max_render_spectrum_data;
+ }
+
+ const auto& X2 = max_render_spectrum;
+ const auto& Y2 = max_capture_spectrum;
+
+ // Update the estimates in a maximum statistics manner.
+ for (size_t k = 1; k < kFftLengthBy2; ++k) {
+ if (X2[k] > kX2Min) {
+ const float new_erl = Y2[k] / X2[k];
+ if (new_erl < erl_[k]) {
+ hold_counters_[k - 1] = 1000;
+ erl_[k] += 0.1f * (new_erl - erl_[k]);
+ erl_[k] = std::max(erl_[k], kMinErl);
+ }
+ }
+ }
+
+ std::for_each(hold_counters_.begin(), hold_counters_.end(),
+ [](int& a) { --a; });
+ std::transform(hold_counters_.begin(), hold_counters_.end(), erl_.begin() + 1,
+ erl_.begin() + 1, [](int a, float b) {
+ return a > 0 ? b : std::min(kMaxErl, 2.f * b);
+ });
+
+ erl_[0] = erl_[1];
+ erl_[kFftLengthBy2] = erl_[kFftLengthBy2 - 1];
+
+ // Compute ERL over all frequency bins.
+ const float X2_sum = std::accumulate(X2.begin(), X2.end(), 0.0f);
+
+ if (X2_sum > kX2Min * X2.size()) {
+ const float Y2_sum = std::accumulate(Y2.begin(), Y2.end(), 0.0f);
+ const float new_erl = Y2_sum / X2_sum;
+ if (new_erl < erl_time_domain_) {
+ hold_counter_time_domain_ = 1000;
+ erl_time_domain_ += 0.1f * (new_erl - erl_time_domain_);
+ erl_time_domain_ = std::max(erl_time_domain_, kMinErl);
+ }
+ }
+
+ --hold_counter_time_domain_;
+ erl_time_domain_ = (hold_counter_time_domain_ > 0)
+ ? erl_time_domain_
+ : std::min(kMaxErl, 2.f * erl_time_domain_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/erl_estimator.h b/webrtc/modules/audio_processing/aec3/erl_estimator.h
new file mode 100644
index 0000000..89bf6ac
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/erl_estimator.h
@@ -0,0 +1,57 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_ERL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ERL_ESTIMATOR_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Estimates the echo return loss based on the signal spectra.
+class ErlEstimator {
+ public:
+ explicit ErlEstimator(size_t startup_phase_length_blocks_);
+ ~ErlEstimator();
+
+ // Resets the ERL estimation.
+ void Reset();
+
+ // Updates the ERL estimate.
+ void Update(const std::vector<bool>& converged_filters,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ render_spectra,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ capture_spectra);
+
+ // Returns the most recent ERL estimate.
+ const std::array<float, kFftLengthBy2Plus1>& Erl() const { return erl_; }
+ float ErlTimeDomain() const { return erl_time_domain_; }
+
+ private:
+ const size_t startup_phase_length_blocks__;
+ std::array<float, kFftLengthBy2Plus1> erl_;
+ std::array<int, kFftLengthBy2Minus1> hold_counters_;
+ float erl_time_domain_;
+ int hold_counter_time_domain_;
+ size_t blocks_since_reset_ = 0;
+ RTC_DISALLOW_COPY_AND_ASSIGN(ErlEstimator);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ERL_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/erle_estimator.cc b/webrtc/modules/audio_processing/aec3/erle_estimator.cc
new file mode 100644
index 0000000..4d84345
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/erle_estimator.cc
@@ -0,0 +1,86 @@
+/*
+ * 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/audio_processing/aec3/erle_estimator.h"
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+ErleEstimator::ErleEstimator(size_t startup_phase_length_blocks,
+ const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : startup_phase_length_blocks_(startup_phase_length_blocks),
+ fullband_erle_estimator_(config.erle, num_capture_channels),
+ subband_erle_estimator_(config, num_capture_channels) {
+ if (config.erle.num_sections > 1) {
+ signal_dependent_erle_estimator_ =
+ std::make_unique<SignalDependentErleEstimator>(config,
+ num_capture_channels);
+ }
+ Reset(true);
+}
+
+ErleEstimator::~ErleEstimator() = default;
+
+void ErleEstimator::Reset(bool delay_change) {
+ fullband_erle_estimator_.Reset();
+ subband_erle_estimator_.Reset();
+ if (signal_dependent_erle_estimator_) {
+ signal_dependent_erle_estimator_->Reset();
+ }
+ if (delay_change) {
+ blocks_since_reset_ = 0;
+ }
+}
+
+void ErleEstimator::Update(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ filter_frequency_responses,
+ rtc::ArrayView<const float, kFftLengthBy2Plus1>
+ avg_render_spectrum_with_reverb,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> capture_spectra,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ subtractor_spectra,
+ const std::vector<bool>& converged_filters) {
+ RTC_DCHECK_EQ(subband_erle_estimator_.Erle().size(), capture_spectra.size());
+ RTC_DCHECK_EQ(subband_erle_estimator_.Erle().size(),
+ subtractor_spectra.size());
+ const auto& X2_reverb = avg_render_spectrum_with_reverb;
+ const auto& Y2 = capture_spectra;
+ const auto& E2 = subtractor_spectra;
+
+ if (++blocks_since_reset_ < startup_phase_length_blocks_) {
+ return;
+ }
+
+ subband_erle_estimator_.Update(X2_reverb, Y2, E2, converged_filters);
+
+ if (signal_dependent_erle_estimator_) {
+ signal_dependent_erle_estimator_->Update(
+ render_buffer, filter_frequency_responses, X2_reverb, Y2, E2,
+ subband_erle_estimator_.Erle(), converged_filters);
+ }
+
+ fullband_erle_estimator_.Update(X2_reverb, Y2, E2, converged_filters);
+}
+
+void ErleEstimator::Dump(
+ const std::unique_ptr<ApmDataDumper>& data_dumper) const {
+ fullband_erle_estimator_.Dump(data_dumper);
+ subband_erle_estimator_.Dump(data_dumper);
+ if (signal_dependent_erle_estimator_) {
+ signal_dependent_erle_estimator_->Dump(data_dumper);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/erle_estimator.h b/webrtc/modules/audio_processing/aec3/erle_estimator.h
new file mode 100644
index 0000000..d741cff
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/erle_estimator.h
@@ -0,0 +1,99 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_ERLE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_ERLE_ESTIMATOR_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/fullband_erle_estimator.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/signal_dependent_erle_estimator.h"
+#include "modules/audio_processing/aec3/subband_erle_estimator.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+
+namespace webrtc {
+
+// Estimates the echo return loss enhancement. One estimate is done per subband
+// and another one is done using the aggreation of energy over all the subbands.
+class ErleEstimator {
+ public:
+ ErleEstimator(size_t startup_phase_length_blocks,
+ const EchoCanceller3Config& config,
+ size_t num_capture_channels);
+ ~ErleEstimator();
+
+ // Resets the fullband ERLE estimator and the subbands ERLE estimators.
+ void Reset(bool delay_change);
+
+ // Updates the ERLE estimates.
+ void Update(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ filter_frequency_responses,
+ rtc::ArrayView<const float, kFftLengthBy2Plus1>
+ avg_render_spectrum_with_reverb,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ capture_spectra,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ subtractor_spectra,
+ const std::vector<bool>& converged_filters);
+
+ // Returns the most recent subband ERLE estimates.
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
+ return signal_dependent_erle_estimator_
+ ? signal_dependent_erle_estimator_->Erle()
+ : subband_erle_estimator_.Erle();
+ }
+
+ // Returns the subband ERLE that are estimated during onsets (only used for
+ // testing).
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> ErleOnsets()
+ const {
+ return subband_erle_estimator_.ErleOnsets();
+ }
+
+ // Returns the fullband ERLE estimate.
+ float FullbandErleLog2() const {
+ return fullband_erle_estimator_.FullbandErleLog2();
+ }
+
+ // Returns an estimation of the current linear filter quality based on the
+ // current and past fullband ERLE estimates. The returned value is a float
+ // vector with content between 0 and 1 where 1 indicates that, at this current
+ // time instant, the linear filter is reaching its maximum subtraction
+ // performance.
+ rtc::ArrayView<const absl::optional<float>> GetInstLinearQualityEstimates()
+ const {
+ return fullband_erle_estimator_.GetInstLinearQualityEstimates();
+ }
+
+ void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper) const;
+
+ private:
+ const size_t startup_phase_length_blocks_;
+ FullBandErleEstimator fullband_erle_estimator_;
+ SubbandErleEstimator subband_erle_estimator_;
+ std::unique_ptr<SignalDependentErleEstimator>
+ signal_dependent_erle_estimator_;
+ size_t blocks_since_reset_ = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_ERLE_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/fft_buffer.cc b/webrtc/modules/audio_processing/aec3/fft_buffer.cc
new file mode 100644
index 0000000..1ce2d31
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/fft_buffer.cc
@@ -0,0 +1,27 @@
+/*
+ * 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/audio_processing/aec3/fft_buffer.h"
+
+namespace webrtc {
+
+FftBuffer::FftBuffer(size_t size, size_t num_channels)
+ : size(static_cast<int>(size)),
+ buffer(size, std::vector<FftData>(num_channels)) {
+ for (auto& block : buffer) {
+ for (auto& channel_fft_data : block) {
+ channel_fft_data.Clear();
+ }
+ }
+}
+
+FftBuffer::~FftBuffer() = default;
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/fft_buffer.h b/webrtc/modules/audio_processing/aec3/fft_buffer.h
new file mode 100644
index 0000000..4187315
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/fft_buffer.h
@@ -0,0 +1,60 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_FFT_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_FFT_BUFFER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// Struct for bundling a circular buffer of FftData objects together with the
+// read and write indices.
+struct FftBuffer {
+ FftBuffer(size_t size, size_t num_channels);
+ ~FftBuffer();
+
+ int IncIndex(int index) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return index < size - 1 ? index + 1 : 0;
+ }
+
+ int DecIndex(int index) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return index > 0 ? index - 1 : size - 1;
+ }
+
+ int OffsetIndex(int index, int offset) const {
+ RTC_DCHECK_GE(buffer.size(), offset);
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return (size + index + offset) % size;
+ }
+
+ void UpdateWriteIndex(int offset) { write = OffsetIndex(write, offset); }
+ void IncWriteIndex() { write = IncIndex(write); }
+ void DecWriteIndex() { write = DecIndex(write); }
+ void UpdateReadIndex(int offset) { read = OffsetIndex(read, offset); }
+ void IncReadIndex() { read = IncIndex(read); }
+ void DecReadIndex() { read = DecIndex(read); }
+
+ const int size;
+ std::vector<std::vector<FftData>> buffer;
+ int write = 0;
+ int read = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_FFT_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/aec3/fft_data.h b/webrtc/modules/audio_processing/aec3/fft_data.h
new file mode 100644
index 0000000..9c25e78
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/fft_data.h
@@ -0,0 +1,104 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_FFT_DATA_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_FFT_DATA_H_
+
+// Defines WEBRTC_ARCH_X86_FAMILY, used below.
+#include "rtc_base/system/arch.h"
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#include <emmintrin.h>
+#endif
+#include <algorithm>
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// Struct that holds imaginary data produced from 128 point real-valued FFTs.
+struct FftData {
+ // Copies the data in src.
+ void Assign(const FftData& src) {
+ std::copy(src.re.begin(), src.re.end(), re.begin());
+ std::copy(src.im.begin(), src.im.end(), im.begin());
+ im[0] = im[kFftLengthBy2] = 0;
+ }
+
+ // Clears all the imaginary.
+ void Clear() {
+ re.fill(0.f);
+ im.fill(0.f);
+ }
+
+ // Computes the power spectrum of the data.
+ void SpectrumAVX2(rtc::ArrayView<float> power_spectrum) const;
+
+ // Computes the power spectrum of the data.
+ void Spectrum(Aec3Optimization optimization,
+ rtc::ArrayView<float> power_spectrum) const {
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, power_spectrum.size());
+ switch (optimization) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2: {
+ constexpr int kNumFourBinBands = kFftLengthBy2 / 4;
+ constexpr int kLimit = kNumFourBinBands * 4;
+ for (size_t k = 0; k < kLimit; k += 4) {
+ const __m128 r = _mm_loadu_ps(&re[k]);
+ const __m128 i = _mm_loadu_ps(&im[k]);
+ const __m128 ii = _mm_mul_ps(i, i);
+ const __m128 rr = _mm_mul_ps(r, r);
+ const __m128 rrii = _mm_add_ps(rr, ii);
+ _mm_storeu_ps(&power_spectrum[k], rrii);
+ }
+ power_spectrum[kFftLengthBy2] = re[kFftLengthBy2] * re[kFftLengthBy2] +
+ im[kFftLengthBy2] * im[kFftLengthBy2];
+ } break;
+ case Aec3Optimization::kAvx2:
+ SpectrumAVX2(power_spectrum);
+ break;
+#endif
+ default:
+ std::transform(re.begin(), re.end(), im.begin(), power_spectrum.begin(),
+ [](float a, float b) { return a * a + b * b; });
+ }
+ }
+
+ // Copy the data from an interleaved array.
+ void CopyFromPackedArray(const std::array<float, kFftLength>& v) {
+ re[0] = v[0];
+ re[kFftLengthBy2] = v[1];
+ im[0] = im[kFftLengthBy2] = 0;
+ for (size_t k = 1, j = 2; k < kFftLengthBy2; ++k) {
+ re[k] = v[j++];
+ im[k] = v[j++];
+ }
+ }
+
+ // Copies the data into an interleaved array.
+ void CopyToPackedArray(std::array<float, kFftLength>* v) const {
+ RTC_DCHECK(v);
+ (*v)[0] = re[0];
+ (*v)[1] = re[kFftLengthBy2];
+ for (size_t k = 1, j = 2; k < kFftLengthBy2; ++k) {
+ (*v)[j++] = re[k];
+ (*v)[j++] = im[k];
+ }
+ }
+
+ std::array<float, kFftLengthBy2Plus1> re;
+ std::array<float, kFftLengthBy2Plus1> im;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_FFT_DATA_H_
diff --git a/webrtc/modules/audio_processing/aec3/fft_data_avx2.cc b/webrtc/modules/audio_processing/aec3/fft_data_avx2.cc
new file mode 100644
index 0000000..1fe4bd6
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/fft_data_avx2.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/fft_data.h"
+
+#include <immintrin.h>
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+// Computes the power spectrum of the data.
+void FftData::SpectrumAVX2(rtc::ArrayView<float> power_spectrum) const {
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, power_spectrum.size());
+ for (size_t k = 0; k < kFftLengthBy2; k += 8) {
+ __m256 r = _mm256_loadu_ps(&re[k]);
+ __m256 i = _mm256_loadu_ps(&im[k]);
+ __m256 ii = _mm256_mul_ps(i, i);
+ ii = _mm256_fmadd_ps(r, r, ii);
+ _mm256_storeu_ps(&power_spectrum[k], ii);
+ }
+ power_spectrum[kFftLengthBy2] = re[kFftLengthBy2] * re[kFftLengthBy2] +
+ im[kFftLengthBy2] * im[kFftLengthBy2];
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/filter_analyzer.cc b/webrtc/modules/audio_processing/aec3/filter_analyzer.cc
new file mode 100644
index 0000000..be954d3
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/filter_analyzer.cc
@@ -0,0 +1,280 @@
+/*
+ * 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/audio_processing/aec3/filter_analyzer.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <array>
+#include <numeric>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+size_t FindPeakIndex(rtc::ArrayView<const float> filter_time_domain,
+ size_t peak_index_in,
+ size_t start_sample,
+ size_t end_sample) {
+ size_t peak_index_out = peak_index_in;
+ float max_h2 =
+ filter_time_domain[peak_index_out] * filter_time_domain[peak_index_out];
+ for (size_t k = start_sample; k <= end_sample; ++k) {
+ float tmp = filter_time_domain[k] * filter_time_domain[k];
+ if (tmp > max_h2) {
+ peak_index_out = k;
+ max_h2 = tmp;
+ }
+ }
+
+ return peak_index_out;
+}
+
+} // namespace
+
+int FilterAnalyzer::instance_count_ = 0;
+
+FilterAnalyzer::FilterAnalyzer(const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ bounded_erl_(config.ep_strength.bounded_erl),
+ default_gain_(config.ep_strength.default_gain),
+ h_highpass_(num_capture_channels,
+ std::vector<float>(
+ GetTimeDomainLength(config.filter.refined.length_blocks),
+ 0.f)),
+ filter_analysis_states_(num_capture_channels,
+ FilterAnalysisState(config)),
+ filter_delays_blocks_(num_capture_channels, 0) {
+ Reset();
+}
+
+FilterAnalyzer::~FilterAnalyzer() = default;
+
+void FilterAnalyzer::Reset() {
+ blocks_since_reset_ = 0;
+ ResetRegion();
+ for (auto& state : filter_analysis_states_) {
+ state.Reset(default_gain_);
+ }
+ std::fill(filter_delays_blocks_.begin(), filter_delays_blocks_.end(), 0);
+}
+
+void FilterAnalyzer::Update(
+ rtc::ArrayView<const std::vector<float>> filters_time_domain,
+ const RenderBuffer& render_buffer,
+ bool* any_filter_consistent,
+ float* max_echo_path_gain) {
+ RTC_DCHECK(any_filter_consistent);
+ RTC_DCHECK(max_echo_path_gain);
+ RTC_DCHECK_EQ(filters_time_domain.size(), filter_analysis_states_.size());
+ RTC_DCHECK_EQ(filters_time_domain.size(), h_highpass_.size());
+
+ ++blocks_since_reset_;
+ SetRegionToAnalyze(filters_time_domain[0].size());
+ AnalyzeRegion(filters_time_domain, render_buffer);
+
+ // Aggregate the results for all capture channels.
+ auto& st_ch0 = filter_analysis_states_[0];
+ *any_filter_consistent = st_ch0.consistent_estimate;
+ *max_echo_path_gain = st_ch0.gain;
+ min_filter_delay_blocks_ = filter_delays_blocks_[0];
+ for (size_t ch = 1; ch < filters_time_domain.size(); ++ch) {
+ auto& st_ch = filter_analysis_states_[ch];
+ *any_filter_consistent =
+ *any_filter_consistent || st_ch.consistent_estimate;
+ *max_echo_path_gain = std::max(*max_echo_path_gain, st_ch.gain);
+ min_filter_delay_blocks_ =
+ std::min(min_filter_delay_blocks_, filter_delays_blocks_[ch]);
+ }
+}
+
+void FilterAnalyzer::AnalyzeRegion(
+ rtc::ArrayView<const std::vector<float>> filters_time_domain,
+ const RenderBuffer& render_buffer) {
+ // Preprocess the filter to avoid issues with low-frequency components in the
+ // filter.
+ PreProcessFilters(filters_time_domain);
+ data_dumper_->DumpRaw("aec3_linear_filter_processed_td", h_highpass_[0]);
+
+ constexpr float kOneByBlockSize = 1.f / kBlockSize;
+ for (size_t ch = 0; ch < filters_time_domain.size(); ++ch) {
+ RTC_DCHECK_LT(region_.start_sample_, filters_time_domain[ch].size());
+ RTC_DCHECK_LT(region_.end_sample_, filters_time_domain[ch].size());
+
+ auto& st_ch = filter_analysis_states_[ch];
+ RTC_DCHECK_EQ(h_highpass_[ch].size(), filters_time_domain[ch].size());
+ RTC_DCHECK_GT(h_highpass_[ch].size(), 0);
+ st_ch.peak_index = std::min(st_ch.peak_index, h_highpass_[ch].size() - 1);
+
+ st_ch.peak_index =
+ FindPeakIndex(h_highpass_[ch], st_ch.peak_index, region_.start_sample_,
+ region_.end_sample_);
+ filter_delays_blocks_[ch] = st_ch.peak_index >> kBlockSizeLog2;
+ UpdateFilterGain(h_highpass_[ch], &st_ch);
+ st_ch.filter_length_blocks =
+ filters_time_domain[ch].size() * kOneByBlockSize;
+
+ st_ch.consistent_estimate = st_ch.consistent_filter_detector.Detect(
+ h_highpass_[ch], region_,
+ render_buffer.Block(-filter_delays_blocks_[ch])[0], st_ch.peak_index,
+ filter_delays_blocks_[ch]);
+ }
+}
+
+void FilterAnalyzer::UpdateFilterGain(
+ rtc::ArrayView<const float> filter_time_domain,
+ FilterAnalysisState* st) {
+ bool sufficient_time_to_converge =
+ blocks_since_reset_ > 5 * kNumBlocksPerSecond;
+
+ if (sufficient_time_to_converge && st->consistent_estimate) {
+ st->gain = fabsf(filter_time_domain[st->peak_index]);
+ } else {
+ // TODO(peah): Verify whether this check against a float is ok.
+ if (st->gain) {
+ st->gain = std::max(st->gain, fabsf(filter_time_domain[st->peak_index]));
+ }
+ }
+
+ if (bounded_erl_ && st->gain) {
+ st->gain = std::max(st->gain, 0.01f);
+ }
+}
+
+void FilterAnalyzer::PreProcessFilters(
+ rtc::ArrayView<const std::vector<float>> filters_time_domain) {
+ for (size_t ch = 0; ch < filters_time_domain.size(); ++ch) {
+ RTC_DCHECK_LT(region_.start_sample_, filters_time_domain[ch].size());
+ RTC_DCHECK_LT(region_.end_sample_, filters_time_domain[ch].size());
+
+ RTC_DCHECK_GE(h_highpass_[ch].capacity(), filters_time_domain[ch].size());
+ h_highpass_[ch].resize(filters_time_domain[ch].size());
+ // Minimum phase high-pass filter with cutoff frequency at about 600 Hz.
+ constexpr std::array<float, 3> h = {
+ {0.7929742f, -0.36072128f, -0.47047766f}};
+
+ std::fill(h_highpass_[ch].begin() + region_.start_sample_,
+ h_highpass_[ch].begin() + region_.end_sample_ + 1, 0.f);
+ for (size_t k = std::max(h.size() - 1, region_.start_sample_);
+ k <= region_.end_sample_; ++k) {
+ for (size_t j = 0; j < h.size(); ++j) {
+ h_highpass_[ch][k] += filters_time_domain[ch][k - j] * h[j];
+ }
+ }
+ }
+}
+
+void FilterAnalyzer::ResetRegion() {
+ region_.start_sample_ = 0;
+ region_.end_sample_ = 0;
+}
+
+void FilterAnalyzer::SetRegionToAnalyze(size_t filter_size) {
+ constexpr size_t kNumberBlocksToUpdate = 1;
+ auto& r = region_;
+ r.start_sample_ = r.end_sample_ >= filter_size - 1 ? 0 : r.end_sample_ + 1;
+ r.end_sample_ =
+ std::min(r.start_sample_ + kNumberBlocksToUpdate * kBlockSize - 1,
+ filter_size - 1);
+
+ // Check range.
+ RTC_DCHECK_LT(r.start_sample_, filter_size);
+ RTC_DCHECK_LT(r.end_sample_, filter_size);
+ RTC_DCHECK_LE(r.start_sample_, r.end_sample_);
+}
+
+FilterAnalyzer::ConsistentFilterDetector::ConsistentFilterDetector(
+ const EchoCanceller3Config& config)
+ : active_render_threshold_(config.render_levels.active_render_limit *
+ config.render_levels.active_render_limit *
+ kFftLengthBy2) {
+ Reset();
+}
+
+void FilterAnalyzer::ConsistentFilterDetector::Reset() {
+ significant_peak_ = false;
+ filter_floor_accum_ = 0.f;
+ filter_secondary_peak_ = 0.f;
+ filter_floor_low_limit_ = 0;
+ filter_floor_high_limit_ = 0;
+ consistent_estimate_counter_ = 0;
+ consistent_delay_reference_ = -10;
+}
+
+bool FilterAnalyzer::ConsistentFilterDetector::Detect(
+ rtc::ArrayView<const float> filter_to_analyze,
+ const FilterRegion& region,
+ rtc::ArrayView<const std::vector<float>> x_block,
+ size_t peak_index,
+ int delay_blocks) {
+ if (region.start_sample_ == 0) {
+ filter_floor_accum_ = 0.f;
+ filter_secondary_peak_ = 0.f;
+ filter_floor_low_limit_ = peak_index < 64 ? 0 : peak_index - 64;
+ filter_floor_high_limit_ =
+ peak_index > filter_to_analyze.size() - 129 ? 0 : peak_index + 128;
+ }
+
+ for (size_t k = region.start_sample_;
+ k < std::min(region.end_sample_ + 1, filter_floor_low_limit_); ++k) {
+ float abs_h = fabsf(filter_to_analyze[k]);
+ filter_floor_accum_ += abs_h;
+ filter_secondary_peak_ = std::max(filter_secondary_peak_, abs_h);
+ }
+
+ for (size_t k = std::max(filter_floor_high_limit_, region.start_sample_);
+ k <= region.end_sample_; ++k) {
+ float abs_h = fabsf(filter_to_analyze[k]);
+ filter_floor_accum_ += abs_h;
+ filter_secondary_peak_ = std::max(filter_secondary_peak_, abs_h);
+ }
+
+ if (region.end_sample_ == filter_to_analyze.size() - 1) {
+ float filter_floor = filter_floor_accum_ /
+ (filter_floor_low_limit_ + filter_to_analyze.size() -
+ filter_floor_high_limit_);
+
+ float abs_peak = fabsf(filter_to_analyze[peak_index]);
+ significant_peak_ = abs_peak > 10.f * filter_floor &&
+ abs_peak > 2.f * filter_secondary_peak_;
+ }
+
+ if (significant_peak_) {
+ bool active_render_block = false;
+ for (auto& x_channel : x_block) {
+ const float x_energy = std::inner_product(
+ x_channel.begin(), x_channel.end(), x_channel.begin(), 0.f);
+ if (x_energy > active_render_threshold_) {
+ active_render_block = true;
+ break;
+ }
+ }
+
+ if (consistent_delay_reference_ == delay_blocks) {
+ if (active_render_block) {
+ ++consistent_estimate_counter_;
+ }
+ } else {
+ consistent_estimate_counter_ = 0;
+ consistent_delay_reference_ = delay_blocks;
+ }
+ }
+ return consistent_estimate_counter_ > 1.5f * kNumBlocksPerSecond;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/filter_analyzer.h b/webrtc/modules/audio_processing/aec3/filter_analyzer.h
new file mode 100644
index 0000000..b0b7070
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/filter_analyzer.h
@@ -0,0 +1,149 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_FILTER_ANALYZER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_FILTER_ANALYZER_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+class RenderBuffer;
+
+// Class for analyzing the properties of an adaptive filter.
+class FilterAnalyzer {
+ public:
+ FilterAnalyzer(const EchoCanceller3Config& config,
+ size_t num_capture_channels);
+ ~FilterAnalyzer();
+
+ FilterAnalyzer(const FilterAnalyzer&) = delete;
+ FilterAnalyzer& operator=(const FilterAnalyzer&) = delete;
+
+ // Resets the analysis.
+ void Reset();
+
+ // Updates the estimates with new input data.
+ void Update(rtc::ArrayView<const std::vector<float>> filters_time_domain,
+ const RenderBuffer& render_buffer,
+ bool* any_filter_consistent,
+ float* max_echo_path_gain);
+
+ // Returns the delay in blocks for each filter.
+ rtc::ArrayView<const int> FilterDelaysBlocks() const {
+ return filter_delays_blocks_;
+ }
+
+ // Returns the minimum delay of all filters in terms of blocks.
+ int MinFilterDelayBlocks() const { return min_filter_delay_blocks_; }
+
+ // Returns the number of blocks for the current used filter.
+ int FilterLengthBlocks() const {
+ return filter_analysis_states_[0].filter_length_blocks;
+ }
+
+ // Returns the preprocessed filter.
+ rtc::ArrayView<const std::vector<float>> GetAdjustedFilters() const {
+ return h_highpass_;
+ }
+
+ // Public for testing purposes only.
+ void SetRegionToAnalyze(size_t filter_size);
+
+ private:
+ struct FilterAnalysisState;
+
+ void AnalyzeRegion(
+ rtc::ArrayView<const std::vector<float>> filters_time_domain,
+ const RenderBuffer& render_buffer);
+
+ void UpdateFilterGain(rtc::ArrayView<const float> filters_time_domain,
+ FilterAnalysisState* st);
+ void PreProcessFilters(
+ rtc::ArrayView<const std::vector<float>> filters_time_domain);
+
+ void ResetRegion();
+
+ struct FilterRegion {
+ size_t start_sample_;
+ size_t end_sample_;
+ };
+
+ // This class checks whether the shape of the impulse response has been
+ // consistent over time.
+ class ConsistentFilterDetector {
+ public:
+ explicit ConsistentFilterDetector(const EchoCanceller3Config& config);
+ void Reset();
+ bool Detect(rtc::ArrayView<const float> filter_to_analyze,
+ const FilterRegion& region,
+ rtc::ArrayView<const std::vector<float>> x_block,
+ size_t peak_index,
+ int delay_blocks);
+
+ private:
+ bool significant_peak_;
+ float filter_floor_accum_;
+ float filter_secondary_peak_;
+ size_t filter_floor_low_limit_;
+ size_t filter_floor_high_limit_;
+ const float active_render_threshold_;
+ size_t consistent_estimate_counter_ = 0;
+ int consistent_delay_reference_ = -10;
+ };
+
+ struct FilterAnalysisState {
+ explicit FilterAnalysisState(const EchoCanceller3Config& config)
+ : filter_length_blocks(config.filter.refined_initial.length_blocks),
+ consistent_filter_detector(config) {
+ Reset(config.ep_strength.default_gain);
+ }
+
+ void Reset(float default_gain) {
+ peak_index = 0;
+ gain = default_gain;
+ consistent_filter_detector.Reset();
+ }
+
+ float gain;
+ size_t peak_index;
+ int filter_length_blocks;
+ bool consistent_estimate = false;
+ ConsistentFilterDetector consistent_filter_detector;
+ };
+
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const bool bounded_erl_;
+ const float default_gain_;
+ std::vector<std::vector<float>> h_highpass_;
+
+ size_t blocks_since_reset_ = 0;
+ FilterRegion region_;
+
+ std::vector<FilterAnalysisState> filter_analysis_states_;
+ std::vector<int> filter_delays_blocks_;
+
+ int min_filter_delay_blocks_ = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_FILTER_ANALYZER_H_
diff --git a/webrtc/modules/audio_processing/aec3/frame_blocker.cc b/webrtc/modules/audio_processing/aec3/frame_blocker.cc
new file mode 100644
index 0000000..63aaf09
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/frame_blocker.cc
@@ -0,0 +1,88 @@
+/*
+ * 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/audio_processing/aec3/frame_blocker.h"
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+FrameBlocker::FrameBlocker(size_t num_bands, size_t num_channels)
+ : num_bands_(num_bands),
+ num_channels_(num_channels),
+ buffer_(num_bands_, std::vector<std::vector<float>>(num_channels)) {
+ RTC_DCHECK_LT(0, num_bands);
+ RTC_DCHECK_LT(0, num_channels);
+ for (auto& band : buffer_) {
+ for (auto& channel : band) {
+ channel.reserve(kBlockSize);
+ RTC_DCHECK(channel.empty());
+ }
+ }
+}
+
+FrameBlocker::~FrameBlocker() = default;
+
+void FrameBlocker::InsertSubFrameAndExtractBlock(
+ const std::vector<std::vector<rtc::ArrayView<float>>>& sub_frame,
+ std::vector<std::vector<std::vector<float>>>* block) {
+ RTC_DCHECK(block);
+ RTC_DCHECK_EQ(num_bands_, block->size());
+ RTC_DCHECK_EQ(num_bands_, sub_frame.size());
+ for (size_t band = 0; band < num_bands_; ++band) {
+ RTC_DCHECK_EQ(num_channels_, (*block)[band].size());
+ RTC_DCHECK_EQ(num_channels_, sub_frame[band].size());
+ for (size_t channel = 0; channel < num_channels_; ++channel) {
+ RTC_DCHECK_GE(kBlockSize - 16, buffer_[band][channel].size());
+ RTC_DCHECK_EQ(kBlockSize, (*block)[band][channel].size());
+ RTC_DCHECK_EQ(kSubFrameLength, sub_frame[band][channel].size());
+ const int samples_to_block = kBlockSize - buffer_[band][channel].size();
+ (*block)[band][channel].clear();
+ (*block)[band][channel].insert((*block)[band][channel].begin(),
+ buffer_[band][channel].begin(),
+ buffer_[band][channel].end());
+ (*block)[band][channel].insert(
+ (*block)[band][channel].begin() + buffer_[band][channel].size(),
+ sub_frame[band][channel].begin(),
+ sub_frame[band][channel].begin() + samples_to_block);
+ buffer_[band][channel].clear();
+ buffer_[band][channel].insert(
+ buffer_[band][channel].begin(),
+ sub_frame[band][channel].begin() + samples_to_block,
+ sub_frame[band][channel].end());
+ }
+ }
+}
+
+bool FrameBlocker::IsBlockAvailable() const {
+ return kBlockSize == buffer_[0][0].size();
+}
+
+void FrameBlocker::ExtractBlock(
+ std::vector<std::vector<std::vector<float>>>* block) {
+ RTC_DCHECK(block);
+ RTC_DCHECK_EQ(num_bands_, block->size());
+ RTC_DCHECK(IsBlockAvailable());
+ for (size_t band = 0; band < num_bands_; ++band) {
+ RTC_DCHECK_EQ(num_channels_, (*block)[band].size());
+ for (size_t channel = 0; channel < num_channels_; ++channel) {
+ RTC_DCHECK_EQ(kBlockSize, buffer_[band][channel].size());
+ RTC_DCHECK_EQ(kBlockSize, (*block)[band][channel].size());
+ (*block)[band][channel].clear();
+ (*block)[band][channel].insert((*block)[band][channel].begin(),
+ buffer_[band][channel].begin(),
+ buffer_[band][channel].end());
+ buffer_[band][channel].clear();
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/frame_blocker.h b/webrtc/modules/audio_processing/aec3/frame_blocker.h
new file mode 100644
index 0000000..ebd6f77
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/frame_blocker.h
@@ -0,0 +1,50 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_FRAME_BLOCKER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_FRAME_BLOCKER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// Class for producing 64 sample multiband blocks from frames consisting of 2
+// subframes of 80 samples.
+class FrameBlocker {
+ public:
+ FrameBlocker(size_t num_bands, size_t num_channels);
+ ~FrameBlocker();
+ FrameBlocker(const FrameBlocker&) = delete;
+ FrameBlocker& operator=(const FrameBlocker&) = delete;
+
+ // Inserts one 80 sample multiband subframe from the multiband frame and
+ // extracts one 64 sample multiband block.
+ void InsertSubFrameAndExtractBlock(
+ const std::vector<std::vector<rtc::ArrayView<float>>>& sub_frame,
+ std::vector<std::vector<std::vector<float>>>* block);
+ // Reports whether a multiband block of 64 samples is available for
+ // extraction.
+ bool IsBlockAvailable() const;
+ // Extracts a multiband block of 64 samples.
+ void ExtractBlock(std::vector<std::vector<std::vector<float>>>* block);
+
+ private:
+ const size_t num_bands_;
+ const size_t num_channels_;
+ std::vector<std::vector<std::vector<float>>> buffer_;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_FRAME_BLOCKER_H_
diff --git a/webrtc/modules/audio_processing/aec3/fullband_erle_estimator.cc b/webrtc/modules/audio_processing/aec3/fullband_erle_estimator.cc
new file mode 100644
index 0000000..e421214
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/fullband_erle_estimator.cc
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/fullband_erle_estimator.h"
+
+#include <algorithm>
+#include <memory>
+#include <numeric>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+
+namespace {
+constexpr float kEpsilon = 1e-3f;
+constexpr float kX2BandEnergyThreshold = 44015068.0f;
+constexpr int kBlocksToHoldErle = 100;
+constexpr int kPointsToAccumulate = 6;
+} // namespace
+
+FullBandErleEstimator::FullBandErleEstimator(
+ const EchoCanceller3Config::Erle& config,
+ size_t num_capture_channels)
+ : min_erle_log2_(FastApproxLog2f(config.min + kEpsilon)),
+ max_erle_lf_log2(FastApproxLog2f(config.max_l + kEpsilon)),
+ hold_counters_time_domain_(num_capture_channels, 0),
+ erle_time_domain_log2_(num_capture_channels, min_erle_log2_),
+ instantaneous_erle_(num_capture_channels, ErleInstantaneous(config)),
+ linear_filters_qualities_(num_capture_channels) {
+ Reset();
+}
+
+FullBandErleEstimator::~FullBandErleEstimator() = default;
+
+void FullBandErleEstimator::Reset() {
+ for (auto& instantaneous_erle_ch : instantaneous_erle_) {
+ instantaneous_erle_ch.Reset();
+ }
+
+ UpdateQualityEstimates();
+ std::fill(erle_time_domain_log2_.begin(), erle_time_domain_log2_.end(),
+ min_erle_log2_);
+ std::fill(hold_counters_time_domain_.begin(),
+ hold_counters_time_domain_.end(), 0);
+}
+
+void FullBandErleEstimator::Update(
+ rtc::ArrayView<const float> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ const std::vector<bool>& converged_filters) {
+ for (size_t ch = 0; ch < Y2.size(); ++ch) {
+ if (converged_filters[ch]) {
+ // Computes the fullband ERLE.
+ const float X2_sum = std::accumulate(X2.begin(), X2.end(), 0.0f);
+ if (X2_sum > kX2BandEnergyThreshold * X2.size()) {
+ const float Y2_sum =
+ std::accumulate(Y2[ch].begin(), Y2[ch].end(), 0.0f);
+ const float E2_sum =
+ std::accumulate(E2[ch].begin(), E2[ch].end(), 0.0f);
+ if (instantaneous_erle_[ch].Update(Y2_sum, E2_sum)) {
+ hold_counters_time_domain_[ch] = kBlocksToHoldErle;
+ erle_time_domain_log2_[ch] +=
+ 0.1f * ((instantaneous_erle_[ch].GetInstErleLog2().value()) -
+ erle_time_domain_log2_[ch]);
+ erle_time_domain_log2_[ch] = rtc::SafeClamp(
+ erle_time_domain_log2_[ch], min_erle_log2_, max_erle_lf_log2);
+ }
+ }
+ }
+ --hold_counters_time_domain_[ch];
+ if (hold_counters_time_domain_[ch] <= 0) {
+ erle_time_domain_log2_[ch] =
+ std::max(min_erle_log2_, erle_time_domain_log2_[ch] - 0.044f);
+ }
+ if (hold_counters_time_domain_[ch] == 0) {
+ instantaneous_erle_[ch].ResetAccumulators();
+ }
+ }
+
+ UpdateQualityEstimates();
+}
+
+void FullBandErleEstimator::Dump(
+ const std::unique_ptr<ApmDataDumper>& data_dumper) const {
+ data_dumper->DumpRaw("aec3_fullband_erle_log2", FullbandErleLog2());
+ instantaneous_erle_[0].Dump(data_dumper);
+}
+
+void FullBandErleEstimator::UpdateQualityEstimates() {
+ for (size_t ch = 0; ch < instantaneous_erle_.size(); ++ch) {
+ linear_filters_qualities_[ch] =
+ instantaneous_erle_[ch].GetQualityEstimate();
+ }
+}
+
+FullBandErleEstimator::ErleInstantaneous::ErleInstantaneous(
+ const EchoCanceller3Config::Erle& config)
+ : clamp_inst_quality_to_zero_(config.clamp_quality_estimate_to_zero),
+ clamp_inst_quality_to_one_(config.clamp_quality_estimate_to_one) {
+ Reset();
+}
+
+FullBandErleEstimator::ErleInstantaneous::~ErleInstantaneous() = default;
+
+bool FullBandErleEstimator::ErleInstantaneous::Update(const float Y2_sum,
+ const float E2_sum) {
+ bool update_estimates = false;
+ E2_acum_ += E2_sum;
+ Y2_acum_ += Y2_sum;
+ num_points_++;
+ if (num_points_ == kPointsToAccumulate) {
+ if (E2_acum_ > 0.f) {
+ update_estimates = true;
+ erle_log2_ = FastApproxLog2f(Y2_acum_ / E2_acum_ + kEpsilon);
+ }
+ num_points_ = 0;
+ E2_acum_ = 0.f;
+ Y2_acum_ = 0.f;
+ }
+
+ if (update_estimates) {
+ UpdateMaxMin();
+ UpdateQualityEstimate();
+ }
+ return update_estimates;
+}
+
+void FullBandErleEstimator::ErleInstantaneous::Reset() {
+ ResetAccumulators();
+ max_erle_log2_ = -10.f; // -30 dB.
+ min_erle_log2_ = 33.f; // 100 dB.
+ inst_quality_estimate_ = 0.f;
+}
+
+void FullBandErleEstimator::ErleInstantaneous::ResetAccumulators() {
+ erle_log2_ = absl::nullopt;
+ inst_quality_estimate_ = 0.f;
+ num_points_ = 0;
+ E2_acum_ = 0.f;
+ Y2_acum_ = 0.f;
+}
+
+void FullBandErleEstimator::ErleInstantaneous::Dump(
+ const std::unique_ptr<ApmDataDumper>& data_dumper) const {
+ data_dumper->DumpRaw("aec3_fullband_erle_inst_log2",
+ erle_log2_ ? *erle_log2_ : -10.f);
+ data_dumper->DumpRaw(
+ "aec3_erle_instantaneous_quality",
+ GetQualityEstimate() ? GetQualityEstimate().value() : 0.f);
+ data_dumper->DumpRaw("aec3_fullband_erle_max_log2", max_erle_log2_);
+ data_dumper->DumpRaw("aec3_fullband_erle_min_log2", min_erle_log2_);
+}
+
+void FullBandErleEstimator::ErleInstantaneous::UpdateMaxMin() {
+ RTC_DCHECK(erle_log2_);
+ if (erle_log2_.value() > max_erle_log2_) {
+ max_erle_log2_ = erle_log2_.value();
+ } else {
+ max_erle_log2_ -= 0.0004; // Forget factor, approx 1dB every 3 sec.
+ }
+
+ if (erle_log2_.value() < min_erle_log2_) {
+ min_erle_log2_ = erle_log2_.value();
+ } else {
+ min_erle_log2_ += 0.0004; // Forget factor, approx 1dB every 3 sec.
+ }
+}
+
+void FullBandErleEstimator::ErleInstantaneous::UpdateQualityEstimate() {
+ const float alpha = 0.07f;
+ float quality_estimate = 0.f;
+ RTC_DCHECK(erle_log2_);
+ // TODO(peah): Currently, the estimate can become be less than 0; this should
+ // be corrected.
+ if (max_erle_log2_ > min_erle_log2_) {
+ quality_estimate = (erle_log2_.value() - min_erle_log2_) /
+ (max_erle_log2_ - min_erle_log2_);
+ }
+ if (quality_estimate > inst_quality_estimate_) {
+ inst_quality_estimate_ = quality_estimate;
+ } else {
+ inst_quality_estimate_ +=
+ alpha * (quality_estimate - inst_quality_estimate_);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/fullband_erle_estimator.h b/webrtc/modules/audio_processing/aec3/fullband_erle_estimator.h
new file mode 100644
index 0000000..1580f1a
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/fullband_erle_estimator.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_FULLBAND_ERLE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_FULLBAND_ERLE_ESTIMATOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+
+namespace webrtc {
+
+// Estimates the echo return loss enhancement using the energy of all the
+// freuquency bands.
+class FullBandErleEstimator {
+ public:
+ FullBandErleEstimator(const EchoCanceller3Config::Erle& config,
+ size_t num_capture_channels);
+ ~FullBandErleEstimator();
+ // Resets the ERLE estimator.
+ void Reset();
+
+ // Updates the ERLE estimator.
+ void Update(rtc::ArrayView<const float> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ const std::vector<bool>& converged_filters);
+
+ // Returns the fullband ERLE estimates in log2 units.
+ float FullbandErleLog2() const {
+ float min_erle = erle_time_domain_log2_[0];
+ for (size_t ch = 1; ch < erle_time_domain_log2_.size(); ++ch) {
+ min_erle = std::min(min_erle, erle_time_domain_log2_[ch]);
+ }
+ return min_erle;
+ }
+
+ // Returns an estimation of the current linear filter quality. It returns a
+ // float number between 0 and 1 mapping 1 to the highest possible quality.
+ rtc::ArrayView<const absl::optional<float>> GetInstLinearQualityEstimates()
+ const {
+ return linear_filters_qualities_;
+ }
+
+ void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper) const;
+
+ private:
+ void UpdateQualityEstimates();
+
+ class ErleInstantaneous {
+ public:
+ explicit ErleInstantaneous(const EchoCanceller3Config::Erle& config);
+ ~ErleInstantaneous();
+
+ // Updates the estimator with a new point, returns true
+ // if the instantaneous ERLE was updated due to having enough
+ // points for performing the estimate.
+ bool Update(const float Y2_sum, const float E2_sum);
+ // Resets the instantaneous ERLE estimator to its initial state.
+ void Reset();
+ // Resets the members related with an instantaneous estimate.
+ void ResetAccumulators();
+ // Returns the instantaneous ERLE in log2 units.
+ absl::optional<float> GetInstErleLog2() const { return erle_log2_; }
+ // Gets an indication between 0 and 1 of the performance of the linear
+ // filter for the current time instant.
+ absl::optional<float> GetQualityEstimate() const {
+ if (erle_log2_) {
+ float value = inst_quality_estimate_;
+ if (clamp_inst_quality_to_zero_) {
+ value = std::max(0.f, value);
+ }
+ if (clamp_inst_quality_to_one_) {
+ value = std::min(1.f, value);
+ }
+ return absl::optional<float>(value);
+ }
+ return absl::nullopt;
+ }
+ void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper) const;
+
+ private:
+ void UpdateMaxMin();
+ void UpdateQualityEstimate();
+ const bool clamp_inst_quality_to_zero_;
+ const bool clamp_inst_quality_to_one_;
+ absl::optional<float> erle_log2_;
+ float inst_quality_estimate_;
+ float max_erle_log2_;
+ float min_erle_log2_;
+ float Y2_acum_;
+ float E2_acum_;
+ int num_points_;
+ };
+
+ const float min_erle_log2_;
+ const float max_erle_lf_log2;
+ std::vector<int> hold_counters_time_domain_;
+ std::vector<float> erle_time_domain_log2_;
+ std::vector<ErleInstantaneous> instantaneous_erle_;
+ std::vector<absl::optional<float>> linear_filters_qualities_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_FULLBAND_ERLE_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/matched_filter.cc b/webrtc/modules/audio_processing/aec3/matched_filter.cc
new file mode 100644
index 0000000..64b2d4e
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/matched_filter.cc
@@ -0,0 +1,464 @@
+/*
+ * 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/audio_processing/aec3/matched_filter.h"
+
+// Defines WEBRTC_ARCH_X86_FAMILY, used below.
+#include "rtc_base/system/arch.h"
+
+#if defined(WEBRTC_HAS_NEON)
+#include <arm_neon.h>
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#include <emmintrin.h>
+#endif
+#include <algorithm>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <numeric>
+
+#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace aec3 {
+
+#if defined(WEBRTC_HAS_NEON)
+
+void MatchedFilterCore_NEON(size_t x_start_index,
+ float x2_sum_threshold,
+ float smoothing,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> h,
+ bool* filters_updated,
+ float* error_sum) {
+ const int h_size = static_cast<int>(h.size());
+ const int x_size = static_cast<int>(x.size());
+ RTC_DCHECK_EQ(0, h_size % 4);
+
+ // Process for all samples in the sub-block.
+ for (size_t i = 0; i < y.size(); ++i) {
+ // Apply the matched filter as filter * x, and compute x * x.
+
+ RTC_DCHECK_GT(x_size, x_start_index);
+ const float* x_p = &x[x_start_index];
+ const float* h_p = &h[0];
+
+ // Initialize values for the accumulation.
+ float32x4_t s_128 = vdupq_n_f32(0);
+ float32x4_t x2_sum_128 = vdupq_n_f32(0);
+ float x2_sum = 0.f;
+ float s = 0;
+
+ // Compute loop chunk sizes until, and after, the wraparound of the circular
+ // buffer for x.
+ const int chunk1 =
+ std::min(h_size, static_cast<int>(x_size - x_start_index));
+
+ // Perform the loop in two chunks.
+ const int chunk2 = h_size - chunk1;
+ for (int limit : {chunk1, chunk2}) {
+ // Perform 128 bit vector operations.
+ const int limit_by_4 = limit >> 2;
+ for (int k = limit_by_4; k > 0; --k, h_p += 4, x_p += 4) {
+ // Load the data into 128 bit vectors.
+ const float32x4_t x_k = vld1q_f32(x_p);
+ const float32x4_t h_k = vld1q_f32(h_p);
+ // Compute and accumulate x * x and h * x.
+ x2_sum_128 = vmlaq_f32(x2_sum_128, x_k, x_k);
+ s_128 = vmlaq_f32(s_128, h_k, x_k);
+ }
+
+ // Perform non-vector operations for any remaining items.
+ for (int k = limit - limit_by_4 * 4; k > 0; --k, ++h_p, ++x_p) {
+ const float x_k = *x_p;
+ x2_sum += x_k * x_k;
+ s += *h_p * x_k;
+ }
+
+ x_p = &x[0];
+ }
+
+ // Combine the accumulated vector and scalar values.
+ float* v = reinterpret_cast<float*>(&x2_sum_128);
+ x2_sum += v[0] + v[1] + v[2] + v[3];
+ v = reinterpret_cast<float*>(&s_128);
+ s += v[0] + v[1] + v[2] + v[3];
+
+ // Compute the matched filter error.
+ float e = y[i] - s;
+ const bool saturation = y[i] >= 32000.f || y[i] <= -32000.f;
+ (*error_sum) += e * e;
+
+ // Update the matched filter estimate in an NLMS manner.
+ if (x2_sum > x2_sum_threshold && !saturation) {
+ RTC_DCHECK_LT(0.f, x2_sum);
+ const float alpha = smoothing * e / x2_sum;
+ const float32x4_t alpha_128 = vmovq_n_f32(alpha);
+
+ // filter = filter + smoothing * (y - filter * x) * x / x * x.
+ float* h_p = &h[0];
+ x_p = &x[x_start_index];
+
+ // Perform the loop in two chunks.
+ for (int limit : {chunk1, chunk2}) {
+ // Perform 128 bit vector operations.
+ const int limit_by_4 = limit >> 2;
+ for (int k = limit_by_4; k > 0; --k, h_p += 4, x_p += 4) {
+ // Load the data into 128 bit vectors.
+ float32x4_t h_k = vld1q_f32(h_p);
+ const float32x4_t x_k = vld1q_f32(x_p);
+ // Compute h = h + alpha * x.
+ h_k = vmlaq_f32(h_k, alpha_128, x_k);
+
+ // Store the result.
+ vst1q_f32(h_p, h_k);
+ }
+
+ // Perform non-vector operations for any remaining items.
+ for (int k = limit - limit_by_4 * 4; k > 0; --k, ++h_p, ++x_p) {
+ *h_p += alpha * *x_p;
+ }
+
+ x_p = &x[0];
+ }
+
+ *filters_updated = true;
+ }
+
+ x_start_index = x_start_index > 0 ? x_start_index - 1 : x_size - 1;
+ }
+}
+
+#endif
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+
+void MatchedFilterCore_SSE2(size_t x_start_index,
+ float x2_sum_threshold,
+ float smoothing,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> h,
+ bool* filters_updated,
+ float* error_sum) {
+ const int h_size = static_cast<int>(h.size());
+ const int x_size = static_cast<int>(x.size());
+ RTC_DCHECK_EQ(0, h_size % 4);
+
+ // Process for all samples in the sub-block.
+ for (size_t i = 0; i < y.size(); ++i) {
+ // Apply the matched filter as filter * x, and compute x * x.
+
+ RTC_DCHECK_GT(x_size, x_start_index);
+ const float* x_p = &x[x_start_index];
+ const float* h_p = &h[0];
+
+ // Initialize values for the accumulation.
+ __m128 s_128 = _mm_set1_ps(0);
+ __m128 x2_sum_128 = _mm_set1_ps(0);
+ float x2_sum = 0.f;
+ float s = 0;
+
+ // Compute loop chunk sizes until, and after, the wraparound of the circular
+ // buffer for x.
+ const int chunk1 =
+ std::min(h_size, static_cast<int>(x_size - x_start_index));
+
+ // Perform the loop in two chunks.
+ const int chunk2 = h_size - chunk1;
+ for (int limit : {chunk1, chunk2}) {
+ // Perform 128 bit vector operations.
+ const int limit_by_4 = limit >> 2;
+ for (int k = limit_by_4; k > 0; --k, h_p += 4, x_p += 4) {
+ // Load the data into 128 bit vectors.
+ const __m128 x_k = _mm_loadu_ps(x_p);
+ const __m128 h_k = _mm_loadu_ps(h_p);
+ const __m128 xx = _mm_mul_ps(x_k, x_k);
+ // Compute and accumulate x * x and h * x.
+ x2_sum_128 = _mm_add_ps(x2_sum_128, xx);
+ const __m128 hx = _mm_mul_ps(h_k, x_k);
+ s_128 = _mm_add_ps(s_128, hx);
+ }
+
+ // Perform non-vector operations for any remaining items.
+ for (int k = limit - limit_by_4 * 4; k > 0; --k, ++h_p, ++x_p) {
+ const float x_k = *x_p;
+ x2_sum += x_k * x_k;
+ s += *h_p * x_k;
+ }
+
+ x_p = &x[0];
+ }
+
+ // Combine the accumulated vector and scalar values.
+ float* v = reinterpret_cast<float*>(&x2_sum_128);
+ x2_sum += v[0] + v[1] + v[2] + v[3];
+ v = reinterpret_cast<float*>(&s_128);
+ s += v[0] + v[1] + v[2] + v[3];
+
+ // Compute the matched filter error.
+ float e = y[i] - s;
+ const bool saturation = y[i] >= 32000.f || y[i] <= -32000.f;
+ (*error_sum) += e * e;
+
+ // Update the matched filter estimate in an NLMS manner.
+ if (x2_sum > x2_sum_threshold && !saturation) {
+ RTC_DCHECK_LT(0.f, x2_sum);
+ const float alpha = smoothing * e / x2_sum;
+ const __m128 alpha_128 = _mm_set1_ps(alpha);
+
+ // filter = filter + smoothing * (y - filter * x) * x / x * x.
+ float* h_p = &h[0];
+ x_p = &x[x_start_index];
+
+ // Perform the loop in two chunks.
+ for (int limit : {chunk1, chunk2}) {
+ // Perform 128 bit vector operations.
+ const int limit_by_4 = limit >> 2;
+ for (int k = limit_by_4; k > 0; --k, h_p += 4, x_p += 4) {
+ // Load the data into 128 bit vectors.
+ __m128 h_k = _mm_loadu_ps(h_p);
+ const __m128 x_k = _mm_loadu_ps(x_p);
+
+ // Compute h = h + alpha * x.
+ const __m128 alpha_x = _mm_mul_ps(alpha_128, x_k);
+ h_k = _mm_add_ps(h_k, alpha_x);
+
+ // Store the result.
+ _mm_storeu_ps(h_p, h_k);
+ }
+
+ // Perform non-vector operations for any remaining items.
+ for (int k = limit - limit_by_4 * 4; k > 0; --k, ++h_p, ++x_p) {
+ *h_p += alpha * *x_p;
+ }
+
+ x_p = &x[0];
+ }
+
+ *filters_updated = true;
+ }
+
+ x_start_index = x_start_index > 0 ? x_start_index - 1 : x_size - 1;
+ }
+}
+#endif
+
+void MatchedFilterCore(size_t x_start_index,
+ float x2_sum_threshold,
+ float smoothing,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> h,
+ bool* filters_updated,
+ float* error_sum) {
+ // Process for all samples in the sub-block.
+ for (size_t i = 0; i < y.size(); ++i) {
+ // Apply the matched filter as filter * x, and compute x * x.
+ float x2_sum = 0.f;
+ float s = 0;
+ size_t x_index = x_start_index;
+ for (size_t k = 0; k < h.size(); ++k) {
+ x2_sum += x[x_index] * x[x_index];
+ s += h[k] * x[x_index];
+ x_index = x_index < (x.size() - 1) ? x_index + 1 : 0;
+ }
+
+ // Compute the matched filter error.
+ float e = y[i] - s;
+ const bool saturation = y[i] >= 32000.f || y[i] <= -32000.f;
+ (*error_sum) += e * e;
+
+ // Update the matched filter estimate in an NLMS manner.
+ if (x2_sum > x2_sum_threshold && !saturation) {
+ RTC_DCHECK_LT(0.f, x2_sum);
+ const float alpha = smoothing * e / x2_sum;
+
+ // filter = filter + smoothing * (y - filter * x) * x / x * x.
+ size_t x_index = x_start_index;
+ for (size_t k = 0; k < h.size(); ++k) {
+ h[k] += alpha * x[x_index];
+ x_index = x_index < (x.size() - 1) ? x_index + 1 : 0;
+ }
+ *filters_updated = true;
+ }
+
+ x_start_index = x_start_index > 0 ? x_start_index - 1 : x.size() - 1;
+ }
+}
+
+} // namespace aec3
+
+MatchedFilter::MatchedFilter(ApmDataDumper* data_dumper,
+ Aec3Optimization optimization,
+ size_t sub_block_size,
+ size_t window_size_sub_blocks,
+ int num_matched_filters,
+ size_t alignment_shift_sub_blocks,
+ float excitation_limit,
+ float smoothing,
+ float matching_filter_threshold)
+ : data_dumper_(data_dumper),
+ optimization_(optimization),
+ sub_block_size_(sub_block_size),
+ filter_intra_lag_shift_(alignment_shift_sub_blocks * sub_block_size_),
+ filters_(
+ num_matched_filters,
+ std::vector<float>(window_size_sub_blocks * sub_block_size_, 0.f)),
+ lag_estimates_(num_matched_filters),
+ filters_offsets_(num_matched_filters, 0),
+ excitation_limit_(excitation_limit),
+ smoothing_(smoothing),
+ matching_filter_threshold_(matching_filter_threshold) {
+ RTC_DCHECK(data_dumper);
+ RTC_DCHECK_LT(0, window_size_sub_blocks);
+ RTC_DCHECK((kBlockSize % sub_block_size) == 0);
+ RTC_DCHECK((sub_block_size % 4) == 0);
+}
+
+MatchedFilter::~MatchedFilter() = default;
+
+void MatchedFilter::Reset() {
+ for (auto& f : filters_) {
+ std::fill(f.begin(), f.end(), 0.f);
+ }
+
+ for (auto& l : lag_estimates_) {
+ l = MatchedFilter::LagEstimate();
+ }
+}
+
+void MatchedFilter::Update(const DownsampledRenderBuffer& render_buffer,
+ rtc::ArrayView<const float> capture) {
+ RTC_DCHECK_EQ(sub_block_size_, capture.size());
+ auto& y = capture;
+
+ const float x2_sum_threshold =
+ filters_[0].size() * excitation_limit_ * excitation_limit_;
+
+ // Apply all matched filters.
+ size_t alignment_shift = 0;
+ for (size_t n = 0; n < filters_.size(); ++n) {
+ float error_sum = 0.f;
+ bool filters_updated = false;
+
+ size_t x_start_index =
+ (render_buffer.read + alignment_shift + sub_block_size_ - 1) %
+ render_buffer.buffer.size();
+
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2:
+ aec3::MatchedFilterCore_SSE2(x_start_index, x2_sum_threshold,
+ smoothing_, render_buffer.buffer, y,
+ filters_[n], &filters_updated, &error_sum);
+ break;
+ case Aec3Optimization::kAvx2:
+ aec3::MatchedFilterCore_AVX2(x_start_index, x2_sum_threshold,
+ smoothing_, render_buffer.buffer, y,
+ filters_[n], &filters_updated, &error_sum);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Aec3Optimization::kNeon:
+ aec3::MatchedFilterCore_NEON(x_start_index, x2_sum_threshold,
+ smoothing_, render_buffer.buffer, y,
+ filters_[n], &filters_updated, &error_sum);
+ break;
+#endif
+ default:
+ aec3::MatchedFilterCore(x_start_index, x2_sum_threshold, smoothing_,
+ render_buffer.buffer, y, filters_[n],
+ &filters_updated, &error_sum);
+ }
+
+ // Compute anchor for the matched filter error.
+ const float error_sum_anchor =
+ std::inner_product(y.begin(), y.end(), y.begin(), 0.f);
+
+ // Estimate the lag in the matched filter as the distance to the portion in
+ // the filter that contributes the most to the matched filter output. This
+ // is detected as the peak of the matched filter.
+ const size_t lag_estimate = std::distance(
+ filters_[n].begin(),
+ std::max_element(
+ filters_[n].begin(), filters_[n].end(),
+ [](float a, float b) -> bool { return a * a < b * b; }));
+
+ // Update the lag estimates for the matched filter.
+ lag_estimates_[n] = LagEstimate(
+ error_sum_anchor - error_sum,
+ (lag_estimate > 2 && lag_estimate < (filters_[n].size() - 10) &&
+ error_sum < matching_filter_threshold_ * error_sum_anchor),
+ lag_estimate + alignment_shift, filters_updated);
+
+ RTC_DCHECK_GE(10, filters_.size());
+ switch (n) {
+ case 0:
+ data_dumper_->DumpRaw("aec3_correlator_0_h", filters_[0]);
+ break;
+ case 1:
+ data_dumper_->DumpRaw("aec3_correlator_1_h", filters_[1]);
+ break;
+ case 2:
+ data_dumper_->DumpRaw("aec3_correlator_2_h", filters_[2]);
+ break;
+ case 3:
+ data_dumper_->DumpRaw("aec3_correlator_3_h", filters_[3]);
+ break;
+ case 4:
+ data_dumper_->DumpRaw("aec3_correlator_4_h", filters_[4]);
+ break;
+ case 5:
+ data_dumper_->DumpRaw("aec3_correlator_5_h", filters_[5]);
+ break;
+ case 6:
+ data_dumper_->DumpRaw("aec3_correlator_6_h", filters_[6]);
+ break;
+ case 7:
+ data_dumper_->DumpRaw("aec3_correlator_7_h", filters_[7]);
+ break;
+ case 8:
+ data_dumper_->DumpRaw("aec3_correlator_8_h", filters_[8]);
+ break;
+ case 9:
+ data_dumper_->DumpRaw("aec3_correlator_9_h", filters_[9]);
+ break;
+ default:
+ RTC_NOTREACHED();
+ }
+
+ alignment_shift += filter_intra_lag_shift_;
+ }
+}
+
+void MatchedFilter::LogFilterProperties(int sample_rate_hz,
+ size_t shift,
+ size_t downsampling_factor) const {
+ size_t alignment_shift = 0;
+ constexpr int kFsBy1000 = 16;
+ for (size_t k = 0; k < filters_.size(); ++k) {
+ int start = static_cast<int>(alignment_shift * downsampling_factor);
+ int end = static_cast<int>((alignment_shift + filters_[k].size()) *
+ downsampling_factor);
+ RTC_LOG(LS_VERBOSE) << "Filter " << k << ": start: "
+ << (start - static_cast<int>(shift)) / kFsBy1000
+ << " ms, end: "
+ << (end - static_cast<int>(shift)) / kFsBy1000
+ << " ms.";
+ alignment_shift += filter_intra_lag_shift_;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/matched_filter.h b/webrtc/modules/audio_processing/aec3/matched_filter.h
new file mode 100644
index 0000000..fa44eb2
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/matched_filter.h
@@ -0,0 +1,149 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+struct DownsampledRenderBuffer;
+
+namespace aec3 {
+
+#if defined(WEBRTC_HAS_NEON)
+
+// Filter core for the matched filter that is optimized for NEON.
+void MatchedFilterCore_NEON(size_t x_start_index,
+ float x2_sum_threshold,
+ float smoothing,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> h,
+ bool* filters_updated,
+ float* error_sum);
+
+#endif
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+
+// Filter core for the matched filter that is optimized for SSE2.
+void MatchedFilterCore_SSE2(size_t x_start_index,
+ float x2_sum_threshold,
+ float smoothing,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> h,
+ bool* filters_updated,
+ float* error_sum);
+
+// Filter core for the matched filter that is optimized for AVX2.
+void MatchedFilterCore_AVX2(size_t x_start_index,
+ float x2_sum_threshold,
+ float smoothing,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> h,
+ bool* filters_updated,
+ float* error_sum);
+
+#endif
+
+// Filter core for the matched filter.
+void MatchedFilterCore(size_t x_start_index,
+ float x2_sum_threshold,
+ float smoothing,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> h,
+ bool* filters_updated,
+ float* error_sum);
+
+} // namespace aec3
+
+// Produces recursively updated cross-correlation estimates for several signal
+// shifts where the intra-shift spacing is uniform.
+class MatchedFilter {
+ public:
+ // Stores properties for the lag estimate corresponding to a particular signal
+ // shift.
+ struct LagEstimate {
+ LagEstimate() = default;
+ LagEstimate(float accuracy, bool reliable, size_t lag, bool updated)
+ : accuracy(accuracy), reliable(reliable), lag(lag), updated(updated) {}
+
+ float accuracy = 0.f;
+ bool reliable = false;
+ size_t lag = 0;
+ bool updated = false;
+ };
+
+ MatchedFilter(ApmDataDumper* data_dumper,
+ Aec3Optimization optimization,
+ size_t sub_block_size,
+ size_t window_size_sub_blocks,
+ int num_matched_filters,
+ size_t alignment_shift_sub_blocks,
+ float excitation_limit,
+ float smoothing,
+ float matching_filter_threshold);
+
+ MatchedFilter() = delete;
+ MatchedFilter(const MatchedFilter&) = delete;
+ MatchedFilter& operator=(const MatchedFilter&) = delete;
+
+ ~MatchedFilter();
+
+ // Updates the correlation with the values in the capture buffer.
+ void Update(const DownsampledRenderBuffer& render_buffer,
+ rtc::ArrayView<const float> capture);
+
+ // Resets the matched filter.
+ void Reset();
+
+ // Returns the current lag estimates.
+ rtc::ArrayView<const MatchedFilter::LagEstimate> GetLagEstimates() const {
+ return lag_estimates_;
+ }
+
+ // Returns the maximum filter lag.
+ size_t GetMaxFilterLag() const {
+ return filters_.size() * filter_intra_lag_shift_ + filters_[0].size();
+ }
+
+ // Log matched filter properties.
+ void LogFilterProperties(int sample_rate_hz,
+ size_t shift,
+ size_t downsampling_factor) const;
+
+ private:
+ ApmDataDumper* const data_dumper_;
+ const Aec3Optimization optimization_;
+ const size_t sub_block_size_;
+ const size_t filter_intra_lag_shift_;
+ std::vector<std::vector<float>> filters_;
+ std::vector<LagEstimate> lag_estimates_;
+ std::vector<size_t> filters_offsets_;
+ const float excitation_limit_;
+ const float smoothing_;
+ const float matching_filter_threshold_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_H_
diff --git a/webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc b/webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc
new file mode 100644
index 0000000..ed32102
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/matched_filter_avx2.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/matched_filter.h"
+
+#include <immintrin.h>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace aec3 {
+
+void MatchedFilterCore_AVX2(size_t x_start_index,
+ float x2_sum_threshold,
+ float smoothing,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> h,
+ bool* filters_updated,
+ float* error_sum) {
+ const int h_size = static_cast<int>(h.size());
+ const int x_size = static_cast<int>(x.size());
+ RTC_DCHECK_EQ(0, h_size % 8);
+
+ // Process for all samples in the sub-block.
+ for (size_t i = 0; i < y.size(); ++i) {
+ // Apply the matched filter as filter * x, and compute x * x.
+
+ RTC_DCHECK_GT(x_size, x_start_index);
+ const float* x_p = &x[x_start_index];
+ const float* h_p = &h[0];
+
+ // Initialize values for the accumulation.
+ __m256 s_256 = _mm256_set1_ps(0);
+ __m256 x2_sum_256 = _mm256_set1_ps(0);
+ float x2_sum = 0.f;
+ float s = 0;
+
+ // Compute loop chunk sizes until, and after, the wraparound of the circular
+ // buffer for x.
+ const int chunk1 =
+ std::min(h_size, static_cast<int>(x_size - x_start_index));
+
+ // Perform the loop in two chunks.
+ const int chunk2 = h_size - chunk1;
+ for (int limit : {chunk1, chunk2}) {
+ // Perform 256 bit vector operations.
+ const int limit_by_8 = limit >> 3;
+ for (int k = limit_by_8; k > 0; --k, h_p += 8, x_p += 8) {
+ // Load the data into 256 bit vectors.
+ __m256 x_k = _mm256_loadu_ps(x_p);
+ __m256 h_k = _mm256_loadu_ps(h_p);
+ // Compute and accumulate x * x and h * x.
+ x2_sum_256 = _mm256_fmadd_ps(x_k, x_k, x2_sum_256);
+ s_256 = _mm256_fmadd_ps(h_k, x_k, s_256);
+ }
+
+ // Perform non-vector operations for any remaining items.
+ for (int k = limit - limit_by_8 * 8; k > 0; --k, ++h_p, ++x_p) {
+ const float x_k = *x_p;
+ x2_sum += x_k * x_k;
+ s += *h_p * x_k;
+ }
+
+ x_p = &x[0];
+ }
+
+ // Sum components together.
+ __m128 x2_sum_128 = _mm_add_ps(_mm256_extractf128_ps(x2_sum_256, 0),
+ _mm256_extractf128_ps(x2_sum_256, 1));
+ __m128 s_128 = _mm_add_ps(_mm256_extractf128_ps(s_256, 0),
+ _mm256_extractf128_ps(s_256, 1));
+ // Combine the accumulated vector and scalar values.
+ float* v = reinterpret_cast<float*>(&x2_sum_128);
+ x2_sum += v[0] + v[1] + v[2] + v[3];
+ v = reinterpret_cast<float*>(&s_128);
+ s += v[0] + v[1] + v[2] + v[3];
+
+ // Compute the matched filter error.
+ float e = y[i] - s;
+ const bool saturation = y[i] >= 32000.f || y[i] <= -32000.f;
+ (*error_sum) += e * e;
+
+ // Update the matched filter estimate in an NLMS manner.
+ if (x2_sum > x2_sum_threshold && !saturation) {
+ RTC_DCHECK_LT(0.f, x2_sum);
+ const float alpha = smoothing * e / x2_sum;
+ const __m256 alpha_256 = _mm256_set1_ps(alpha);
+
+ // filter = filter + smoothing * (y - filter * x) * x / x * x.
+ float* h_p = &h[0];
+ x_p = &x[x_start_index];
+
+ // Perform the loop in two chunks.
+ for (int limit : {chunk1, chunk2}) {
+ // Perform 256 bit vector operations.
+ const int limit_by_8 = limit >> 3;
+ for (int k = limit_by_8; k > 0; --k, h_p += 8, x_p += 8) {
+ // Load the data into 256 bit vectors.
+ __m256 h_k = _mm256_loadu_ps(h_p);
+ __m256 x_k = _mm256_loadu_ps(x_p);
+ // Compute h = h + alpha * x.
+ h_k = _mm256_fmadd_ps(x_k, alpha_256, h_k);
+
+ // Store the result.
+ _mm256_storeu_ps(h_p, h_k);
+ }
+
+ // Perform non-vector operations for any remaining items.
+ for (int k = limit - limit_by_8 * 8; k > 0; --k, ++h_p, ++x_p) {
+ *h_p += alpha * *x_p;
+ }
+
+ x_p = &x[0];
+ }
+
+ *filters_updated = true;
+ }
+
+ x_start_index = x_start_index > 0 ? x_start_index - 1 : x_size - 1;
+ }
+}
+
+} // namespace aec3
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc b/webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
new file mode 100644
index 0000000..603a864
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
@@ -0,0 +1,97 @@
+/*
+ * 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/audio_processing/aec3/matched_filter_lag_aggregator.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+MatchedFilterLagAggregator::MatchedFilterLagAggregator(
+ ApmDataDumper* data_dumper,
+ size_t max_filter_lag,
+ const EchoCanceller3Config::Delay::DelaySelectionThresholds& thresholds)
+ : data_dumper_(data_dumper),
+ histogram_(max_filter_lag + 1, 0),
+ thresholds_(thresholds) {
+ RTC_DCHECK(data_dumper);
+ RTC_DCHECK_LE(thresholds_.initial, thresholds_.converged);
+ histogram_data_.fill(0);
+}
+
+MatchedFilterLagAggregator::~MatchedFilterLagAggregator() = default;
+
+void MatchedFilterLagAggregator::Reset(bool hard_reset) {
+ std::fill(histogram_.begin(), histogram_.end(), 0);
+ histogram_data_.fill(0);
+ histogram_data_index_ = 0;
+ if (hard_reset) {
+ significant_candidate_found_ = false;
+ }
+}
+
+absl::optional<DelayEstimate> MatchedFilterLagAggregator::Aggregate(
+ rtc::ArrayView<const MatchedFilter::LagEstimate> lag_estimates) {
+ // Choose the strongest lag estimate as the best one.
+ float best_accuracy = 0.f;
+ int best_lag_estimate_index = -1;
+ for (size_t k = 0; k < lag_estimates.size(); ++k) {
+ if (lag_estimates[k].updated && lag_estimates[k].reliable) {
+ if (lag_estimates[k].accuracy > best_accuracy) {
+ best_accuracy = lag_estimates[k].accuracy;
+ best_lag_estimate_index = static_cast<int>(k);
+ }
+ }
+ }
+
+ // TODO(peah): Remove this logging once all development is done.
+ data_dumper_->DumpRaw("aec3_echo_path_delay_estimator_best_index",
+ best_lag_estimate_index);
+ data_dumper_->DumpRaw("aec3_echo_path_delay_estimator_histogram", histogram_);
+
+ if (best_lag_estimate_index != -1) {
+ RTC_DCHECK_GT(histogram_.size(), histogram_data_[histogram_data_index_]);
+ RTC_DCHECK_LE(0, histogram_data_[histogram_data_index_]);
+ --histogram_[histogram_data_[histogram_data_index_]];
+
+ histogram_data_[histogram_data_index_] =
+ lag_estimates[best_lag_estimate_index].lag;
+
+ RTC_DCHECK_GT(histogram_.size(), histogram_data_[histogram_data_index_]);
+ RTC_DCHECK_LE(0, histogram_data_[histogram_data_index_]);
+ ++histogram_[histogram_data_[histogram_data_index_]];
+
+ histogram_data_index_ =
+ (histogram_data_index_ + 1) % histogram_data_.size();
+
+ const int candidate =
+ std::distance(histogram_.begin(),
+ std::max_element(histogram_.begin(), histogram_.end()));
+
+ significant_candidate_found_ =
+ significant_candidate_found_ ||
+ histogram_[candidate] > thresholds_.converged;
+ if (histogram_[candidate] > thresholds_.converged ||
+ (histogram_[candidate] > thresholds_.initial &&
+ !significant_candidate_found_)) {
+ DelayEstimate::Quality quality = significant_candidate_found_
+ ? DelayEstimate::Quality::kRefined
+ : DelayEstimate::Quality::kCoarse;
+ return DelayEstimate(quality, candidate);
+ }
+ }
+
+ return absl::nullopt;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.h b/webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
new file mode 100644
index 0000000..d48011e
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
@@ -0,0 +1,58 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_LAG_AGGREGATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_LAG_AGGREGATOR_H_
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/delay_estimate.h"
+#include "modules/audio_processing/aec3/matched_filter.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+
+// Aggregates lag estimates produced by the MatchedFilter class into a single
+// reliable combined lag estimate.
+class MatchedFilterLagAggregator {
+ public:
+ MatchedFilterLagAggregator(
+ ApmDataDumper* data_dumper,
+ size_t max_filter_lag,
+ const EchoCanceller3Config::Delay::DelaySelectionThresholds& thresholds);
+
+ MatchedFilterLagAggregator() = delete;
+ MatchedFilterLagAggregator(const MatchedFilterLagAggregator&) = delete;
+ MatchedFilterLagAggregator& operator=(const MatchedFilterLagAggregator&) =
+ delete;
+
+ ~MatchedFilterLagAggregator();
+
+ // Resets the aggregator.
+ void Reset(bool hard_reset);
+
+ // Aggregates the provided lag estimates.
+ absl::optional<DelayEstimate> Aggregate(
+ rtc::ArrayView<const MatchedFilter::LagEstimate> lag_estimates);
+
+ private:
+ ApmDataDumper* const data_dumper_;
+ std::vector<int> histogram_;
+ std::array<int, 250> histogram_data_;
+ int histogram_data_index_ = 0;
+ bool significant_candidate_found_ = false;
+ const EchoCanceller3Config::Delay::DelaySelectionThresholds thresholds_;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_MATCHED_FILTER_LAG_AGGREGATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/moving_average.cc b/webrtc/modules/audio_processing/aec3/moving_average.cc
new file mode 100644
index 0000000..7a81ee8
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/moving_average.cc
@@ -0,0 +1,60 @@
+
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/moving_average.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace aec3 {
+
+MovingAverage::MovingAverage(size_t num_elem, size_t mem_len)
+ : num_elem_(num_elem),
+ mem_len_(mem_len - 1),
+ scaling_(1.0f / static_cast<float>(mem_len)),
+ memory_(num_elem * mem_len_, 0.f),
+ mem_index_(0) {
+ RTC_DCHECK(num_elem_ > 0);
+ RTC_DCHECK(mem_len > 0);
+}
+
+MovingAverage::~MovingAverage() = default;
+
+void MovingAverage::Average(rtc::ArrayView<const float> input,
+ rtc::ArrayView<float> output) {
+ RTC_DCHECK(input.size() == num_elem_);
+ RTC_DCHECK(output.size() == num_elem_);
+
+ // Sum all contributions.
+ std::copy(input.begin(), input.end(), output.begin());
+ for (auto i = memory_.begin(); i < memory_.end(); i += num_elem_) {
+ std::transform(i, i + num_elem_, output.begin(), output.begin(),
+ std::plus<float>());
+ }
+
+ // Divide by mem_len_.
+ for (float& o : output) {
+ o *= scaling_;
+ }
+
+ // Update memory.
+ if (mem_len_ > 0) {
+ std::copy(input.begin(), input.end(),
+ memory_.begin() + mem_index_ * num_elem_);
+ mem_index_ = (mem_index_ + 1) % mem_len_;
+ }
+}
+
+} // namespace aec3
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/moving_average.h b/webrtc/modules/audio_processing/aec3/moving_average.h
new file mode 100644
index 0000000..913d785
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/moving_average.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "api/array_view.h"
+
+namespace webrtc {
+namespace aec3 {
+
+class MovingAverage {
+ public:
+ // Creates an instance of MovingAverage that accepts inputs of length num_elem
+ // and averages over mem_len inputs.
+ MovingAverage(size_t num_elem, size_t mem_len);
+ ~MovingAverage();
+
+ // Computes the average of input and mem_len-1 previous inputs and stores the
+ // result in output.
+ void Average(rtc::ArrayView<const float> input, rtc::ArrayView<float> output);
+
+ private:
+ const size_t num_elem_;
+ const size_t mem_len_;
+ const float scaling_;
+ std::vector<float> memory_;
+ size_t mem_index_;
+};
+
+} // namespace aec3
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_MOVING_AVERAGE_H_
diff --git a/webrtc/modules/audio_processing/aec3/nearend_detector.h b/webrtc/modules/audio_processing/aec3/nearend_detector.h
new file mode 100644
index 0000000..0d8a06b
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/nearend_detector.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_NEAREND_DETECTOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_NEAREND_DETECTOR_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+// Class for selecting whether the suppressor is in the nearend or echo state.
+class NearendDetector {
+ public:
+ virtual ~NearendDetector() {}
+
+ // Returns whether the current state is the nearend state.
+ virtual bool IsNearendState() const = 0;
+
+ // Updates the state selection based on latest spectral estimates.
+ virtual void Update(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ nearend_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ residual_echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ bool initial_state) = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_NEAREND_DETECTOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/refined_filter_update_gain.cc b/webrtc/modules/audio_processing/aec3/refined_filter_update_gain.cc
new file mode 100644
index 0000000..138329a
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/refined_filter_update_gain.cc
@@ -0,0 +1,174 @@
+/*
+ * 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/audio_processing/aec3/refined_filter_update_gain.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "modules/audio_processing/aec3/adaptive_fir_filter.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/echo_path_variability.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "modules/audio_processing/aec3/render_signal_analyzer.h"
+#include "modules/audio_processing/aec3/subtractor_output.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+constexpr float kHErrorInitial = 10000.f;
+constexpr int kPoorExcitationCounterInitial = 1000;
+
+} // namespace
+
+int RefinedFilterUpdateGain::instance_count_ = 0;
+
+RefinedFilterUpdateGain::RefinedFilterUpdateGain(
+ const EchoCanceller3Config::Filter::RefinedConfiguration& config,
+ size_t config_change_duration_blocks)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ config_change_duration_blocks_(
+ static_cast<int>(config_change_duration_blocks)),
+ poor_excitation_counter_(kPoorExcitationCounterInitial) {
+ SetConfig(config, true);
+ H_error_.fill(kHErrorInitial);
+ RTC_DCHECK_LT(0, config_change_duration_blocks_);
+ one_by_config_change_duration_blocks_ = 1.f / config_change_duration_blocks_;
+}
+
+RefinedFilterUpdateGain::~RefinedFilterUpdateGain() {}
+
+void RefinedFilterUpdateGain::HandleEchoPathChange(
+ const EchoPathVariability& echo_path_variability) {
+ if (echo_path_variability.gain_change) {
+ // TODO(bugs.webrtc.org/9526) Handle gain changes.
+ }
+
+ if (echo_path_variability.delay_change !=
+ EchoPathVariability::DelayAdjustment::kNone) {
+ H_error_.fill(kHErrorInitial);
+ }
+
+ if (!echo_path_variability.gain_change) {
+ poor_excitation_counter_ = kPoorExcitationCounterInitial;
+ call_counter_ = 0;
+ }
+}
+
+void RefinedFilterUpdateGain::Compute(
+ const std::array<float, kFftLengthBy2Plus1>& render_power,
+ const RenderSignalAnalyzer& render_signal_analyzer,
+ const SubtractorOutput& subtractor_output,
+ rtc::ArrayView<const float> erl,
+ size_t size_partitions,
+ bool saturated_capture_signal,
+ FftData* gain_fft) {
+ RTC_DCHECK(gain_fft);
+ // Introducing shorter notation to improve readability.
+ const FftData& E_refined = subtractor_output.E_refined;
+ const auto& E2_refined = subtractor_output.E2_refined;
+ const auto& E2_coarse = subtractor_output.E2_coarse;
+ FftData* G = gain_fft;
+ const auto& X2 = render_power;
+
+ ++call_counter_;
+
+ UpdateCurrentConfig();
+
+ if (render_signal_analyzer.PoorSignalExcitation()) {
+ poor_excitation_counter_ = 0;
+ }
+
+ // Do not update the filter if the render is not sufficiently excited.
+ if (++poor_excitation_counter_ < size_partitions ||
+ saturated_capture_signal || call_counter_ <= size_partitions) {
+ G->re.fill(0.f);
+ G->im.fill(0.f);
+ } else {
+ // Corresponds to WGN of power -39 dBFS.
+ std::array<float, kFftLengthBy2Plus1> mu;
+ // mu = H_error / (0.5* H_error* X2 + n * E2).
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ if (X2[k] >= current_config_.noise_gate) {
+ mu[k] = H_error_[k] /
+ (0.5f * H_error_[k] * X2[k] + size_partitions * E2_refined[k]);
+ } else {
+ mu[k] = 0.f;
+ }
+ }
+
+ // Avoid updating the filter close to narrow bands in the render signals.
+ render_signal_analyzer.MaskRegionsAroundNarrowBands(&mu);
+
+ // H_error = H_error - 0.5 * mu * X2 * H_error.
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ H_error_[k] -= 0.5f * mu[k] * X2[k] * H_error_[k];
+ }
+
+ // G = mu * E.
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ G->re[k] = mu[k] * E_refined.re[k];
+ G->im[k] = mu[k] * E_refined.im[k];
+ }
+ }
+
+ // H_error = H_error + factor * erl.
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ if (E2_coarse[k] >= E2_refined[k]) {
+ H_error_[k] += current_config_.leakage_converged * erl[k];
+ } else {
+ H_error_[k] += current_config_.leakage_diverged * erl[k];
+ }
+
+ H_error_[k] = std::max(H_error_[k], current_config_.error_floor);
+ H_error_[k] = std::min(H_error_[k], current_config_.error_ceil);
+ }
+
+ data_dumper_->DumpRaw("aec3_refined_gain_H_error", H_error_);
+}
+
+void RefinedFilterUpdateGain::UpdateCurrentConfig() {
+ RTC_DCHECK_GE(config_change_duration_blocks_, config_change_counter_);
+ if (config_change_counter_ > 0) {
+ if (--config_change_counter_ > 0) {
+ auto average = [](float from, float to, float from_weight) {
+ return from * from_weight + to * (1.f - from_weight);
+ };
+
+ float change_factor =
+ config_change_counter_ * one_by_config_change_duration_blocks_;
+
+ current_config_.leakage_converged =
+ average(old_target_config_.leakage_converged,
+ target_config_.leakage_converged, change_factor);
+ current_config_.leakage_diverged =
+ average(old_target_config_.leakage_diverged,
+ target_config_.leakage_diverged, change_factor);
+ current_config_.error_floor =
+ average(old_target_config_.error_floor, target_config_.error_floor,
+ change_factor);
+ current_config_.error_ceil =
+ average(old_target_config_.error_ceil, target_config_.error_ceil,
+ change_factor);
+ current_config_.noise_gate =
+ average(old_target_config_.noise_gate, target_config_.noise_gate,
+ change_factor);
+ } else {
+ current_config_ = old_target_config_ = target_config_;
+ }
+ }
+ RTC_DCHECK_LE(0, config_change_counter_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/refined_filter_update_gain.h b/webrtc/modules/audio_processing/aec3/refined_filter_update_gain.h
new file mode 100644
index 0000000..5730979
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/refined_filter_update_gain.h
@@ -0,0 +1,89 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_REFINED_FILTER_UPDATE_GAIN_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_REFINED_FILTER_UPDATE_GAIN_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <memory>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+class AdaptiveFirFilter;
+class ApmDataDumper;
+struct EchoPathVariability;
+struct FftData;
+class RenderSignalAnalyzer;
+struct SubtractorOutput;
+
+// Provides functionality for computing the adaptive gain for the refined
+// filter.
+class RefinedFilterUpdateGain {
+ public:
+ RefinedFilterUpdateGain(
+ const EchoCanceller3Config::Filter::RefinedConfiguration& config,
+ size_t config_change_duration_blocks);
+ ~RefinedFilterUpdateGain();
+
+ RefinedFilterUpdateGain(const RefinedFilterUpdateGain&) = delete;
+ RefinedFilterUpdateGain& operator=(const RefinedFilterUpdateGain&) = delete;
+
+ // Takes action in the case of a known echo path change.
+ void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
+
+ // Computes the gain.
+ void Compute(const std::array<float, kFftLengthBy2Plus1>& render_power,
+ const RenderSignalAnalyzer& render_signal_analyzer,
+ const SubtractorOutput& subtractor_output,
+ rtc::ArrayView<const float> erl,
+ size_t size_partitions,
+ bool saturated_capture_signal,
+ FftData* gain_fft);
+
+ // Sets a new config.
+ void SetConfig(
+ const EchoCanceller3Config::Filter::RefinedConfiguration& config,
+ bool immediate_effect) {
+ if (immediate_effect) {
+ old_target_config_ = current_config_ = target_config_ = config;
+ config_change_counter_ = 0;
+ } else {
+ old_target_config_ = current_config_;
+ target_config_ = config;
+ config_change_counter_ = config_change_duration_blocks_;
+ }
+ }
+
+ private:
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const int config_change_duration_blocks_;
+ float one_by_config_change_duration_blocks_;
+ EchoCanceller3Config::Filter::RefinedConfiguration current_config_;
+ EchoCanceller3Config::Filter::RefinedConfiguration target_config_;
+ EchoCanceller3Config::Filter::RefinedConfiguration old_target_config_;
+ std::array<float, kFftLengthBy2Plus1> H_error_;
+ size_t poor_excitation_counter_;
+ size_t call_counter_ = 0;
+ int config_change_counter_ = 0;
+
+ // Updates the current config towards the target config.
+ void UpdateCurrentConfig();
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_REFINED_FILTER_UPDATE_GAIN_H_
diff --git a/webrtc/modules/audio_processing/aec3/render_buffer.cc b/webrtc/modules/audio_processing/aec3/render_buffer.cc
new file mode 100644
index 0000000..60ea69c
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_buffer.cc
@@ -0,0 +1,80 @@
+/*
+ * 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/audio_processing/aec3/render_buffer.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+RenderBuffer::RenderBuffer(BlockBuffer* block_buffer,
+ SpectrumBuffer* spectrum_buffer,
+ FftBuffer* fft_buffer)
+ : block_buffer_(block_buffer),
+ spectrum_buffer_(spectrum_buffer),
+ fft_buffer_(fft_buffer) {
+ RTC_DCHECK(block_buffer_);
+ RTC_DCHECK(spectrum_buffer_);
+ RTC_DCHECK(fft_buffer_);
+ RTC_DCHECK_EQ(block_buffer_->buffer.size(), fft_buffer_->buffer.size());
+ RTC_DCHECK_EQ(spectrum_buffer_->buffer.size(), fft_buffer_->buffer.size());
+ RTC_DCHECK_EQ(spectrum_buffer_->read, fft_buffer_->read);
+ RTC_DCHECK_EQ(spectrum_buffer_->write, fft_buffer_->write);
+}
+
+RenderBuffer::~RenderBuffer() = default;
+
+void RenderBuffer::SpectralSum(
+ size_t num_spectra,
+ std::array<float, kFftLengthBy2Plus1>* X2) const {
+ X2->fill(0.f);
+ int position = spectrum_buffer_->read;
+ for (size_t j = 0; j < num_spectra; ++j) {
+ for (const auto& channel_spectrum : spectrum_buffer_->buffer[position]) {
+ std::transform(X2->begin(), X2->end(), channel_spectrum.begin(),
+ X2->begin(), std::plus<float>());
+ }
+ position = spectrum_buffer_->IncIndex(position);
+ }
+}
+
+void RenderBuffer::SpectralSums(
+ size_t num_spectra_shorter,
+ size_t num_spectra_longer,
+ std::array<float, kFftLengthBy2Plus1>* X2_shorter,
+ std::array<float, kFftLengthBy2Plus1>* X2_longer) const {
+ RTC_DCHECK_LE(num_spectra_shorter, num_spectra_longer);
+ X2_shorter->fill(0.f);
+ int position = spectrum_buffer_->read;
+ size_t j = 0;
+ for (; j < num_spectra_shorter; ++j) {
+ for (const auto& channel_spectrum : spectrum_buffer_->buffer[position]) {
+ std::transform(X2_shorter->begin(), X2_shorter->end(),
+ channel_spectrum.begin(), X2_shorter->begin(),
+ std::plus<float>());
+ }
+ position = spectrum_buffer_->IncIndex(position);
+ }
+ std::copy(X2_shorter->begin(), X2_shorter->end(), X2_longer->begin());
+ for (; j < num_spectra_longer; ++j) {
+ for (const auto& channel_spectrum : spectrum_buffer_->buffer[position]) {
+ std::transform(X2_longer->begin(), X2_longer->end(),
+ channel_spectrum.begin(), X2_longer->begin(),
+ std::plus<float>());
+ }
+ position = spectrum_buffer_->IncIndex(position);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/render_buffer.h b/webrtc/modules/audio_processing/aec3/render_buffer.h
new file mode 100644
index 0000000..b8be6f5
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_buffer.h
@@ -0,0 +1,116 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_RENDER_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_RENDER_BUFFER_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/block_buffer.h"
+#include "modules/audio_processing/aec3/fft_buffer.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "modules/audio_processing/aec3/spectrum_buffer.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// Provides a buffer of the render data for the echo remover.
+class RenderBuffer {
+ public:
+ RenderBuffer(BlockBuffer* block_buffer,
+ SpectrumBuffer* spectrum_buffer,
+ FftBuffer* fft_buffer);
+
+ RenderBuffer() = delete;
+ RenderBuffer(const RenderBuffer&) = delete;
+ RenderBuffer& operator=(const RenderBuffer&) = delete;
+
+ ~RenderBuffer();
+
+ // Get a block.
+ const std::vector<std::vector<std::vector<float>>>& Block(
+ int buffer_offset_blocks) const {
+ int position =
+ block_buffer_->OffsetIndex(block_buffer_->read, buffer_offset_blocks);
+ return block_buffer_->buffer[position];
+ }
+
+ // Get the spectrum from one of the FFTs in the buffer.
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Spectrum(
+ int buffer_offset_ffts) const {
+ int position = spectrum_buffer_->OffsetIndex(spectrum_buffer_->read,
+ buffer_offset_ffts);
+ return spectrum_buffer_->buffer[position];
+ }
+
+ // Returns the circular fft buffer.
+ rtc::ArrayView<const std::vector<FftData>> GetFftBuffer() const {
+ return fft_buffer_->buffer;
+ }
+
+ // Returns the current position in the circular buffer.
+ size_t Position() const {
+ RTC_DCHECK_EQ(spectrum_buffer_->read, fft_buffer_->read);
+ RTC_DCHECK_EQ(spectrum_buffer_->write, fft_buffer_->write);
+ return fft_buffer_->read;
+ }
+
+ // Returns the sum of the spectrums for a certain number of FFTs.
+ void SpectralSum(size_t num_spectra,
+ std::array<float, kFftLengthBy2Plus1>* X2) const;
+
+ // Returns the sums of the spectrums for two numbers of FFTs.
+ void SpectralSums(size_t num_spectra_shorter,
+ size_t num_spectra_longer,
+ std::array<float, kFftLengthBy2Plus1>* X2_shorter,
+ std::array<float, kFftLengthBy2Plus1>* X2_longer) const;
+
+ // Gets the recent activity seen in the render signal.
+ bool GetRenderActivity() const { return render_activity_; }
+
+ // Specifies the recent activity seen in the render signal.
+ void SetRenderActivity(bool activity) { render_activity_ = activity; }
+
+ // Returns the headroom between the write and the read positions in the
+ // buffer.
+ int Headroom() const {
+ // The write and read indices are decreased over time.
+ int headroom =
+ fft_buffer_->write < fft_buffer_->read
+ ? fft_buffer_->read - fft_buffer_->write
+ : fft_buffer_->size - fft_buffer_->write + fft_buffer_->read;
+
+ RTC_DCHECK_LE(0, headroom);
+ RTC_DCHECK_GE(fft_buffer_->size, headroom);
+
+ return headroom;
+ }
+
+ // Returns a reference to the spectrum buffer.
+ const SpectrumBuffer& GetSpectrumBuffer() const { return *spectrum_buffer_; }
+
+ // Returns a reference to the block buffer.
+ const BlockBuffer& GetBlockBuffer() const { return *block_buffer_; }
+
+ private:
+ const BlockBuffer* const block_buffer_;
+ const SpectrumBuffer* const spectrum_buffer_;
+ const FftBuffer* const fft_buffer_;
+ bool render_activity_ = false;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/aec3/render_delay_buffer.cc b/webrtc/modules/audio_processing/aec3/render_delay_buffer.cc
new file mode 100644
index 0000000..7bebc6f
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_delay_buffer.cc
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/render_delay_buffer.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <numeric>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec3_fft.h"
+#include "modules/audio_processing/aec3/alignment_mixer.h"
+#include "modules/audio_processing/aec3/block_buffer.h"
+#include "modules/audio_processing/aec3/decimator.h"
+#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
+#include "modules/audio_processing/aec3/fft_buffer.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/spectrum_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+namespace {
+
+bool UpdateCaptureCallCounterOnSkippedBlocks() {
+ return !field_trial::IsEnabled(
+ "WebRTC-Aec3RenderBufferCallCounterUpdateKillSwitch");
+}
+
+class RenderDelayBufferImpl final : public RenderDelayBuffer {
+ public:
+ RenderDelayBufferImpl(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels);
+ RenderDelayBufferImpl() = delete;
+ ~RenderDelayBufferImpl() override;
+
+ void Reset() override;
+ BufferingEvent Insert(
+ const std::vector<std::vector<std::vector<float>>>& block) override;
+ BufferingEvent PrepareCaptureProcessing() override;
+ void HandleSkippedCaptureProcessing() override;
+ bool AlignFromDelay(size_t delay) override;
+ void AlignFromExternalDelay() override;
+ size_t Delay() const override { return ComputeDelay(); }
+ size_t MaxDelay() const override {
+ return blocks_.buffer.size() - 1 - buffer_headroom_;
+ }
+ RenderBuffer* GetRenderBuffer() override { return &echo_remover_buffer_; }
+
+ const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const override {
+ return low_rate_;
+ }
+
+ int BufferLatency() const;
+ void SetAudioBufferDelay(int delay_ms) override;
+ bool HasReceivedBufferDelay() override;
+
+ private:
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const Aec3Optimization optimization_;
+ const EchoCanceller3Config config_;
+ const bool update_capture_call_counter_on_skipped_blocks_;
+ const float render_linear_amplitude_gain_;
+ const rtc::LoggingSeverity delay_log_level_;
+ size_t down_sampling_factor_;
+ const int sub_block_size_;
+ BlockBuffer blocks_;
+ SpectrumBuffer spectra_;
+ FftBuffer ffts_;
+ absl::optional<size_t> delay_;
+ RenderBuffer echo_remover_buffer_;
+ DownsampledRenderBuffer low_rate_;
+ AlignmentMixer render_mixer_;
+ Decimator render_decimator_;
+ const Aec3Fft fft_;
+ std::vector<float> render_ds_;
+ const int buffer_headroom_;
+ bool last_call_was_render_ = false;
+ int num_api_calls_in_a_row_ = 0;
+ int max_observed_jitter_ = 1;
+ int64_t capture_call_counter_ = 0;
+ int64_t render_call_counter_ = 0;
+ bool render_activity_ = false;
+ size_t render_activity_counter_ = 0;
+ absl::optional<int> external_audio_buffer_delay_;
+ bool external_audio_buffer_delay_verified_after_reset_ = false;
+ size_t min_latency_blocks_ = 0;
+ size_t excess_render_detection_counter_ = 0;
+
+ int MapDelayToTotalDelay(size_t delay) const;
+ int ComputeDelay() const;
+ void ApplyTotalDelay(int delay);
+ void InsertBlock(const std::vector<std::vector<std::vector<float>>>& block,
+ int previous_write);
+ bool DetectActiveRender(rtc::ArrayView<const float> x) const;
+ bool DetectExcessRenderBlocks();
+ void IncrementWriteIndices();
+ void IncrementLowRateReadIndices();
+ void IncrementReadIndices();
+ bool RenderOverrun();
+ bool RenderUnderrun();
+};
+
+int RenderDelayBufferImpl::instance_count_ = 0;
+
+RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ optimization_(DetectOptimization()),
+ config_(config),
+ update_capture_call_counter_on_skipped_blocks_(
+ UpdateCaptureCallCounterOnSkippedBlocks()),
+ render_linear_amplitude_gain_(
+ std::pow(10.0f, config_.render_levels.render_power_gain_db / 20.f)),
+ delay_log_level_(config_.delay.log_warning_on_delay_changes
+ ? rtc::LS_WARNING
+ : rtc::LS_VERBOSE),
+ down_sampling_factor_(config.delay.down_sampling_factor),
+ sub_block_size_(static_cast<int>(down_sampling_factor_ > 0
+ ? kBlockSize / down_sampling_factor_
+ : kBlockSize)),
+ blocks_(GetRenderDelayBufferSize(down_sampling_factor_,
+ config.delay.num_filters,
+ config.filter.refined.length_blocks),
+ NumBandsForRate(sample_rate_hz),
+ num_render_channels,
+ kBlockSize),
+ spectra_(blocks_.buffer.size(), num_render_channels),
+ ffts_(blocks_.buffer.size(), num_render_channels),
+ delay_(config_.delay.default_delay),
+ echo_remover_buffer_(&blocks_, &spectra_, &ffts_),
+ low_rate_(GetDownSampledBufferSize(down_sampling_factor_,
+ config.delay.num_filters)),
+ render_mixer_(num_render_channels, config.delay.render_alignment_mixing),
+ render_decimator_(down_sampling_factor_),
+ fft_(),
+ render_ds_(sub_block_size_, 0.f),
+ buffer_headroom_(config.filter.refined.length_blocks) {
+ RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size());
+ RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size());
+ for (size_t i = 0; i < blocks_.buffer.size(); ++i) {
+ RTC_DCHECK_EQ(blocks_.buffer[i][0].size(), ffts_.buffer[i].size());
+ RTC_DCHECK_EQ(spectra_.buffer[i].size(), ffts_.buffer[i].size());
+ }
+
+ Reset();
+}
+
+RenderDelayBufferImpl::~RenderDelayBufferImpl() = default;
+
+// Resets the buffer delays and clears the reported delays.
+void RenderDelayBufferImpl::Reset() {
+ last_call_was_render_ = false;
+ num_api_calls_in_a_row_ = 1;
+ min_latency_blocks_ = 0;
+ excess_render_detection_counter_ = 0;
+
+ // Initialize the read index to one sub-block before the write index.
+ low_rate_.read = low_rate_.OffsetIndex(low_rate_.write, sub_block_size_);
+
+ // Check for any external audio buffer delay and whether it is feasible.
+ if (external_audio_buffer_delay_) {
+ const int headroom = 2;
+ size_t audio_buffer_delay_to_set;
+ // Minimum delay is 1 (like the low-rate render buffer).
+ if (*external_audio_buffer_delay_ <= headroom) {
+ audio_buffer_delay_to_set = 1;
+ } else {
+ audio_buffer_delay_to_set = *external_audio_buffer_delay_ - headroom;
+ }
+
+ audio_buffer_delay_to_set = std::min(audio_buffer_delay_to_set, MaxDelay());
+
+ // When an external delay estimate is available, use that delay as the
+ // initial render buffer delay.
+ ApplyTotalDelay(audio_buffer_delay_to_set);
+ delay_ = ComputeDelay();
+
+ external_audio_buffer_delay_verified_after_reset_ = false;
+ } else {
+ // If an external delay estimate is not available, use that delay as the
+ // initial delay. Set the render buffer delays to the default delay.
+ ApplyTotalDelay(config_.delay.default_delay);
+
+ // Unset the delays which are set by AlignFromDelay.
+ delay_ = absl::nullopt;
+ }
+}
+
+// Inserts a new block into the render buffers.
+RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert(
+ const std::vector<std::vector<std::vector<float>>>& block) {
+ ++render_call_counter_;
+ if (delay_) {
+ if (!last_call_was_render_) {
+ last_call_was_render_ = true;
+ num_api_calls_in_a_row_ = 1;
+ } else {
+ if (++num_api_calls_in_a_row_ > max_observed_jitter_) {
+ max_observed_jitter_ = num_api_calls_in_a_row_;
+ RTC_LOG_V(delay_log_level_)
+ << "New max number api jitter observed at render block "
+ << render_call_counter_ << ": " << num_api_calls_in_a_row_
+ << " blocks";
+ }
+ }
+ }
+
+ // Increase the write indices to where the new blocks should be written.
+ const int previous_write = blocks_.write;
+ IncrementWriteIndices();
+
+ // Allow overrun and do a reset when render overrun occurrs due to more render
+ // data being inserted than capture data is received.
+ BufferingEvent event =
+ RenderOverrun() ? BufferingEvent::kRenderOverrun : BufferingEvent::kNone;
+
+ // Detect and update render activity.
+ if (!render_activity_) {
+ render_activity_counter_ += DetectActiveRender(block[0][0]) ? 1 : 0;
+ render_activity_ = render_activity_counter_ >= 20;
+ }
+
+ // Insert the new render block into the specified position.
+ InsertBlock(block, previous_write);
+
+ if (event != BufferingEvent::kNone) {
+ Reset();
+ }
+
+ return event;
+}
+
+void RenderDelayBufferImpl::HandleSkippedCaptureProcessing() {
+ if (update_capture_call_counter_on_skipped_blocks_) {
+ ++capture_call_counter_;
+ }
+}
+
+// Prepares the render buffers for processing another capture block.
+RenderDelayBuffer::BufferingEvent
+RenderDelayBufferImpl::PrepareCaptureProcessing() {
+ RenderDelayBuffer::BufferingEvent event = BufferingEvent::kNone;
+ ++capture_call_counter_;
+
+ if (delay_) {
+ if (last_call_was_render_) {
+ last_call_was_render_ = false;
+ num_api_calls_in_a_row_ = 1;
+ } else {
+ if (++num_api_calls_in_a_row_ > max_observed_jitter_) {
+ max_observed_jitter_ = num_api_calls_in_a_row_;
+ RTC_LOG_V(delay_log_level_)
+ << "New max number api jitter observed at capture block "
+ << capture_call_counter_ << ": " << num_api_calls_in_a_row_
+ << " blocks";
+ }
+ }
+ }
+
+ if (DetectExcessRenderBlocks()) {
+ // Too many render blocks compared to capture blocks. Risk of delay ending
+ // up before the filter used by the delay estimator.
+ RTC_LOG_V(delay_log_level_)
+ << "Excess render blocks detected at block " << capture_call_counter_;
+ Reset();
+ event = BufferingEvent::kRenderOverrun;
+ } else if (RenderUnderrun()) {
+ // Don't increment the read indices of the low rate buffer if there is a
+ // render underrun.
+ RTC_LOG_V(delay_log_level_)
+ << "Render buffer underrun detected at block " << capture_call_counter_;
+ IncrementReadIndices();
+ // Incrementing the buffer index without increasing the low rate buffer
+ // index means that the delay is reduced by one.
+ if (delay_ && *delay_ > 0)
+ delay_ = *delay_ - 1;
+ event = BufferingEvent::kRenderUnderrun;
+ } else {
+ // Increment the read indices in the render buffers to point to the most
+ // recent block to use in the capture processing.
+ IncrementLowRateReadIndices();
+ IncrementReadIndices();
+ }
+
+ echo_remover_buffer_.SetRenderActivity(render_activity_);
+ if (render_activity_) {
+ render_activity_counter_ = 0;
+ render_activity_ = false;
+ }
+
+ return event;
+}
+
+// Sets the delay and returns a bool indicating whether the delay was changed.
+bool RenderDelayBufferImpl::AlignFromDelay(size_t delay) {
+ RTC_DCHECK(!config_.delay.use_external_delay_estimator);
+ if (!external_audio_buffer_delay_verified_after_reset_ &&
+ external_audio_buffer_delay_ && delay_) {
+ int difference = static_cast<int>(delay) - static_cast<int>(*delay_);
+ RTC_LOG_V(delay_log_level_)
+ << "Mismatch between first estimated delay after reset "
+ "and externally reported audio buffer delay: "
+ << difference << " blocks";
+ external_audio_buffer_delay_verified_after_reset_ = true;
+ }
+ if (delay_ && *delay_ == delay) {
+ return false;
+ }
+ delay_ = delay;
+
+ // Compute the total delay and limit the delay to the allowed range.
+ int total_delay = MapDelayToTotalDelay(*delay_);
+ total_delay =
+ std::min(MaxDelay(), static_cast<size_t>(std::max(total_delay, 0)));
+
+ // Apply the delay to the buffers.
+ ApplyTotalDelay(total_delay);
+ return true;
+}
+
+void RenderDelayBufferImpl::SetAudioBufferDelay(int delay_ms) {
+ if (!external_audio_buffer_delay_) {
+ RTC_LOG_V(delay_log_level_)
+ << "Receiving a first externally reported audio buffer delay of "
+ << delay_ms << " ms.";
+ }
+
+ // Convert delay from milliseconds to blocks (rounded down).
+ external_audio_buffer_delay_ = delay_ms / 4;
+}
+
+bool RenderDelayBufferImpl::HasReceivedBufferDelay() {
+ return external_audio_buffer_delay_.has_value();
+}
+
+// Maps the externally computed delay to the delay used internally.
+int RenderDelayBufferImpl::MapDelayToTotalDelay(
+ size_t external_delay_blocks) const {
+ const int latency_blocks = BufferLatency();
+ return latency_blocks + static_cast<int>(external_delay_blocks);
+}
+
+// Returns the delay (not including call jitter).
+int RenderDelayBufferImpl::ComputeDelay() const {
+ const int latency_blocks = BufferLatency();
+ int internal_delay = spectra_.read >= spectra_.write
+ ? spectra_.read - spectra_.write
+ : spectra_.size + spectra_.read - spectra_.write;
+
+ return internal_delay - latency_blocks;
+}
+
+// Set the read indices according to the delay.
+void RenderDelayBufferImpl::ApplyTotalDelay(int delay) {
+ RTC_LOG_V(delay_log_level_)
+ << "Applying total delay of " << delay << " blocks.";
+ blocks_.read = blocks_.OffsetIndex(blocks_.write, -delay);
+ spectra_.read = spectra_.OffsetIndex(spectra_.write, delay);
+ ffts_.read = ffts_.OffsetIndex(ffts_.write, delay);
+}
+
+void RenderDelayBufferImpl::AlignFromExternalDelay() {
+ RTC_DCHECK(config_.delay.use_external_delay_estimator);
+ if (external_audio_buffer_delay_) {
+ const int64_t delay = render_call_counter_ - capture_call_counter_ +
+ *external_audio_buffer_delay_;
+ const int64_t delay_with_headroom =
+ delay - config_.delay.delay_headroom_samples / kBlockSize;
+ ApplyTotalDelay(delay_with_headroom);
+ }
+}
+
+// Inserts a block into the render buffers.
+void RenderDelayBufferImpl::InsertBlock(
+ const std::vector<std::vector<std::vector<float>>>& block,
+ int previous_write) {
+ auto& b = blocks_;
+ auto& lr = low_rate_;
+ auto& ds = render_ds_;
+ auto& f = ffts_;
+ auto& s = spectra_;
+ const size_t num_bands = b.buffer[b.write].size();
+ const size_t num_render_channels = b.buffer[b.write][0].size();
+ RTC_DCHECK_EQ(block.size(), b.buffer[b.write].size());
+ for (size_t band = 0; band < num_bands; ++band) {
+ RTC_DCHECK_EQ(block[band].size(), num_render_channels);
+ RTC_DCHECK_EQ(b.buffer[b.write][band].size(), num_render_channels);
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ RTC_DCHECK_EQ(block[band][ch].size(), b.buffer[b.write][band][ch].size());
+ std::copy(block[band][ch].begin(), block[band][ch].end(),
+ b.buffer[b.write][band][ch].begin());
+ }
+ }
+
+ if (render_linear_amplitude_gain_ != 1.f) {
+ for (size_t band = 0; band < num_bands; ++band) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ for (size_t k = 0; k < 64; ++k) {
+ b.buffer[b.write][band][ch][k] *= render_linear_amplitude_gain_;
+ }
+ }
+ }
+ }
+
+ std::array<float, kBlockSize> downmixed_render;
+ render_mixer_.ProduceOutput(b.buffer[b.write][0], downmixed_render);
+ render_decimator_.Decimate(downmixed_render, ds);
+ data_dumper_->DumpWav("aec3_render_decimator_output", ds.size(), ds.data(),
+ 16000 / down_sampling_factor_, 1);
+ std::copy(ds.rbegin(), ds.rend(), lr.buffer.begin() + lr.write);
+ for (size_t channel = 0; channel < b.buffer[b.write][0].size(); ++channel) {
+ fft_.PaddedFft(b.buffer[b.write][0][channel],
+ b.buffer[previous_write][0][channel],
+ &f.buffer[f.write][channel]);
+ f.buffer[f.write][channel].Spectrum(optimization_,
+ s.buffer[s.write][channel]);
+ }
+}
+
+bool RenderDelayBufferImpl::DetectActiveRender(
+ rtc::ArrayView<const float> x) const {
+ const float x_energy = std::inner_product(x.begin(), x.end(), x.begin(), 0.f);
+ return x_energy > (config_.render_levels.active_render_limit *
+ config_.render_levels.active_render_limit) *
+ kFftLengthBy2;
+}
+
+bool RenderDelayBufferImpl::DetectExcessRenderBlocks() {
+ bool excess_render_detected = false;
+ const size_t latency_blocks = static_cast<size_t>(BufferLatency());
+ // The recently seen minimum latency in blocks. Should be close to 0.
+ min_latency_blocks_ = std::min(min_latency_blocks_, latency_blocks);
+ // After processing a configurable number of blocks the minimum latency is
+ // checked.
+ if (++excess_render_detection_counter_ >=
+ config_.buffering.excess_render_detection_interval_blocks) {
+ // If the minimum latency is not lower than the threshold there have been
+ // more render than capture frames.
+ excess_render_detected = min_latency_blocks_ >
+ config_.buffering.max_allowed_excess_render_blocks;
+ // Reset the counter and let the minimum latency be the current latency.
+ min_latency_blocks_ = latency_blocks;
+ excess_render_detection_counter_ = 0;
+ }
+
+ data_dumper_->DumpRaw("aec3_latency_blocks", latency_blocks);
+ data_dumper_->DumpRaw("aec3_min_latency_blocks", min_latency_blocks_);
+ data_dumper_->DumpRaw("aec3_excess_render_detected", excess_render_detected);
+ return excess_render_detected;
+}
+
+// Computes the latency in the buffer (the number of unread sub-blocks).
+int RenderDelayBufferImpl::BufferLatency() const {
+ const DownsampledRenderBuffer& l = low_rate_;
+ int latency_samples = (l.buffer.size() + l.read - l.write) % l.buffer.size();
+ int latency_blocks = latency_samples / sub_block_size_;
+ return latency_blocks;
+}
+
+// Increments the write indices for the render buffers.
+void RenderDelayBufferImpl::IncrementWriteIndices() {
+ low_rate_.UpdateWriteIndex(-sub_block_size_);
+ blocks_.IncWriteIndex();
+ spectra_.DecWriteIndex();
+ ffts_.DecWriteIndex();
+}
+
+// Increments the read indices of the low rate render buffers.
+void RenderDelayBufferImpl::IncrementLowRateReadIndices() {
+ low_rate_.UpdateReadIndex(-sub_block_size_);
+}
+
+// Increments the read indices for the render buffers.
+void RenderDelayBufferImpl::IncrementReadIndices() {
+ if (blocks_.read != blocks_.write) {
+ blocks_.IncReadIndex();
+ spectra_.DecReadIndex();
+ ffts_.DecReadIndex();
+ }
+}
+
+// Checks for a render buffer overrun.
+bool RenderDelayBufferImpl::RenderOverrun() {
+ return low_rate_.read == low_rate_.write || blocks_.read == blocks_.write;
+}
+
+// Checks for a render buffer underrun.
+bool RenderDelayBufferImpl::RenderUnderrun() {
+ return low_rate_.read == low_rate_.write;
+}
+
+} // namespace
+
+RenderDelayBuffer* RenderDelayBuffer::Create(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels) {
+ return new RenderDelayBufferImpl(config, sample_rate_hz, num_render_channels);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/render_delay_buffer.h b/webrtc/modules/audio_processing/aec3/render_delay_buffer.h
new file mode 100644
index 0000000..79ffc4d
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_delay_buffer.h
@@ -0,0 +1,86 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_RENDER_DELAY_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_BUFFER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+
+namespace webrtc {
+
+// Class for buffering the incoming render blocks such that these may be
+// extracted with a specified delay.
+class RenderDelayBuffer {
+ public:
+ enum class BufferingEvent {
+ kNone,
+ kRenderUnderrun,
+ kRenderOverrun,
+ kApiCallSkew
+ };
+
+ static RenderDelayBuffer* Create(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_render_channels);
+ virtual ~RenderDelayBuffer() = default;
+
+ // Resets the buffer alignment.
+ virtual void Reset() = 0;
+
+ // Inserts a block into the buffer.
+ virtual BufferingEvent Insert(
+ const std::vector<std::vector<std::vector<float>>>& block) = 0;
+
+ // Updates the buffers one step based on the specified buffer delay. Returns
+ // an enum indicating whether there was a special event that occurred.
+ virtual BufferingEvent PrepareCaptureProcessing() = 0;
+
+ // Called on capture blocks where PrepareCaptureProcessing is not called.
+ virtual void HandleSkippedCaptureProcessing() = 0;
+
+ // Sets the buffer delay and returns a bool indicating whether the delay
+ // changed.
+ virtual bool AlignFromDelay(size_t delay) = 0;
+
+ // Sets the buffer delay from the most recently reported external delay.
+ virtual void AlignFromExternalDelay() = 0;
+
+ // Gets the buffer delay.
+ virtual size_t Delay() const = 0;
+
+ // Gets the buffer delay.
+ virtual size_t MaxDelay() const = 0;
+
+ // Returns the render buffer for the echo remover.
+ virtual RenderBuffer* GetRenderBuffer() = 0;
+
+ // Returns the downsampled render buffer.
+ virtual const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const = 0;
+
+ // Returns the maximum non calusal offset that can occur in the delay buffer.
+ static int DelayEstimatorOffset(const EchoCanceller3Config& config);
+
+ // Provides an optional external estimate of the audio buffer delay.
+ virtual void SetAudioBufferDelay(int delay_ms) = 0;
+
+ // Returns whether an external delay estimate has been reported via
+ // SetAudioBufferDelay.
+ virtual bool HasReceivedBufferDelay() = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/aec3/render_delay_controller.cc b/webrtc/modules/audio_processing/aec3/render_delay_controller.cc
new file mode 100644
index 0000000..3677085
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_delay_controller.cc
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "modules/audio_processing/aec3/render_delay_controller.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <memory>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/delay_estimate.h"
+#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
+#include "modules/audio_processing/aec3/echo_path_delay_estimator.h"
+#include "modules/audio_processing/aec3/render_delay_controller_metrics.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+class RenderDelayControllerImpl final : public RenderDelayController {
+ public:
+ RenderDelayControllerImpl(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_capture_channels);
+
+ RenderDelayControllerImpl() = delete;
+ RenderDelayControllerImpl(const RenderDelayControllerImpl&) = delete;
+ RenderDelayControllerImpl& operator=(const RenderDelayControllerImpl&) =
+ delete;
+
+ ~RenderDelayControllerImpl() override;
+ void Reset(bool reset_delay_confidence) override;
+ void LogRenderCall() override;
+ absl::optional<DelayEstimate> GetDelay(
+ const DownsampledRenderBuffer& render_buffer,
+ size_t render_delay_buffer_delay,
+ const std::vector<std::vector<float>>& capture) override;
+ bool HasClockdrift() const override;
+
+ private:
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const int hysteresis_limit_blocks_;
+ const int delay_headroom_samples_;
+ absl::optional<DelayEstimate> delay_;
+ EchoPathDelayEstimator delay_estimator_;
+ RenderDelayControllerMetrics metrics_;
+ absl::optional<DelayEstimate> delay_samples_;
+ size_t capture_call_counter_ = 0;
+ int delay_change_counter_ = 0;
+ DelayEstimate::Quality last_delay_estimate_quality_;
+};
+
+DelayEstimate ComputeBufferDelay(
+ const absl::optional<DelayEstimate>& current_delay,
+ int hysteresis_limit_blocks,
+ int delay_headroom_samples,
+ DelayEstimate estimated_delay) {
+ // Subtract delay headroom.
+ const int delay_with_headroom_samples = std::max(
+ static_cast<int>(estimated_delay.delay) - delay_headroom_samples, 0);
+
+ // Compute the buffer delay increase required to achieve the desired latency.
+ size_t new_delay_blocks = delay_with_headroom_samples >> kBlockSizeLog2;
+
+ // Add hysteresis.
+ if (current_delay) {
+ size_t current_delay_blocks = current_delay->delay;
+ if (new_delay_blocks > current_delay_blocks &&
+ new_delay_blocks <= current_delay_blocks + hysteresis_limit_blocks) {
+ new_delay_blocks = current_delay_blocks;
+ }
+ }
+
+ DelayEstimate new_delay = estimated_delay;
+ new_delay.delay = new_delay_blocks;
+ return new_delay;
+}
+
+int RenderDelayControllerImpl::instance_count_ = 0;
+
+RenderDelayControllerImpl::RenderDelayControllerImpl(
+ const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_capture_channels)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ hysteresis_limit_blocks_(
+ static_cast<int>(config.delay.hysteresis_limit_blocks)),
+ delay_headroom_samples_(config.delay.delay_headroom_samples),
+ delay_estimator_(data_dumper_.get(), config, num_capture_channels),
+ last_delay_estimate_quality_(DelayEstimate::Quality::kCoarse) {
+ RTC_DCHECK(ValidFullBandRate(sample_rate_hz));
+ delay_estimator_.LogDelayEstimationProperties(sample_rate_hz, 0);
+}
+
+RenderDelayControllerImpl::~RenderDelayControllerImpl() = default;
+
+void RenderDelayControllerImpl::Reset(bool reset_delay_confidence) {
+ delay_ = absl::nullopt;
+ delay_samples_ = absl::nullopt;
+ delay_estimator_.Reset(reset_delay_confidence);
+ delay_change_counter_ = 0;
+ if (reset_delay_confidence) {
+ last_delay_estimate_quality_ = DelayEstimate::Quality::kCoarse;
+ }
+}
+
+void RenderDelayControllerImpl::LogRenderCall() {}
+
+absl::optional<DelayEstimate> RenderDelayControllerImpl::GetDelay(
+ const DownsampledRenderBuffer& render_buffer,
+ size_t render_delay_buffer_delay,
+ const std::vector<std::vector<float>>& capture) {
+ RTC_DCHECK_EQ(kBlockSize, capture[0].size());
+ ++capture_call_counter_;
+
+ auto delay_samples = delay_estimator_.EstimateDelay(render_buffer, capture);
+
+ if (delay_samples) {
+ if (!delay_samples_ || delay_samples->delay != delay_samples_->delay) {
+ delay_change_counter_ = 0;
+ }
+ if (delay_samples_) {
+ delay_samples_->blocks_since_last_change =
+ delay_samples_->delay == delay_samples->delay
+ ? delay_samples_->blocks_since_last_change + 1
+ : 0;
+ delay_samples_->blocks_since_last_update = 0;
+ delay_samples_->delay = delay_samples->delay;
+ delay_samples_->quality = delay_samples->quality;
+ } else {
+ delay_samples_ = delay_samples;
+ }
+ } else {
+ if (delay_samples_) {
+ ++delay_samples_->blocks_since_last_change;
+ ++delay_samples_->blocks_since_last_update;
+ }
+ }
+
+ if (delay_change_counter_ < 2 * kNumBlocksPerSecond) {
+ ++delay_change_counter_;
+ }
+
+ if (delay_samples_) {
+ // Compute the render delay buffer delay.
+ const bool use_hysteresis =
+ last_delay_estimate_quality_ == DelayEstimate::Quality::kRefined &&
+ delay_samples_->quality == DelayEstimate::Quality::kRefined;
+ delay_ = ComputeBufferDelay(delay_,
+ use_hysteresis ? hysteresis_limit_blocks_ : 0,
+ delay_headroom_samples_, *delay_samples_);
+ last_delay_estimate_quality_ = delay_samples_->quality;
+ }
+
+ metrics_.Update(delay_samples_ ? absl::optional<size_t>(delay_samples_->delay)
+ : absl::nullopt,
+ delay_ ? delay_->delay : 0, 0, delay_estimator_.Clockdrift());
+
+ data_dumper_->DumpRaw("aec3_render_delay_controller_delay",
+ delay_samples ? delay_samples->delay : 0);
+ data_dumper_->DumpRaw("aec3_render_delay_controller_buffer_delay",
+ delay_ ? delay_->delay : 0);
+
+ return delay_;
+}
+
+bool RenderDelayControllerImpl::HasClockdrift() const {
+ return delay_estimator_.Clockdrift() != ClockdriftDetector::Level::kNone;
+}
+
+} // namespace
+
+RenderDelayController* RenderDelayController::Create(
+ const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_capture_channels) {
+ return new RenderDelayControllerImpl(config, sample_rate_hz,
+ num_capture_channels);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/render_delay_controller.h b/webrtc/modules/audio_processing/aec3/render_delay_controller.h
new file mode 100644
index 0000000..c45ab1f
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_delay_controller.h
@@ -0,0 +1,50 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_H_
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/delay_estimate.h"
+#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
+#include "modules/audio_processing/aec3/render_delay_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+
+namespace webrtc {
+
+// Class for aligning the render and capture signal using a RenderDelayBuffer.
+class RenderDelayController {
+ public:
+ static RenderDelayController* Create(const EchoCanceller3Config& config,
+ int sample_rate_hz,
+ size_t num_capture_channels);
+ virtual ~RenderDelayController() = default;
+
+ // Resets the delay controller. If the delay confidence is reset, the reset
+ // behavior is as if the call is restarted.
+ virtual void Reset(bool reset_delay_confidence) = 0;
+
+ // Logs a render call.
+ virtual void LogRenderCall() = 0;
+
+ // Aligns the render buffer content with the capture signal.
+ virtual absl::optional<DelayEstimate> GetDelay(
+ const DownsampledRenderBuffer& render_buffer,
+ size_t render_delay_buffer_delay,
+ const std::vector<std::vector<float>>& capture) = 0;
+
+ // Returns true if clockdrift has been detected.
+ virtual bool HasClockdrift() const = 0;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_H_
diff --git a/webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.cc b/webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.cc
new file mode 100644
index 0000000..582e033
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.cc
@@ -0,0 +1,145 @@
+/*
+ * 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/audio_processing/aec3/render_delay_controller_metrics.h"
+
+#include <algorithm>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+
+namespace {
+
+enum class DelayReliabilityCategory {
+ kNone,
+ kPoor,
+ kMedium,
+ kGood,
+ kExcellent,
+ kNumCategories
+};
+enum class DelayChangesCategory {
+ kNone,
+ kFew,
+ kSeveral,
+ kMany,
+ kConstant,
+ kNumCategories
+};
+
+constexpr int kMaxSkewShiftCount = 20;
+
+} // namespace
+
+RenderDelayControllerMetrics::RenderDelayControllerMetrics() = default;
+
+void RenderDelayControllerMetrics::Update(
+ absl::optional<size_t> delay_samples,
+ size_t buffer_delay_blocks,
+ absl::optional<int> skew_shift_blocks,
+ ClockdriftDetector::Level clockdrift) {
+ ++call_counter_;
+
+ if (!initial_update) {
+ size_t delay_blocks;
+ if (delay_samples) {
+ ++reliable_delay_estimate_counter_;
+ delay_blocks = (*delay_samples) / kBlockSize + 2;
+ } else {
+ delay_blocks = 0;
+ }
+
+ if (delay_blocks != delay_blocks_) {
+ ++delay_change_counter_;
+ delay_blocks_ = delay_blocks;
+ }
+
+ if (skew_shift_blocks) {
+ skew_shift_count_ = std::min(kMaxSkewShiftCount, skew_shift_count_);
+ }
+ } else if (++initial_call_counter_ == 5 * kNumBlocksPerSecond) {
+ initial_update = false;
+ }
+
+ if (call_counter_ == kMetricsReportingIntervalBlocks) {
+ int value_to_report = static_cast<int>(delay_blocks_);
+ value_to_report = std::min(124, value_to_report >> 1);
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.EchoPathDelay",
+ value_to_report, 0, 124, 125);
+
+ value_to_report = static_cast<int>(buffer_delay_blocks + 2);
+ value_to_report = std::min(124, value_to_report >> 1);
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.BufferDelay",
+ value_to_report, 0, 124, 125);
+
+ DelayReliabilityCategory delay_reliability;
+ if (reliable_delay_estimate_counter_ == 0) {
+ delay_reliability = DelayReliabilityCategory::kNone;
+ } else if (reliable_delay_estimate_counter_ > (call_counter_ >> 1)) {
+ delay_reliability = DelayReliabilityCategory::kExcellent;
+ } else if (reliable_delay_estimate_counter_ > 100) {
+ delay_reliability = DelayReliabilityCategory::kGood;
+ } else if (reliable_delay_estimate_counter_ > 10) {
+ delay_reliability = DelayReliabilityCategory::kMedium;
+ } else {
+ delay_reliability = DelayReliabilityCategory::kPoor;
+ }
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Audio.EchoCanceller.ReliableDelayEstimates",
+ static_cast<int>(delay_reliability),
+ static_cast<int>(DelayReliabilityCategory::kNumCategories));
+
+ DelayChangesCategory delay_changes;
+ if (delay_change_counter_ == 0) {
+ delay_changes = DelayChangesCategory::kNone;
+ } else if (delay_change_counter_ > 10) {
+ delay_changes = DelayChangesCategory::kConstant;
+ } else if (delay_change_counter_ > 5) {
+ delay_changes = DelayChangesCategory::kMany;
+ } else if (delay_change_counter_ > 2) {
+ delay_changes = DelayChangesCategory::kSeveral;
+ } else {
+ delay_changes = DelayChangesCategory::kFew;
+ }
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Audio.EchoCanceller.DelayChanges",
+ static_cast<int>(delay_changes),
+ static_cast<int>(DelayChangesCategory::kNumCategories));
+
+ RTC_HISTOGRAM_ENUMERATION(
+ "WebRTC.Audio.EchoCanceller.Clockdrift", static_cast<int>(clockdrift),
+ static_cast<int>(ClockdriftDetector::Level::kNumCategories));
+
+ metrics_reported_ = true;
+ call_counter_ = 0;
+ ResetMetrics();
+ } else {
+ metrics_reported_ = false;
+ }
+
+ if (!initial_update && ++skew_report_timer_ == 60 * kNumBlocksPerSecond) {
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MaxSkewShiftCount",
+ skew_shift_count_, 0, kMaxSkewShiftCount,
+ kMaxSkewShiftCount + 1);
+
+ skew_shift_count_ = 0;
+ skew_report_timer_ = 0;
+ }
+}
+
+void RenderDelayControllerMetrics::ResetMetrics() {
+ delay_change_counter_ = 0;
+ reliable_delay_estimate_counter_ = 0;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.h b/webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.h
new file mode 100644
index 0000000..8c527a1
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_delay_controller_metrics.h
@@ -0,0 +1,55 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_METRICS_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_METRICS_H_
+
+#include <stddef.h>
+
+#include "absl/types/optional.h"
+#include "modules/audio_processing/aec3/clockdrift_detector.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Handles the reporting of metrics for the render delay controller.
+class RenderDelayControllerMetrics {
+ public:
+ RenderDelayControllerMetrics();
+
+ // Updates the metric with new data.
+ void Update(absl::optional<size_t> delay_samples,
+ size_t buffer_delay_blocks,
+ absl::optional<int> skew_shift_blocks,
+ ClockdriftDetector::Level clockdrift);
+
+ // Returns true if the metrics have just been reported, otherwise false.
+ bool MetricsReported() { return metrics_reported_; }
+
+ private:
+ // Resets the metrics.
+ void ResetMetrics();
+
+ size_t delay_blocks_ = 0;
+ int reliable_delay_estimate_counter_ = 0;
+ int delay_change_counter_ = 0;
+ int call_counter_ = 0;
+ int skew_report_timer_ = 0;
+ int initial_call_counter_ = 0;
+ bool metrics_reported_ = false;
+ bool initial_update = true;
+ int skew_shift_count_ = 0;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RenderDelayControllerMetrics);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_DELAY_CONTROLLER_METRICS_H_
diff --git a/webrtc/modules/audio_processing/aec3/render_signal_analyzer.cc b/webrtc/modules/audio_processing/aec3/render_signal_analyzer.cc
new file mode 100644
index 0000000..f570aac
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_signal_analyzer.cc
@@ -0,0 +1,156 @@
+/*
+ * 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/audio_processing/aec3/render_signal_analyzer.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+constexpr size_t kCounterThreshold = 5;
+
+// Identifies local bands with narrow characteristics.
+void IdentifySmallNarrowBandRegions(
+ const RenderBuffer& render_buffer,
+ const absl::optional<size_t>& delay_partitions,
+ std::array<size_t, kFftLengthBy2 - 1>* narrow_band_counters) {
+ RTC_DCHECK(narrow_band_counters);
+
+ if (!delay_partitions) {
+ narrow_band_counters->fill(0);
+ return;
+ }
+
+ std::array<size_t, kFftLengthBy2 - 1> channel_counters;
+ channel_counters.fill(0);
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
+ render_buffer.Spectrum(*delay_partitions);
+ for (size_t ch = 0; ch < X2.size(); ++ch) {
+ for (size_t k = 1; k < kFftLengthBy2; ++k) {
+ if (X2[ch][k] > 3 * std::max(X2[ch][k - 1], X2[ch][k + 1])) {
+ ++channel_counters[k - 1];
+ }
+ }
+ }
+ for (size_t k = 1; k < kFftLengthBy2; ++k) {
+ (*narrow_band_counters)[k - 1] =
+ channel_counters[k - 1] > 0 ? (*narrow_band_counters)[k - 1] + 1 : 0;
+ }
+}
+
+// Identifies whether the signal has a single strong narrow-band component.
+void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer,
+ int strong_peak_freeze_duration,
+ absl::optional<int>* narrow_peak_band,
+ size_t* narrow_peak_counter) {
+ RTC_DCHECK(narrow_peak_band);
+ RTC_DCHECK(narrow_peak_counter);
+ if (*narrow_peak_band &&
+ ++(*narrow_peak_counter) >
+ static_cast<size_t>(strong_peak_freeze_duration)) {
+ *narrow_peak_band = absl::nullopt;
+ }
+
+ const std::vector<std::vector<std::vector<float>>>& x_latest =
+ render_buffer.Block(0);
+ float max_peak_level = 0.f;
+ for (size_t channel = 0; channel < x_latest[0].size(); ++channel) {
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> X2_latest =
+ render_buffer.Spectrum(0)[channel];
+
+ // Identify the spectral peak.
+ const int peak_bin =
+ static_cast<int>(std::max_element(X2_latest.begin(), X2_latest.end()) -
+ X2_latest.begin());
+
+ // Compute the level around the peak.
+ float non_peak_power = 0.f;
+ for (int k = std::max(0, peak_bin - 14); k < peak_bin - 4; ++k) {
+ non_peak_power = std::max(X2_latest[k], non_peak_power);
+ }
+ for (int k = peak_bin + 5;
+ k < std::min(peak_bin + 15, static_cast<int>(kFftLengthBy2Plus1));
+ ++k) {
+ non_peak_power = std::max(X2_latest[k], non_peak_power);
+ }
+
+ // Assess the render signal strength.
+ auto result0 = std::minmax_element(x_latest[0][channel].begin(),
+ x_latest[0][channel].end());
+ float max_abs = std::max(fabs(*result0.first), fabs(*result0.second));
+
+ if (x_latest.size() > 1) {
+ const auto result1 = std::minmax_element(x_latest[1][channel].begin(),
+ x_latest[1][channel].end());
+ max_abs =
+ std::max(max_abs, static_cast<float>(std::max(
+ fabs(*result1.first), fabs(*result1.second))));
+ }
+
+ // Detect whether the spectral peak has as strong narrowband nature.
+ const float peak_level = X2_latest[peak_bin];
+ if (peak_bin > 0 && max_abs > 100 && peak_level > 100 * non_peak_power) {
+ // Store the strongest peak across channels.
+ if (peak_level > max_peak_level) {
+ max_peak_level = peak_level;
+ *narrow_peak_band = peak_bin;
+ *narrow_peak_counter = 0;
+ }
+ }
+ }
+}
+
+} // namespace
+
+RenderSignalAnalyzer::RenderSignalAnalyzer(const EchoCanceller3Config& config)
+ : strong_peak_freeze_duration_(config.filter.refined.length_blocks) {
+ narrow_band_counters_.fill(0);
+}
+RenderSignalAnalyzer::~RenderSignalAnalyzer() = default;
+
+void RenderSignalAnalyzer::Update(
+ const RenderBuffer& render_buffer,
+ const absl::optional<size_t>& delay_partitions) {
+ // Identify bands of narrow nature.
+ IdentifySmallNarrowBandRegions(render_buffer, delay_partitions,
+ &narrow_band_counters_);
+
+ // Identify the presence of a strong narrow band.
+ IdentifyStrongNarrowBandComponent(render_buffer, strong_peak_freeze_duration_,
+ &narrow_peak_band_, &narrow_peak_counter_);
+}
+
+void RenderSignalAnalyzer::MaskRegionsAroundNarrowBands(
+ std::array<float, kFftLengthBy2Plus1>* v) const {
+ RTC_DCHECK(v);
+
+ // Set v to zero around narrow band signal regions.
+ if (narrow_band_counters_[0] > kCounterThreshold) {
+ (*v)[1] = (*v)[0] = 0.f;
+ }
+ for (size_t k = 2; k < kFftLengthBy2 - 1; ++k) {
+ if (narrow_band_counters_[k - 1] > kCounterThreshold) {
+ (*v)[k - 2] = (*v)[k - 1] = (*v)[k] = (*v)[k + 1] = (*v)[k + 2] = 0.f;
+ }
+ }
+ if (narrow_band_counters_[kFftLengthBy2 - 2] > kCounterThreshold) {
+ (*v)[kFftLengthBy2] = (*v)[kFftLengthBy2 - 1] = 0.f;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/render_signal_analyzer.h b/webrtc/modules/audio_processing/aec3/render_signal_analyzer.h
new file mode 100644
index 0000000..c7a3d8b
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/render_signal_analyzer.h
@@ -0,0 +1,62 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_RENDER_SIGNAL_ANALYZER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_RENDER_SIGNAL_ANALYZER_H_
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+
+#include "absl/types/optional.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Provides functionality for analyzing the properties of the render signal.
+class RenderSignalAnalyzer {
+ public:
+ explicit RenderSignalAnalyzer(const EchoCanceller3Config& config);
+ ~RenderSignalAnalyzer();
+
+ // Updates the render signal analysis with the most recent render signal.
+ void Update(const RenderBuffer& render_buffer,
+ const absl::optional<size_t>& delay_partitions);
+
+ // Returns true if the render signal is poorly exciting.
+ bool PoorSignalExcitation() const {
+ RTC_DCHECK_LT(2, narrow_band_counters_.size());
+ return std::any_of(narrow_band_counters_.begin(),
+ narrow_band_counters_.end(),
+ [](size_t a) { return a > 10; });
+ }
+
+ // Zeros the array around regions with narrow bands signal characteristics.
+ void MaskRegionsAroundNarrowBands(
+ std::array<float, kFftLengthBy2Plus1>* v) const;
+
+ absl::optional<int> NarrowPeakBand() const { return narrow_peak_band_; }
+
+ private:
+ const int strong_peak_freeze_duration_;
+ std::array<size_t, kFftLengthBy2 - 1> narrow_band_counters_;
+ absl::optional<int> narrow_peak_band_;
+ size_t narrow_peak_counter_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RenderSignalAnalyzer);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_RENDER_SIGNAL_ANALYZER_H_
diff --git a/webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc b/webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc
new file mode 100644
index 0000000..46db233
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc
@@ -0,0 +1,379 @@
+/*
+ * 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/audio_processing/aec3/residual_echo_estimator.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/reverb_model.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+namespace {
+
+constexpr float kDefaultTransparentModeGain = 0.f;
+
+float GetTransparentModeGain() {
+ if (field_trial::IsEnabled(
+ "WebRTC-Aec3NoSuppressionInTransparentModeKillSwitch")) {
+ return 0.01f;
+ } else {
+ return kDefaultTransparentModeGain;
+ }
+}
+
+float GetEarlyReflectionsDefaultModeGain(
+ const EchoCanceller3Config::EpStrength& config) {
+ if (field_trial::IsEnabled("WebRTC-Aec3UseLowEarlyReflectionsDefaultGain")) {
+ return 0.1f;
+ }
+ return config.default_gain;
+}
+
+float GetLateReflectionsDefaultModeGain(
+ const EchoCanceller3Config::EpStrength& config) {
+ if (field_trial::IsEnabled("WebRTC-Aec3UseLowLateReflectionsDefaultGain")) {
+ return 0.1f;
+ }
+ return config.default_gain;
+}
+
+// Computes the indexes that will be used for computing spectral power over
+// the blocks surrounding the delay.
+void GetRenderIndexesToAnalyze(
+ const SpectrumBuffer& spectrum_buffer,
+ const EchoCanceller3Config::EchoModel& echo_model,
+ int filter_delay_blocks,
+ int* idx_start,
+ int* idx_stop) {
+ RTC_DCHECK(idx_start);
+ RTC_DCHECK(idx_stop);
+ size_t window_start;
+ size_t window_end;
+ window_start =
+ std::max(0, filter_delay_blocks -
+ static_cast<int>(echo_model.render_pre_window_size));
+ window_end = filter_delay_blocks +
+ static_cast<int>(echo_model.render_post_window_size);
+ *idx_start = spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start);
+ *idx_stop = spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1);
+}
+
+// Estimates the residual echo power based on the echo return loss enhancement
+// (ERLE) and the linear power estimate.
+void LinearEstimate(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> S2_linear,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> erle,
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2) {
+ RTC_DCHECK_EQ(S2_linear.size(), erle.size());
+ RTC_DCHECK_EQ(S2_linear.size(), R2.size());
+
+ const size_t num_capture_channels = R2.size();
+ for (size_t ch = 0; ch < num_capture_channels; ++ch) {
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ RTC_DCHECK_LT(0.f, erle[ch][k]);
+ R2[ch][k] = S2_linear[ch][k] / erle[ch][k];
+ }
+ }
+}
+
+// Estimates the residual echo power based on an uncertainty estimate of the
+// echo return loss enhancement (ERLE) and the linear power estimate.
+void LinearEstimate(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> S2_linear,
+ float erle_uncertainty,
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2) {
+ RTC_DCHECK_EQ(S2_linear.size(), R2.size());
+
+ const size_t num_capture_channels = R2.size();
+ for (size_t ch = 0; ch < num_capture_channels; ++ch) {
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ R2[ch][k] = S2_linear[ch][k] * erle_uncertainty;
+ }
+ }
+}
+
+// Estimates the residual echo power based on the estimate of the echo path
+// gain.
+void NonLinearEstimate(
+ float echo_path_gain,
+ const std::array<float, kFftLengthBy2Plus1>& X2,
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2) {
+ const size_t num_capture_channels = R2.size();
+ for (size_t ch = 0; ch < num_capture_channels; ++ch) {
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ R2[ch][k] = X2[k] * echo_path_gain;
+ }
+ }
+}
+
+// Applies a soft noise gate to the echo generating power.
+void ApplyNoiseGate(const EchoCanceller3Config::EchoModel& config,
+ rtc::ArrayView<float, kFftLengthBy2Plus1> X2) {
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ if (config.noise_gate_power > X2[k]) {
+ X2[k] = std::max(0.f, X2[k] - config.noise_gate_slope *
+ (config.noise_gate_power - X2[k]));
+ }
+ }
+}
+
+// Estimates the echo generating signal power as gated maximal power over a
+// time window.
+void EchoGeneratingPower(size_t num_render_channels,
+ const SpectrumBuffer& spectrum_buffer,
+ const EchoCanceller3Config::EchoModel& echo_model,
+ int filter_delay_blocks,
+ rtc::ArrayView<float, kFftLengthBy2Plus1> X2) {
+ int idx_stop;
+ int idx_start;
+ GetRenderIndexesToAnalyze(spectrum_buffer, echo_model, filter_delay_blocks,
+ &idx_start, &idx_stop);
+
+ std::fill(X2.begin(), X2.end(), 0.f);
+ if (num_render_channels == 1) {
+ for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) {
+ for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) {
+ X2[j] = std::max(X2[j], spectrum_buffer.buffer[k][/*channel=*/0][j]);
+ }
+ }
+ } else {
+ for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) {
+ std::array<float, kFftLengthBy2Plus1> render_power;
+ render_power.fill(0.f);
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const auto& channel_power = spectrum_buffer.buffer[k][ch];
+ for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) {
+ render_power[j] += channel_power[j];
+ }
+ }
+ for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) {
+ X2[j] = std::max(X2[j], render_power[j]);
+ }
+ }
+ }
+}
+
+} // namespace
+
+ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config,
+ size_t num_render_channels)
+ : config_(config),
+ num_render_channels_(num_render_channels),
+ early_reflections_transparent_mode_gain_(GetTransparentModeGain()),
+ late_reflections_transparent_mode_gain_(GetTransparentModeGain()),
+ early_reflections_general_gain_(
+ GetEarlyReflectionsDefaultModeGain(config_.ep_strength)),
+ late_reflections_general_gain_(
+ GetLateReflectionsDefaultModeGain(config_.ep_strength)) {
+ Reset();
+}
+
+ResidualEchoEstimator::~ResidualEchoEstimator() = default;
+
+void ResidualEchoEstimator::Estimate(
+ const AecState& aec_state,
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> S2_linear,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2) {
+ RTC_DCHECK_EQ(R2.size(), Y2.size());
+ RTC_DCHECK_EQ(R2.size(), S2_linear.size());
+
+ const size_t num_capture_channels = R2.size();
+
+ // Estimate the power of the stationary noise in the render signal.
+ UpdateRenderNoisePower(render_buffer);
+
+ // Estimate the residual echo power.
+ if (aec_state.UsableLinearEstimate()) {
+ // When there is saturated echo, assume the same spectral content as is
+ // present in the microphone signal.
+ if (aec_state.SaturatedEcho()) {
+ for (size_t ch = 0; ch < num_capture_channels; ++ch) {
+ std::copy(Y2[ch].begin(), Y2[ch].end(), R2[ch].begin());
+ }
+ } else {
+ absl::optional<float> erle_uncertainty = aec_state.ErleUncertainty();
+ if (erle_uncertainty) {
+ LinearEstimate(S2_linear, *erle_uncertainty, R2);
+ } else {
+ LinearEstimate(S2_linear, aec_state.Erle(), R2);
+ }
+ }
+
+ AddReverb(ReverbType::kLinear, aec_state, render_buffer, R2);
+ } else {
+ const float echo_path_gain =
+ GetEchoPathGain(aec_state, /*gain_for_early_reflections=*/true);
+
+ // When there is saturated echo, assume the same spectral content as is
+ // present in the microphone signal.
+ if (aec_state.SaturatedEcho()) {
+ for (size_t ch = 0; ch < num_capture_channels; ++ch) {
+ std::copy(Y2[ch].begin(), Y2[ch].end(), R2[ch].begin());
+ }
+ } else {
+ // Estimate the echo generating signal power.
+ std::array<float, kFftLengthBy2Plus1> X2;
+ EchoGeneratingPower(num_render_channels_,
+ render_buffer.GetSpectrumBuffer(), config_.echo_model,
+ aec_state.MinDirectPathFilterDelay(), X2);
+ if (!aec_state.UseStationarityProperties()) {
+ ApplyNoiseGate(config_.echo_model, X2);
+ }
+
+ // Subtract the stationary noise power to avoid stationary noise causing
+ // excessive echo suppression.
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ X2[k] -= config_.echo_model.stationary_gate_slope * X2_noise_floor_[k];
+ X2[k] = std::max(0.f, X2[k]);
+ }
+
+ NonLinearEstimate(echo_path_gain, X2, R2);
+ }
+
+ if (config_.echo_model.model_reverb_in_nonlinear_mode &&
+ !aec_state.TransparentModeActive()) {
+ AddReverb(ReverbType::kNonLinear, aec_state, render_buffer, R2);
+ }
+ }
+
+ if (aec_state.UseStationarityProperties()) {
+ // Scale the echo according to echo audibility.
+ std::array<float, kFftLengthBy2Plus1> residual_scaling;
+ aec_state.GetResidualEchoScaling(residual_scaling);
+ for (size_t ch = 0; ch < num_capture_channels; ++ch) {
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ R2[ch][k] *= residual_scaling[k];
+ }
+ }
+ }
+}
+
+void ResidualEchoEstimator::Reset() {
+ echo_reverb_.Reset();
+ X2_noise_floor_counter_.fill(config_.echo_model.noise_floor_hold);
+ X2_noise_floor_.fill(config_.echo_model.min_noise_floor_power);
+}
+
+void ResidualEchoEstimator::UpdateRenderNoisePower(
+ const RenderBuffer& render_buffer) {
+ std::array<float, kFftLengthBy2Plus1> render_power_data;
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
+ render_buffer.Spectrum(0);
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> render_power =
+ X2[/*channel=*/0];
+ if (num_render_channels_ > 1) {
+ render_power_data.fill(0.f);
+ for (size_t ch = 0; ch < num_render_channels_; ++ch) {
+ const auto& channel_power = X2[ch];
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ render_power_data[k] += channel_power[k];
+ }
+ }
+ render_power = render_power_data;
+ }
+
+ // Estimate the stationary noise power in a minimum statistics manner.
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ // Decrease rapidly.
+ if (render_power[k] < X2_noise_floor_[k]) {
+ X2_noise_floor_[k] = render_power[k];
+ X2_noise_floor_counter_[k] = 0;
+ } else {
+ // Increase in a delayed, leaky manner.
+ if (X2_noise_floor_counter_[k] >=
+ static_cast<int>(config_.echo_model.noise_floor_hold)) {
+ X2_noise_floor_[k] = std::max(X2_noise_floor_[k] * 1.1f,
+ config_.echo_model.min_noise_floor_power);
+ } else {
+ ++X2_noise_floor_counter_[k];
+ }
+ }
+ }
+}
+
+// Adds the estimated power of the reverb to the residual echo power.
+void ResidualEchoEstimator::AddReverb(
+ ReverbType reverb_type,
+ const AecState& aec_state,
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2) {
+ const size_t num_capture_channels = R2.size();
+
+ // Choose reverb partition based on what type of echo power model is used.
+ const size_t first_reverb_partition =
+ reverb_type == ReverbType::kLinear
+ ? aec_state.FilterLengthBlocks() + 1
+ : aec_state.MinDirectPathFilterDelay() + 1;
+
+ // Compute render power for the reverb.
+ std::array<float, kFftLengthBy2Plus1> render_power_data;
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> X2 =
+ render_buffer.Spectrum(first_reverb_partition);
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> render_power =
+ X2[/*channel=*/0];
+ if (num_render_channels_ > 1) {
+ render_power_data.fill(0.f);
+ for (size_t ch = 0; ch < num_render_channels_; ++ch) {
+ const auto& channel_power = X2[ch];
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ render_power_data[k] += channel_power[k];
+ }
+ }
+ render_power = render_power_data;
+ }
+
+ // Update the reverb estimate.
+ if (reverb_type == ReverbType::kLinear) {
+ echo_reverb_.UpdateReverb(render_power,
+ aec_state.GetReverbFrequencyResponse(),
+ aec_state.ReverbDecay());
+ } else {
+ const float echo_path_gain =
+ GetEchoPathGain(aec_state, /*gain_for_early_reflections=*/false);
+ echo_reverb_.UpdateReverbNoFreqShaping(render_power, echo_path_gain,
+ aec_state.ReverbDecay());
+ }
+
+ // Add the reverb power.
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> reverb_power =
+ echo_reverb_.reverb();
+ for (size_t ch = 0; ch < num_capture_channels; ++ch) {
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ R2[ch][k] += reverb_power[k];
+ }
+ }
+}
+
+// Chooses the echo path gain to use.
+float ResidualEchoEstimator::GetEchoPathGain(
+ const AecState& aec_state,
+ bool gain_for_early_reflections) const {
+ float gain_amplitude;
+ if (aec_state.TransparentModeActive()) {
+ gain_amplitude = gain_for_early_reflections
+ ? early_reflections_transparent_mode_gain_
+ : late_reflections_transparent_mode_gain_;
+ } else {
+ gain_amplitude = gain_for_early_reflections
+ ? early_reflections_general_gain_
+ : late_reflections_general_gain_;
+ }
+ return gain_amplitude * gain_amplitude;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/residual_echo_estimator.h b/webrtc/modules/audio_processing/aec3/residual_echo_estimator.h
new file mode 100644
index 0000000..8fe7a84
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/residual_echo_estimator.h
@@ -0,0 +1,78 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_RESIDUAL_ECHO_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_RESIDUAL_ECHO_ESTIMATOR_H_
+
+#include <array>
+#include <memory>
+
+#include "absl/types/optional.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec_state.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/reverb_model.h"
+#include "modules/audio_processing/aec3/spectrum_buffer.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+class ResidualEchoEstimator {
+ public:
+ ResidualEchoEstimator(const EchoCanceller3Config& config,
+ size_t num_render_channels);
+ ~ResidualEchoEstimator();
+
+ ResidualEchoEstimator(const ResidualEchoEstimator&) = delete;
+ ResidualEchoEstimator& operator=(const ResidualEchoEstimator&) = delete;
+
+ void Estimate(
+ const AecState& aec_state,
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> S2_linear,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2);
+
+ private:
+ enum class ReverbType { kLinear, kNonLinear };
+
+ // Resets the state.
+ void Reset();
+
+ // Updates estimate for the power of the stationary noise component in the
+ // render signal.
+ void UpdateRenderNoisePower(const RenderBuffer& render_buffer);
+
+ // Adds the estimated unmodelled echo power to the residual echo power
+ // estimate.
+ void AddReverb(ReverbType reverb_type,
+ const AecState& aec_state,
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2);
+
+ // Gets the echo path gain to apply.
+ float GetEchoPathGain(const AecState& aec_state,
+ bool gain_for_early_reflections) const;
+
+ const EchoCanceller3Config config_;
+ const size_t num_render_channels_;
+ const float early_reflections_transparent_mode_gain_;
+ const float late_reflections_transparent_mode_gain_;
+ const float early_reflections_general_gain_;
+ const float late_reflections_general_gain_;
+ std::array<float, kFftLengthBy2Plus1> X2_noise_floor_;
+ std::array<int, kFftLengthBy2Plus1> X2_noise_floor_counter_;
+ ReverbModel echo_reverb_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_RESIDUAL_ECHO_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/reverb_decay_estimator.cc b/webrtc/modules/audio_processing/aec3/reverb_decay_estimator.cc
new file mode 100644
index 0000000..f160b83
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/reverb_decay_estimator.cc
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/reverb_decay_estimator.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <cmath>
+#include <numeric>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr int kEarlyReverbMinSizeBlocks = 3;
+constexpr int kBlocksPerSection = 6;
+// Linear regression approach assumes symmetric index around 0.
+constexpr float kEarlyReverbFirstPointAtLinearRegressors =
+ -0.5f * kBlocksPerSection * kFftLengthBy2 + 0.5f;
+
+// Averages the values in a block of size kFftLengthBy2;
+float BlockAverage(rtc::ArrayView<const float> v, size_t block_index) {
+ constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2;
+ const int i = block_index * kFftLengthBy2;
+ RTC_DCHECK_GE(v.size(), i + kFftLengthBy2);
+ const float sum =
+ std::accumulate(v.begin() + i, v.begin() + i + kFftLengthBy2, 0.f);
+ return sum * kOneByFftLengthBy2;
+}
+
+// Analyzes the gain in a block.
+void AnalyzeBlockGain(const std::array<float, kFftLengthBy2>& h2,
+ float floor_gain,
+ float* previous_gain,
+ bool* block_adapting,
+ bool* decaying_gain) {
+ float gain = std::max(BlockAverage(h2, 0), 1e-32f);
+ *block_adapting =
+ *previous_gain > 1.1f * gain || *previous_gain < 0.9f * gain;
+ *decaying_gain = gain > floor_gain;
+ *previous_gain = gain;
+}
+
+// Arithmetic sum of $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly.
+constexpr float SymmetricArithmetricSum(int N) {
+ return N * (N * N - 1.0f) * (1.f / 12.f);
+}
+
+// Returns the peak energy of an impulse response.
+float BlockEnergyPeak(rtc::ArrayView<const float> h, int peak_block) {
+ RTC_DCHECK_LE((peak_block + 1) * kFftLengthBy2, h.size());
+ RTC_DCHECK_GE(peak_block, 0);
+ float peak_value =
+ *std::max_element(h.begin() + peak_block * kFftLengthBy2,
+ h.begin() + (peak_block + 1) * kFftLengthBy2,
+ [](float a, float b) { return a * a < b * b; });
+ return peak_value * peak_value;
+}
+
+// Returns the average energy of an impulse response block.
+float BlockEnergyAverage(rtc::ArrayView<const float> h, int block_index) {
+ RTC_DCHECK_LE((block_index + 1) * kFftLengthBy2, h.size());
+ RTC_DCHECK_GE(block_index, 0);
+ constexpr float kOneByFftLengthBy2 = 1.f / kFftLengthBy2;
+ const auto sum_of_squares = [](float a, float b) { return a + b * b; };
+ return std::accumulate(h.begin() + block_index * kFftLengthBy2,
+ h.begin() + (block_index + 1) * kFftLengthBy2, 0.f,
+ sum_of_squares) *
+ kOneByFftLengthBy2;
+}
+
+} // namespace
+
+ReverbDecayEstimator::ReverbDecayEstimator(const EchoCanceller3Config& config)
+ : filter_length_blocks_(config.filter.refined.length_blocks),
+ filter_length_coefficients_(GetTimeDomainLength(filter_length_blocks_)),
+ use_adaptive_echo_decay_(config.ep_strength.default_len < 0.f),
+ early_reverb_estimator_(config.filter.refined.length_blocks -
+ kEarlyReverbMinSizeBlocks),
+ late_reverb_start_(kEarlyReverbMinSizeBlocks),
+ late_reverb_end_(kEarlyReverbMinSizeBlocks),
+ previous_gains_(config.filter.refined.length_blocks, 0.f),
+ decay_(std::fabs(config.ep_strength.default_len)) {
+ RTC_DCHECK_GT(config.filter.refined.length_blocks,
+ static_cast<size_t>(kEarlyReverbMinSizeBlocks));
+}
+
+ReverbDecayEstimator::~ReverbDecayEstimator() = default;
+
+void ReverbDecayEstimator::Update(rtc::ArrayView<const float> filter,
+ const absl::optional<float>& filter_quality,
+ int filter_delay_blocks,
+ bool usable_linear_filter,
+ bool stationary_signal) {
+ const int filter_size = static_cast<int>(filter.size());
+
+ if (stationary_signal) {
+ return;
+ }
+
+ bool estimation_feasible =
+ filter_delay_blocks <=
+ filter_length_blocks_ - kEarlyReverbMinSizeBlocks - 1;
+ estimation_feasible =
+ estimation_feasible && filter_size == filter_length_coefficients_;
+ estimation_feasible = estimation_feasible && filter_delay_blocks > 0;
+ estimation_feasible = estimation_feasible && usable_linear_filter;
+
+ if (!estimation_feasible) {
+ ResetDecayEstimation();
+ return;
+ }
+
+ if (!use_adaptive_echo_decay_) {
+ return;
+ }
+
+ const float new_smoothing = filter_quality ? *filter_quality * 0.2f : 0.f;
+ smoothing_constant_ = std::max(new_smoothing, smoothing_constant_);
+ if (smoothing_constant_ == 0.f) {
+ return;
+ }
+
+ if (block_to_analyze_ < filter_length_blocks_) {
+ // Analyze the filter and accumulate data for reverb estimation.
+ AnalyzeFilter(filter);
+ ++block_to_analyze_;
+ } else {
+ // When the filter is fully analyzed, estimate the reverb decay and reset
+ // the block_to_analyze_ counter.
+ EstimateDecay(filter, filter_delay_blocks);
+ }
+}
+
+void ReverbDecayEstimator::ResetDecayEstimation() {
+ early_reverb_estimator_.Reset();
+ late_reverb_decay_estimator_.Reset(0);
+ block_to_analyze_ = 0;
+ estimation_region_candidate_size_ = 0;
+ estimation_region_identified_ = false;
+ smoothing_constant_ = 0.f;
+ late_reverb_start_ = 0;
+ late_reverb_end_ = 0;
+}
+
+void ReverbDecayEstimator::EstimateDecay(rtc::ArrayView<const float> filter,
+ int peak_block) {
+ auto& h = filter;
+ RTC_DCHECK_EQ(0, h.size() % kFftLengthBy2);
+
+ // Reset the block analysis counter.
+ block_to_analyze_ =
+ std::min(peak_block + kEarlyReverbMinSizeBlocks, filter_length_blocks_);
+
+ // To estimate the reverb decay, the energy of the first filter section must
+ // be substantially larger than the last. Also, the first filter section
+ // energy must not deviate too much from the max peak.
+ const float first_reverb_gain = BlockEnergyAverage(h, block_to_analyze_);
+ const size_t h_size_blocks = h.size() >> kFftLengthBy2Log2;
+ tail_gain_ = BlockEnergyAverage(h, h_size_blocks - 1);
+ float peak_energy = BlockEnergyPeak(h, peak_block);
+ const bool sufficient_reverb_decay = first_reverb_gain > 4.f * tail_gain_;
+ const bool valid_filter =
+ first_reverb_gain > 2.f * tail_gain_ && peak_energy < 100.f;
+
+ // Estimate the size of the regions with early and late reflections.
+ const int size_early_reverb = early_reverb_estimator_.Estimate();
+ const int size_late_reverb =
+ std::max(estimation_region_candidate_size_ - size_early_reverb, 0);
+
+ // Only update the reverb decay estimate if the size of the identified late
+ // reverb is sufficiently large.
+ if (size_late_reverb >= 5) {
+ if (valid_filter && late_reverb_decay_estimator_.EstimateAvailable()) {
+ float decay = std::pow(
+ 2.0f, late_reverb_decay_estimator_.Estimate() * kFftLengthBy2);
+ constexpr float kMaxDecay = 0.95f; // ~1 sec min RT60.
+ constexpr float kMinDecay = 0.02f; // ~15 ms max RT60.
+ decay = std::max(.97f * decay_, decay);
+ decay = std::min(decay, kMaxDecay);
+ decay = std::max(decay, kMinDecay);
+ decay_ += smoothing_constant_ * (decay - decay_);
+ }
+
+ // Update length of decay. Must have enough data (number of sections) in
+ // order to estimate decay rate.
+ late_reverb_decay_estimator_.Reset(size_late_reverb * kFftLengthBy2);
+ late_reverb_start_ =
+ peak_block + kEarlyReverbMinSizeBlocks + size_early_reverb;
+ late_reverb_end_ =
+ block_to_analyze_ + estimation_region_candidate_size_ - 1;
+ } else {
+ late_reverb_decay_estimator_.Reset(0);
+ late_reverb_start_ = 0;
+ late_reverb_end_ = 0;
+ }
+
+ // Reset variables for the identification of the region for reverb decay
+ // estimation.
+ estimation_region_identified_ = !(valid_filter && sufficient_reverb_decay);
+ estimation_region_candidate_size_ = 0;
+
+ // Stop estimation of the decay until another good filter is received.
+ smoothing_constant_ = 0.f;
+
+ // Reset early reflections detector.
+ early_reverb_estimator_.Reset();
+}
+
+void ReverbDecayEstimator::AnalyzeFilter(rtc::ArrayView<const float> filter) {
+ auto h = rtc::ArrayView<const float>(
+ filter.begin() + block_to_analyze_ * kFftLengthBy2, kFftLengthBy2);
+
+ // Compute squared filter coeffiecients for the block to analyze_;
+ std::array<float, kFftLengthBy2> h2;
+ std::transform(h.begin(), h.end(), h2.begin(), [](float a) { return a * a; });
+
+ // Map out the region for estimating the reverb decay.
+ bool adapting;
+ bool above_noise_floor;
+ AnalyzeBlockGain(h2, tail_gain_, &previous_gains_[block_to_analyze_],
+ &adapting, &above_noise_floor);
+
+ // Count consecutive number of "good" filter sections, where "good" means:
+ // 1) energy is above noise floor.
+ // 2) energy of current section has not changed too much from last check.
+ estimation_region_identified_ =
+ estimation_region_identified_ || adapting || !above_noise_floor;
+ if (!estimation_region_identified_) {
+ ++estimation_region_candidate_size_;
+ }
+
+ // Accumulate data for reverb decay estimation and for the estimation of early
+ // reflections.
+ if (block_to_analyze_ <= late_reverb_end_) {
+ if (block_to_analyze_ >= late_reverb_start_) {
+ for (float h2_k : h2) {
+ float h2_log2 = FastApproxLog2f(h2_k + 1e-10);
+ late_reverb_decay_estimator_.Accumulate(h2_log2);
+ early_reverb_estimator_.Accumulate(h2_log2, smoothing_constant_);
+ }
+ } else {
+ for (float h2_k : h2) {
+ float h2_log2 = FastApproxLog2f(h2_k + 1e-10);
+ early_reverb_estimator_.Accumulate(h2_log2, smoothing_constant_);
+ }
+ }
+ }
+}
+
+void ReverbDecayEstimator::Dump(ApmDataDumper* data_dumper) const {
+ data_dumper->DumpRaw("aec3_reverb_decay", decay_);
+ data_dumper->DumpRaw("aec3_reverb_tail_energy", tail_gain_);
+ data_dumper->DumpRaw("aec3_reverb_alpha", smoothing_constant_);
+ data_dumper->DumpRaw("aec3_num_reverb_decay_blocks",
+ late_reverb_end_ - late_reverb_start_);
+ data_dumper->DumpRaw("aec3_late_reverb_start", late_reverb_start_);
+ data_dumper->DumpRaw("aec3_late_reverb_end", late_reverb_end_);
+ early_reverb_estimator_.Dump(data_dumper);
+}
+
+void ReverbDecayEstimator::LateReverbLinearRegressor::Reset(
+ int num_data_points) {
+ RTC_DCHECK_LE(0, num_data_points);
+ RTC_DCHECK_EQ(0, num_data_points % 2);
+ const int N = num_data_points;
+ nz_ = 0.f;
+ // Arithmetic sum of $2 \sum_{i=0.5}^{(N-1)/2}i^2$ calculated directly.
+ nn_ = SymmetricArithmetricSum(N);
+ // The linear regression approach assumes symmetric index around 0.
+ count_ = N > 0 ? -N * 0.5f + 0.5f : 0.f;
+ N_ = N;
+ n_ = 0;
+}
+
+void ReverbDecayEstimator::LateReverbLinearRegressor::Accumulate(float z) {
+ nz_ += count_ * z;
+ ++count_;
+ ++n_;
+}
+
+float ReverbDecayEstimator::LateReverbLinearRegressor::Estimate() {
+ RTC_DCHECK(EstimateAvailable());
+ if (nn_ == 0.f) {
+ RTC_NOTREACHED();
+ return 0.f;
+ }
+ return nz_ / nn_;
+}
+
+ReverbDecayEstimator::EarlyReverbLengthEstimator::EarlyReverbLengthEstimator(
+ int max_blocks)
+ : numerators_smooth_(max_blocks - kBlocksPerSection, 0.f),
+ numerators_(numerators_smooth_.size(), 0.f),
+ coefficients_counter_(0) {
+ RTC_DCHECK_LE(0, max_blocks);
+}
+
+ReverbDecayEstimator::EarlyReverbLengthEstimator::
+ ~EarlyReverbLengthEstimator() = default;
+
+void ReverbDecayEstimator::EarlyReverbLengthEstimator::Reset() {
+ coefficients_counter_ = 0;
+ std::fill(numerators_.begin(), numerators_.end(), 0.f);
+ block_counter_ = 0;
+}
+
+void ReverbDecayEstimator::EarlyReverbLengthEstimator::Accumulate(
+ float value,
+ float smoothing) {
+ // Each section is composed by kBlocksPerSection blocks and each section
+ // overlaps with the next one in (kBlocksPerSection - 1) blocks. For example,
+ // the first section covers the blocks [0:5], the second covers the blocks
+ // [1:6] and so on. As a result, for each value, kBlocksPerSection sections
+ // need to be updated.
+ int first_section_index = std::max(block_counter_ - kBlocksPerSection + 1, 0);
+ int last_section_index =
+ std::min(block_counter_, static_cast<int>(numerators_.size() - 1));
+ float x_value = static_cast<float>(coefficients_counter_) +
+ kEarlyReverbFirstPointAtLinearRegressors;
+ const float value_to_inc = kFftLengthBy2 * value;
+ float value_to_add =
+ x_value * value + (block_counter_ - last_section_index) * value_to_inc;
+ for (int section = last_section_index; section >= first_section_index;
+ --section, value_to_add += value_to_inc) {
+ numerators_[section] += value_to_add;
+ }
+
+ // Check if this update was the last coefficient of the current block. In that
+ // case, check if we are at the end of one of the sections and update the
+ // numerator of the linear regressor that is computed in such section.
+ if (++coefficients_counter_ == kFftLengthBy2) {
+ if (block_counter_ >= (kBlocksPerSection - 1)) {
+ size_t section = block_counter_ - (kBlocksPerSection - 1);
+ RTC_DCHECK_GT(numerators_.size(), section);
+ RTC_DCHECK_GT(numerators_smooth_.size(), section);
+ numerators_smooth_[section] +=
+ smoothing * (numerators_[section] - numerators_smooth_[section]);
+ n_sections_ = section + 1;
+ }
+ ++block_counter_;
+ coefficients_counter_ = 0;
+ }
+}
+
+// Estimates the size in blocks of the early reverb. The estimation is done by
+// comparing the tilt that is estimated in each section. As an optimization
+// detail and due to the fact that all the linear regressors that are computed
+// shared the same denominator, the comparison of the tilts is done by a
+// comparison of the numerator of the linear regressors.
+int ReverbDecayEstimator::EarlyReverbLengthEstimator::Estimate() {
+ constexpr float N = kBlocksPerSection * kFftLengthBy2;
+ constexpr float nn = SymmetricArithmetricSum(N);
+ // numerator_11 refers to the quantity that the linear regressor needs in the
+ // numerator for getting a decay equal to 1.1 (which is not a decay).
+ // log2(1.1) * nn / kFftLengthBy2.
+ constexpr float numerator_11 = 0.13750352374993502f * nn / kFftLengthBy2;
+ // log2(0.8) * nn / kFftLengthBy2.
+ constexpr float numerator_08 = -0.32192809488736229f * nn / kFftLengthBy2;
+ constexpr int kNumSectionsToAnalyze = 9;
+
+ if (n_sections_ < kNumSectionsToAnalyze) {
+ return 0;
+ }
+
+ // Estimation of the blocks that correspond to early reverberations. The
+ // estimation is done by analyzing the impulse response. The portions of the
+ // impulse response whose energy is not decreasing over its coefficients are
+ // considered to be part of the early reverberations. Furthermore, the blocks
+ // where the energy is decreasing faster than what it does at the end of the
+ // impulse response are also considered to be part of the early
+ // reverberations. The estimation is limited to the first
+ // kNumSectionsToAnalyze sections.
+
+ RTC_DCHECK_LE(n_sections_, numerators_smooth_.size());
+ const float min_numerator_tail =
+ *std::min_element(numerators_smooth_.begin() + kNumSectionsToAnalyze,
+ numerators_smooth_.begin() + n_sections_);
+ int early_reverb_size_minus_1 = 0;
+ for (int k = 0; k < kNumSectionsToAnalyze; ++k) {
+ if ((numerators_smooth_[k] > numerator_11) ||
+ (numerators_smooth_[k] < numerator_08 &&
+ numerators_smooth_[k] < 0.9f * min_numerator_tail)) {
+ early_reverb_size_minus_1 = k;
+ }
+ }
+
+ return early_reverb_size_minus_1 == 0 ? 0 : early_reverb_size_minus_1 + 1;
+}
+
+void ReverbDecayEstimator::EarlyReverbLengthEstimator::Dump(
+ ApmDataDumper* data_dumper) const {
+ data_dumper->DumpRaw("aec3_er_acum_numerator", numerators_smooth_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/reverb_decay_estimator.h b/webrtc/modules/audio_processing/aec3/reverb_decay_estimator.h
new file mode 100644
index 0000000..3bb9b2b
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/reverb_decay_estimator.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_REVERB_DECAY_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_REVERB_DECAY_ESTIMATOR_H_
+
+#include <array>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h" // kMaxAdaptiveFilter...
+
+namespace webrtc {
+
+class ApmDataDumper;
+struct EchoCanceller3Config;
+
+// Class for estimating the decay of the late reverb.
+class ReverbDecayEstimator {
+ public:
+ explicit ReverbDecayEstimator(const EchoCanceller3Config& config);
+ ~ReverbDecayEstimator();
+ // Updates the decay estimate.
+ void Update(rtc::ArrayView<const float> filter,
+ const absl::optional<float>& filter_quality,
+ int filter_delay_blocks,
+ bool usable_linear_filter,
+ bool stationary_signal);
+ // Returns the decay for the exponential model.
+ float Decay() const { return decay_; }
+ // Dumps debug data.
+ void Dump(ApmDataDumper* data_dumper) const;
+
+ private:
+ void EstimateDecay(rtc::ArrayView<const float> filter, int peak_block);
+ void AnalyzeFilter(rtc::ArrayView<const float> filter);
+
+ void ResetDecayEstimation();
+
+ // Class for estimating the decay of the late reverb from the linear filter.
+ class LateReverbLinearRegressor {
+ public:
+ // Resets the estimator to receive a specified number of data points.
+ void Reset(int num_data_points);
+ // Accumulates estimation data.
+ void Accumulate(float z);
+ // Estimates the decay.
+ float Estimate();
+ // Returns whether an estimate is available.
+ bool EstimateAvailable() const { return n_ == N_ && N_ != 0; }
+
+ public:
+ float nz_ = 0.f;
+ float nn_ = 0.f;
+ float count_ = 0.f;
+ int N_ = 0;
+ int n_ = 0;
+ };
+
+ // Class for identifying the length of the early reverb from the linear
+ // filter. For identifying the early reverberations, the impulse response is
+ // divided in sections and the tilt of each section is computed by a linear
+ // regressor.
+ class EarlyReverbLengthEstimator {
+ public:
+ explicit EarlyReverbLengthEstimator(int max_blocks);
+ ~EarlyReverbLengthEstimator();
+
+ // Resets the estimator.
+ void Reset();
+ // Accumulates estimation data.
+ void Accumulate(float value, float smoothing);
+ // Estimates the size in blocks of the early reverb.
+ int Estimate();
+ // Dumps debug data.
+ void Dump(ApmDataDumper* data_dumper) const;
+
+ private:
+ std::vector<float> numerators_smooth_;
+ std::vector<float> numerators_;
+ int coefficients_counter_;
+ int block_counter_ = 0;
+ int n_sections_ = 0;
+ };
+
+ const int filter_length_blocks_;
+ const int filter_length_coefficients_;
+ const bool use_adaptive_echo_decay_;
+ LateReverbLinearRegressor late_reverb_decay_estimator_;
+ EarlyReverbLengthEstimator early_reverb_estimator_;
+ int late_reverb_start_;
+ int late_reverb_end_;
+ int block_to_analyze_ = 0;
+ int estimation_region_candidate_size_ = 0;
+ bool estimation_region_identified_ = false;
+ std::vector<float> previous_gains_;
+ float decay_;
+ float tail_gain_ = 0.f;
+ float smoothing_constant_ = 0.f;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_REVERB_DECAY_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/reverb_frequency_response.cc b/webrtc/modules/audio_processing/aec3/reverb_frequency_response.cc
new file mode 100644
index 0000000..f4bd91f
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/reverb_frequency_response.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/reverb_frequency_response.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <array>
+#include <numeric>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Computes the ratio of the energies between the direct path and the tail. The
+// energy is computed in the power spectrum domain discarding the DC
+// contributions.
+float AverageDecayWithinFilter(
+ rtc::ArrayView<const float> freq_resp_direct_path,
+ rtc::ArrayView<const float> freq_resp_tail) {
+ // Skipping the DC for the ratio computation
+ constexpr size_t kSkipBins = 1;
+ RTC_CHECK_EQ(freq_resp_direct_path.size(), freq_resp_tail.size());
+
+ float direct_path_energy =
+ std::accumulate(freq_resp_direct_path.begin() + kSkipBins,
+ freq_resp_direct_path.end(), 0.f);
+
+ if (direct_path_energy == 0.f) {
+ return 0.f;
+ }
+
+ float tail_energy = std::accumulate(freq_resp_tail.begin() + kSkipBins,
+ freq_resp_tail.end(), 0.f);
+ return tail_energy / direct_path_energy;
+}
+
+} // namespace
+
+ReverbFrequencyResponse::ReverbFrequencyResponse() {
+ tail_response_.fill(0.f);
+}
+ReverbFrequencyResponse::~ReverbFrequencyResponse() = default;
+
+void ReverbFrequencyResponse::Update(
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+ frequency_response,
+ int filter_delay_blocks,
+ const absl::optional<float>& linear_filter_quality,
+ bool stationary_block) {
+ if (stationary_block || !linear_filter_quality) {
+ return;
+ }
+
+ Update(frequency_response, filter_delay_blocks, *linear_filter_quality);
+}
+
+void ReverbFrequencyResponse::Update(
+ const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+ frequency_response,
+ int filter_delay_blocks,
+ float linear_filter_quality) {
+ rtc::ArrayView<const float> freq_resp_tail(
+ frequency_response[frequency_response.size() - 1]);
+
+ rtc::ArrayView<const float> freq_resp_direct_path(
+ frequency_response[filter_delay_blocks]);
+
+ float average_decay =
+ AverageDecayWithinFilter(freq_resp_direct_path, freq_resp_tail);
+
+ const float smoothing = 0.2f * linear_filter_quality;
+ average_decay_ += smoothing * (average_decay - average_decay_);
+
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ tail_response_[k] = freq_resp_direct_path[k] * average_decay_;
+ }
+
+ for (size_t k = 1; k < kFftLengthBy2; ++k) {
+ const float avg_neighbour =
+ 0.5f * (tail_response_[k - 1] + tail_response_[k + 1]);
+ tail_response_[k] = std::max(tail_response_[k], avg_neighbour);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/reverb_frequency_response.h b/webrtc/modules/audio_processing/aec3/reverb_frequency_response.h
new file mode 100644
index 0000000..b164186
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/reverb_frequency_response.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_REVERB_FREQUENCY_RESPONSE_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_REVERB_FREQUENCY_RESPONSE_H_
+
+#include <array>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// Class for updating the frequency response for the reverb.
+class ReverbFrequencyResponse {
+ public:
+ ReverbFrequencyResponse();
+ ~ReverbFrequencyResponse();
+
+ // Updates the frequency response estimate of the reverb.
+ void Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+ frequency_response,
+ int filter_delay_blocks,
+ const absl::optional<float>& linear_filter_quality,
+ bool stationary_block);
+
+ // Returns the estimated frequency response for the reverb.
+ rtc::ArrayView<const float> FrequencyResponse() const {
+ return tail_response_;
+ }
+
+ private:
+ void Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>&
+ frequency_response,
+ int filter_delay_blocks,
+ float linear_filter_quality);
+
+ float average_decay_ = 0.f;
+ std::array<float, kFftLengthBy2Plus1> tail_response_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_REVERB_FREQUENCY_RESPONSE_H_
diff --git a/webrtc/modules/audio_processing/aec3/reverb_model.cc b/webrtc/modules/audio_processing/aec3/reverb_model.cc
new file mode 100644
index 0000000..e4f3507
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/reverb_model.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/reverb_model.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <functional>
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+ReverbModel::ReverbModel() {
+ Reset();
+}
+
+ReverbModel::~ReverbModel() = default;
+
+void ReverbModel::Reset() {
+ reverb_.fill(0.);
+}
+
+void ReverbModel::UpdateReverbNoFreqShaping(
+ rtc::ArrayView<const float> power_spectrum,
+ float power_spectrum_scaling,
+ float reverb_decay) {
+ if (reverb_decay > 0) {
+ // Update the estimate of the reverberant power.
+ for (size_t k = 0; k < power_spectrum.size(); ++k) {
+ reverb_[k] = (reverb_[k] + power_spectrum[k] * power_spectrum_scaling) *
+ reverb_decay;
+ }
+ }
+}
+
+void ReverbModel::UpdateReverb(
+ rtc::ArrayView<const float> power_spectrum,
+ rtc::ArrayView<const float> power_spectrum_scaling,
+ float reverb_decay) {
+ if (reverb_decay > 0) {
+ // Update the estimate of the reverberant power.
+ for (size_t k = 0; k < power_spectrum.size(); ++k) {
+ reverb_[k] =
+ (reverb_[k] + power_spectrum[k] * power_spectrum_scaling[k]) *
+ reverb_decay;
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/reverb_model.h b/webrtc/modules/audio_processing/aec3/reverb_model.h
new file mode 100644
index 0000000..5ba5485
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/reverb_model.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// The ReverbModel class describes an exponential reverberant model
+// that can be applied over power spectrums.
+class ReverbModel {
+ public:
+ ReverbModel();
+ ~ReverbModel();
+
+ // Resets the state.
+ void Reset();
+
+ // Returns the reverb.
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> reverb() const {
+ return reverb_;
+ }
+
+ // The methods UpdateReverbNoFreqShaping and UpdateReverb update the
+ // estimate of the reverberation contribution to an input/output power
+ // spectrum. Before applying the exponential reverberant model, the input
+ // power spectrum is pre-scaled. Use the method UpdateReverb when a different
+ // scaling should be applied per frequency and UpdateReverb_no_freq_shape if
+ // the same scaling should be used for all the frequencies.
+ void UpdateReverbNoFreqShaping(rtc::ArrayView<const float> power_spectrum,
+ float power_spectrum_scaling,
+ float reverb_decay);
+
+ // Update the reverb based on new data.
+ void UpdateReverb(rtc::ArrayView<const float> power_spectrum,
+ rtc::ArrayView<const float> power_spectrum_scaling,
+ float reverb_decay);
+
+ private:
+
+ std::array<float, kFftLengthBy2Plus1> reverb_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_H_
diff --git a/webrtc/modules/audio_processing/aec3/reverb_model_estimator.cc b/webrtc/modules/audio_processing/aec3/reverb_model_estimator.cc
new file mode 100644
index 0000000..7174311
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/reverb_model_estimator.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/reverb_model_estimator.h"
+
+namespace webrtc {
+
+ReverbModelEstimator::ReverbModelEstimator(const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : reverb_decay_estimators_(num_capture_channels),
+ reverb_frequency_responses_(num_capture_channels) {
+ for (size_t ch = 0; ch < reverb_decay_estimators_.size(); ++ch) {
+ reverb_decay_estimators_[ch] =
+ std::make_unique<ReverbDecayEstimator>(config);
+ }
+}
+
+ReverbModelEstimator::~ReverbModelEstimator() = default;
+
+void ReverbModelEstimator::Update(
+ rtc::ArrayView<const std::vector<float>> impulse_responses,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ frequency_responses,
+ rtc::ArrayView<const absl::optional<float>> linear_filter_qualities,
+ rtc::ArrayView<const int> filter_delays_blocks,
+ const std::vector<bool>& usable_linear_estimates,
+ bool stationary_block) {
+ const size_t num_capture_channels = reverb_decay_estimators_.size();
+ RTC_DCHECK_EQ(num_capture_channels, impulse_responses.size());
+ RTC_DCHECK_EQ(num_capture_channels, frequency_responses.size());
+ RTC_DCHECK_EQ(num_capture_channels, usable_linear_estimates.size());
+
+ for (size_t ch = 0; ch < num_capture_channels; ++ch) {
+ // Estimate the frequency response for the reverb.
+ reverb_frequency_responses_[ch].Update(
+ frequency_responses[ch], filter_delays_blocks[ch],
+ linear_filter_qualities[ch], stationary_block);
+
+ // Estimate the reverb decay,
+ reverb_decay_estimators_[ch]->Update(
+ impulse_responses[ch], linear_filter_qualities[ch],
+ filter_delays_blocks[ch], usable_linear_estimates[ch],
+ stationary_block);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h b/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h
new file mode 100644
index 0000000..3b9971a
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/reverb_model_estimator.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_
+
+#include <array>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h" // kFftLengthBy2Plus1
+#include "modules/audio_processing/aec3/reverb_decay_estimator.h"
+#include "modules/audio_processing/aec3/reverb_frequency_response.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+
+// Class for estimating the model parameters for the reverberant echo.
+class ReverbModelEstimator {
+ public:
+ ReverbModelEstimator(const EchoCanceller3Config& config,
+ size_t num_capture_channels);
+ ~ReverbModelEstimator();
+
+ // Updates the estimates based on new data.
+ void Update(
+ rtc::ArrayView<const std::vector<float>> impulse_responses,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ frequency_responses,
+ rtc::ArrayView<const absl::optional<float>> linear_filter_qualities,
+ rtc::ArrayView<const int> filter_delays_blocks,
+ const std::vector<bool>& usable_linear_estimates,
+ bool stationary_block);
+
+ // Returns the exponential decay of the reverberant echo.
+ // TODO(peah): Correct to properly support multiple channels.
+ float ReverbDecay() const { return reverb_decay_estimators_[0]->Decay(); }
+
+ // Return the frequency response of the reverberant echo.
+ // TODO(peah): Correct to properly support multiple channels.
+ rtc::ArrayView<const float> GetReverbFrequencyResponse() const {
+ return reverb_frequency_responses_[0].FrequencyResponse();
+ }
+
+ // Dumps debug data.
+ void Dump(ApmDataDumper* data_dumper) const {
+ reverb_decay_estimators_[0]->Dump(data_dumper);
+ }
+
+ private:
+ std::vector<std::unique_ptr<ReverbDecayEstimator>> reverb_decay_estimators_;
+ std::vector<ReverbFrequencyResponse> reverb_frequency_responses_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_REVERB_MODEL_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc b/webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc
new file mode 100644
index 0000000..5a3ba6c
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.cc
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/signal_dependent_erle_estimator.h"
+
+#include <algorithm>
+#include <functional>
+#include <numeric>
+
+#include "modules/audio_processing/aec3/spectrum_buffer.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr std::array<size_t, SignalDependentErleEstimator::kSubbands + 1>
+ kBandBoundaries = {1, 8, 16, 24, 32, 48, kFftLengthBy2Plus1};
+
+std::array<size_t, kFftLengthBy2Plus1> FormSubbandMap() {
+ std::array<size_t, kFftLengthBy2Plus1> map_band_to_subband;
+ size_t subband = 1;
+ for (size_t k = 0; k < map_band_to_subband.size(); ++k) {
+ RTC_DCHECK_LT(subband, kBandBoundaries.size());
+ if (k >= kBandBoundaries[subband]) {
+ subband++;
+ RTC_DCHECK_LT(k, kBandBoundaries[subband]);
+ }
+ map_band_to_subband[k] = subband - 1;
+ }
+ return map_band_to_subband;
+}
+
+// Defines the size in blocks of the sections that are used for dividing the
+// linear filter. The sections are split in a non-linear manner so that lower
+// sections that typically represent the direct path have a larger resolution
+// than the higher sections which typically represent more reverberant acoustic
+// paths.
+std::vector<size_t> DefineFilterSectionSizes(size_t delay_headroom_blocks,
+ size_t num_blocks,
+ size_t num_sections) {
+ size_t filter_length_blocks = num_blocks - delay_headroom_blocks;
+ std::vector<size_t> section_sizes(num_sections);
+ size_t remaining_blocks = filter_length_blocks;
+ size_t remaining_sections = num_sections;
+ size_t estimator_size = 2;
+ size_t idx = 0;
+ while (remaining_sections > 1 &&
+ remaining_blocks > estimator_size * remaining_sections) {
+ RTC_DCHECK_LT(idx, section_sizes.size());
+ section_sizes[idx] = estimator_size;
+ remaining_blocks -= estimator_size;
+ remaining_sections--;
+ estimator_size *= 2;
+ idx++;
+ }
+
+ size_t last_groups_size = remaining_blocks / remaining_sections;
+ for (; idx < num_sections; idx++) {
+ section_sizes[idx] = last_groups_size;
+ }
+ section_sizes[num_sections - 1] +=
+ remaining_blocks - last_groups_size * remaining_sections;
+ return section_sizes;
+}
+
+// Forms the limits in blocks for each filter section. Those sections
+// are used for analyzing the echo estimates and investigating which
+// linear filter sections contribute most to the echo estimate energy.
+std::vector<size_t> SetSectionsBoundaries(size_t delay_headroom_blocks,
+ size_t num_blocks,
+ size_t num_sections) {
+ std::vector<size_t> estimator_boundaries_blocks(num_sections + 1);
+ if (estimator_boundaries_blocks.size() == 2) {
+ estimator_boundaries_blocks[0] = 0;
+ estimator_boundaries_blocks[1] = num_blocks;
+ return estimator_boundaries_blocks;
+ }
+ RTC_DCHECK_GT(estimator_boundaries_blocks.size(), 2);
+ const std::vector<size_t> section_sizes =
+ DefineFilterSectionSizes(delay_headroom_blocks, num_blocks,
+ estimator_boundaries_blocks.size() - 1);
+
+ size_t idx = 0;
+ size_t current_size_block = 0;
+ RTC_DCHECK_EQ(section_sizes.size() + 1, estimator_boundaries_blocks.size());
+ estimator_boundaries_blocks[0] = delay_headroom_blocks;
+ for (size_t k = delay_headroom_blocks; k < num_blocks; ++k) {
+ current_size_block++;
+ if (current_size_block >= section_sizes[idx]) {
+ idx = idx + 1;
+ if (idx == section_sizes.size()) {
+ break;
+ }
+ estimator_boundaries_blocks[idx] = k + 1;
+ current_size_block = 0;
+ }
+ }
+ estimator_boundaries_blocks[section_sizes.size()] = num_blocks;
+ return estimator_boundaries_blocks;
+}
+
+std::array<float, SignalDependentErleEstimator::kSubbands>
+SetMaxErleSubbands(float max_erle_l, float max_erle_h, size_t limit_subband_l) {
+ std::array<float, SignalDependentErleEstimator::kSubbands> max_erle;
+ std::fill(max_erle.begin(), max_erle.begin() + limit_subband_l, max_erle_l);
+ std::fill(max_erle.begin() + limit_subband_l, max_erle.end(), max_erle_h);
+ return max_erle;
+}
+
+} // namespace
+
+SignalDependentErleEstimator::SignalDependentErleEstimator(
+ const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : min_erle_(config.erle.min),
+ num_sections_(config.erle.num_sections),
+ num_blocks_(config.filter.refined.length_blocks),
+ delay_headroom_blocks_(config.delay.delay_headroom_samples / kBlockSize),
+ band_to_subband_(FormSubbandMap()),
+ max_erle_(SetMaxErleSubbands(config.erle.max_l,
+ config.erle.max_h,
+ band_to_subband_[kFftLengthBy2 / 2])),
+ section_boundaries_blocks_(SetSectionsBoundaries(delay_headroom_blocks_,
+ num_blocks_,
+ num_sections_)),
+ erle_(num_capture_channels),
+ S2_section_accum_(
+ num_capture_channels,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>(num_sections_)),
+ erle_estimators_(
+ num_capture_channels,
+ std::vector<std::array<float, kSubbands>>(num_sections_)),
+ erle_ref_(num_capture_channels),
+ correction_factors_(
+ num_capture_channels,
+ std::vector<std::array<float, kSubbands>>(num_sections_)),
+ num_updates_(num_capture_channels),
+ n_active_sections_(num_capture_channels) {
+ RTC_DCHECK_LE(num_sections_, num_blocks_);
+ RTC_DCHECK_GE(num_sections_, 1);
+ Reset();
+}
+
+SignalDependentErleEstimator::~SignalDependentErleEstimator() = default;
+
+void SignalDependentErleEstimator::Reset() {
+ for (size_t ch = 0; ch < erle_.size(); ++ch) {
+ erle_[ch].fill(min_erle_);
+ for (auto& erle_estimator : erle_estimators_[ch]) {
+ erle_estimator.fill(min_erle_);
+ }
+ erle_ref_[ch].fill(min_erle_);
+ for (auto& factor : correction_factors_[ch]) {
+ factor.fill(1.0f);
+ }
+ num_updates_[ch].fill(0);
+ n_active_sections_[ch].fill(0);
+ }
+}
+
+// Updates the Erle estimate by analyzing the current input signals. It takes
+// the render buffer and the filter frequency response in order to do an
+// estimation of the number of sections of the linear filter that are needed
+// for getting the majority of the energy in the echo estimate. Based on that
+// number of sections, it updates the erle estimation by introducing a
+// correction factor to the erle that is given as an input to this method.
+void SignalDependentErleEstimator::Update(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ filter_frequency_responses,
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> average_erle,
+ const std::vector<bool>& converged_filters) {
+ RTC_DCHECK_GT(num_sections_, 1);
+
+ // Gets the number of filter sections that are needed for achieving 90 %
+ // of the power spectrum energy of the echo estimate.
+ ComputeNumberOfActiveFilterSections(render_buffer,
+ filter_frequency_responses);
+
+ // Updates the correction factors that is used for correcting the erle and
+ // adapt it to the particular characteristics of the input signal.
+ UpdateCorrectionFactors(X2, Y2, E2, converged_filters);
+
+ // Applies the correction factor to the input erle for getting a more refined
+ // erle estimation for the current input signal.
+ for (size_t ch = 0; ch < erle_.size(); ++ch) {
+ for (size_t k = 0; k < kFftLengthBy2; ++k) {
+ RTC_DCHECK_GT(correction_factors_[ch].size(), n_active_sections_[ch][k]);
+ float correction_factor =
+ correction_factors_[ch][n_active_sections_[ch][k]]
+ [band_to_subband_[k]];
+ erle_[ch][k] = rtc::SafeClamp(average_erle[ch][k] * correction_factor,
+ min_erle_, max_erle_[band_to_subband_[k]]);
+ }
+ }
+}
+
+void SignalDependentErleEstimator::Dump(
+ const std::unique_ptr<ApmDataDumper>& data_dumper) const {
+ for (auto& erle : erle_estimators_[0]) {
+ data_dumper->DumpRaw("aec3_all_erle", erle);
+ }
+ data_dumper->DumpRaw("aec3_ref_erle", erle_ref_[0]);
+ for (auto& factor : correction_factors_[0]) {
+ data_dumper->DumpRaw("aec3_erle_correction_factor", factor);
+ }
+}
+
+// Estimates for each band the smallest number of sections in the filter that
+// together constitute 90% of the estimated echo energy.
+void SignalDependentErleEstimator::ComputeNumberOfActiveFilterSections(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ filter_frequency_responses) {
+ RTC_DCHECK_GT(num_sections_, 1);
+ // Computes an approximation of the power spectrum if the filter would have
+ // been limited to a certain number of filter sections.
+ ComputeEchoEstimatePerFilterSection(render_buffer,
+ filter_frequency_responses);
+ // For each band, computes the number of filter sections that are needed for
+ // achieving the 90 % energy in the echo estimate.
+ ComputeActiveFilterSections();
+}
+
+void SignalDependentErleEstimator::UpdateCorrectionFactors(
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ const std::vector<bool>& converged_filters) {
+ for (size_t ch = 0; ch < converged_filters.size(); ++ch) {
+ if (converged_filters[ch]) {
+ constexpr float kX2BandEnergyThreshold = 44015068.0f;
+ constexpr float kSmthConstantDecreases = 0.1f;
+ constexpr float kSmthConstantIncreases = kSmthConstantDecreases / 2.f;
+ auto subband_powers = [](rtc::ArrayView<const float> power_spectrum,
+ rtc::ArrayView<float> power_spectrum_subbands) {
+ for (size_t subband = 0; subband < kSubbands; ++subband) {
+ RTC_DCHECK_LE(kBandBoundaries[subband + 1], power_spectrum.size());
+ power_spectrum_subbands[subband] = std::accumulate(
+ power_spectrum.begin() + kBandBoundaries[subband],
+ power_spectrum.begin() + kBandBoundaries[subband + 1], 0.f);
+ }
+ };
+
+ std::array<float, kSubbands> X2_subbands, E2_subbands, Y2_subbands;
+ subband_powers(X2, X2_subbands);
+ subband_powers(E2[ch], E2_subbands);
+ subband_powers(Y2[ch], Y2_subbands);
+ std::array<size_t, kSubbands> idx_subbands;
+ for (size_t subband = 0; subband < kSubbands; ++subband) {
+ // When aggregating the number of active sections in the filter for
+ // different bands we choose to take the minimum of all of them. As an
+ // example, if for one of the bands it is the direct path its refined
+ // contributor to the final echo estimate, we consider the direct path
+ // is as well the refined contributor for the subband that contains that
+ // particular band. That aggregate number of sections will be later used
+ // as the identifier of the erle estimator that needs to be updated.
+ RTC_DCHECK_LE(kBandBoundaries[subband + 1],
+ n_active_sections_[ch].size());
+ idx_subbands[subband] = *std::min_element(
+ n_active_sections_[ch].begin() + kBandBoundaries[subband],
+ n_active_sections_[ch].begin() + kBandBoundaries[subband + 1]);
+ }
+
+ std::array<float, kSubbands> new_erle;
+ std::array<bool, kSubbands> is_erle_updated;
+ is_erle_updated.fill(false);
+ new_erle.fill(0.f);
+ for (size_t subband = 0; subband < kSubbands; ++subband) {
+ if (X2_subbands[subband] > kX2BandEnergyThreshold &&
+ E2_subbands[subband] > 0) {
+ new_erle[subband] = Y2_subbands[subband] / E2_subbands[subband];
+ RTC_DCHECK_GT(new_erle[subband], 0);
+ is_erle_updated[subband] = true;
+ ++num_updates_[ch][subband];
+ }
+ }
+
+ for (size_t subband = 0; subband < kSubbands; ++subband) {
+ const size_t idx = idx_subbands[subband];
+ RTC_DCHECK_LT(idx, erle_estimators_[ch].size());
+ float alpha = new_erle[subband] > erle_estimators_[ch][idx][subband]
+ ? kSmthConstantIncreases
+ : kSmthConstantDecreases;
+ alpha = static_cast<float>(is_erle_updated[subband]) * alpha;
+ erle_estimators_[ch][idx][subband] +=
+ alpha * (new_erle[subband] - erle_estimators_[ch][idx][subband]);
+ erle_estimators_[ch][idx][subband] = rtc::SafeClamp(
+ erle_estimators_[ch][idx][subband], min_erle_, max_erle_[subband]);
+ }
+
+ for (size_t subband = 0; subband < kSubbands; ++subband) {
+ float alpha = new_erle[subband] > erle_ref_[ch][subband]
+ ? kSmthConstantIncreases
+ : kSmthConstantDecreases;
+ alpha = static_cast<float>(is_erle_updated[subband]) * alpha;
+ erle_ref_[ch][subband] +=
+ alpha * (new_erle[subband] - erle_ref_[ch][subband]);
+ erle_ref_[ch][subband] = rtc::SafeClamp(erle_ref_[ch][subband],
+ min_erle_, max_erle_[subband]);
+ }
+
+ for (size_t subband = 0; subband < kSubbands; ++subband) {
+ constexpr int kNumUpdateThr = 50;
+ if (is_erle_updated[subband] &&
+ num_updates_[ch][subband] > kNumUpdateThr) {
+ const size_t idx = idx_subbands[subband];
+ RTC_DCHECK_GT(erle_ref_[ch][subband], 0.f);
+ // Computes the ratio between the erle that is updated using all the
+ // points and the erle that is updated only on signals that share the
+ // same number of active filter sections.
+ float new_correction_factor =
+ erle_estimators_[ch][idx][subband] / erle_ref_[ch][subband];
+
+ correction_factors_[ch][idx][subband] +=
+ 0.1f *
+ (new_correction_factor - correction_factors_[ch][idx][subband]);
+ }
+ }
+ }
+ }
+}
+
+void SignalDependentErleEstimator::ComputeEchoEstimatePerFilterSection(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ filter_frequency_responses) {
+ const SpectrumBuffer& spectrum_render_buffer =
+ render_buffer.GetSpectrumBuffer();
+ const size_t num_render_channels = spectrum_render_buffer.buffer[0].size();
+ const size_t num_capture_channels = S2_section_accum_.size();
+ const float one_by_num_render_channels = 1.f / num_render_channels;
+
+ RTC_DCHECK_EQ(S2_section_accum_.size(), filter_frequency_responses.size());
+
+ for (size_t capture_ch = 0; capture_ch < num_capture_channels; ++capture_ch) {
+ RTC_DCHECK_EQ(S2_section_accum_[capture_ch].size() + 1,
+ section_boundaries_blocks_.size());
+ size_t idx_render = render_buffer.Position();
+ idx_render = spectrum_render_buffer.OffsetIndex(
+ idx_render, section_boundaries_blocks_[0]);
+
+ for (size_t section = 0; section < num_sections_; ++section) {
+ std::array<float, kFftLengthBy2Plus1> X2_section;
+ std::array<float, kFftLengthBy2Plus1> H2_section;
+ X2_section.fill(0.f);
+ H2_section.fill(0.f);
+ const size_t block_limit =
+ std::min(section_boundaries_blocks_[section + 1],
+ filter_frequency_responses[capture_ch].size());
+ for (size_t block = section_boundaries_blocks_[section];
+ block < block_limit; ++block) {
+ for (size_t render_ch = 0;
+ render_ch < spectrum_render_buffer.buffer[idx_render].size();
+ ++render_ch) {
+ for (size_t k = 0; k < X2_section.size(); ++k) {
+ X2_section[k] +=
+ spectrum_render_buffer.buffer[idx_render][render_ch][k] *
+ one_by_num_render_channels;
+ }
+ }
+ std::transform(H2_section.begin(), H2_section.end(),
+ filter_frequency_responses[capture_ch][block].begin(),
+ H2_section.begin(), std::plus<float>());
+ idx_render = spectrum_render_buffer.IncIndex(idx_render);
+ }
+
+ std::transform(X2_section.begin(), X2_section.end(), H2_section.begin(),
+ S2_section_accum_[capture_ch][section].begin(),
+ std::multiplies<float>());
+ }
+
+ for (size_t section = 1; section < num_sections_; ++section) {
+ std::transform(S2_section_accum_[capture_ch][section - 1].begin(),
+ S2_section_accum_[capture_ch][section - 1].end(),
+ S2_section_accum_[capture_ch][section].begin(),
+ S2_section_accum_[capture_ch][section].begin(),
+ std::plus<float>());
+ }
+ }
+}
+
+void SignalDependentErleEstimator::ComputeActiveFilterSections() {
+ for (size_t ch = 0; ch < n_active_sections_.size(); ++ch) {
+ std::fill(n_active_sections_[ch].begin(), n_active_sections_[ch].end(), 0);
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ size_t section = num_sections_;
+ float target = 0.9f * S2_section_accum_[ch][num_sections_ - 1][k];
+ while (section > 0 && S2_section_accum_[ch][section - 1][k] >= target) {
+ n_active_sections_[ch][k] = --section;
+ }
+ }
+ }
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.h b/webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.h
new file mode 100644
index 0000000..498e922
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/signal_dependent_erle_estimator.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_SIGNAL_DEPENDENT_ERLE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SIGNAL_DEPENDENT_ERLE_ESTIMATOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+
+namespace webrtc {
+
+// This class estimates the dependency of the Erle to the input signal. By
+// looking at the input signal, an estimation on whether the current echo
+// estimate is due to the direct path or to a more reverberant one is performed.
+// Once that estimation is done, it is possible to refine the average Erle that
+// this class receive as an input.
+class SignalDependentErleEstimator {
+ public:
+ SignalDependentErleEstimator(const EchoCanceller3Config& config,
+ size_t num_capture_channels);
+
+ ~SignalDependentErleEstimator();
+
+ void Reset();
+
+ // Returns the Erle per frequency subband.
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
+ return erle_;
+ }
+
+ // Updates the Erle estimate. The Erle that is passed as an input is required
+ // to be an estimation of the average Erle achieved by the linear filter.
+ void Update(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ filter_frequency_response,
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> average_erle,
+ const std::vector<bool>& converged_filters);
+
+ void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper) const;
+
+ static constexpr size_t kSubbands = 6;
+
+ private:
+ void ComputeNumberOfActiveFilterSections(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ filter_frequency_responses);
+
+ void UpdateCorrectionFactors(
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ const std::vector<bool>& converged_filters);
+
+ void ComputeEchoEstimatePerFilterSection(
+ const RenderBuffer& render_buffer,
+ rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ filter_frequency_responses);
+
+ void ComputeActiveFilterSections();
+
+ const float min_erle_;
+ const size_t num_sections_;
+ const size_t num_blocks_;
+ const size_t delay_headroom_blocks_;
+ const std::array<size_t, kFftLengthBy2Plus1> band_to_subband_;
+ const std::array<float, kSubbands> max_erle_;
+ const std::vector<size_t> section_boundaries_blocks_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> erle_;
+ std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ S2_section_accum_;
+ std::vector<std::vector<std::array<float, kSubbands>>> erle_estimators_;
+ std::vector<std::array<float, kSubbands>> erle_ref_;
+ std::vector<std::vector<std::array<float, kSubbands>>> correction_factors_;
+ std::vector<std::array<int, kSubbands>> num_updates_;
+ std::vector<std::array<size_t, kFftLengthBy2Plus1>> n_active_sections_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SIGNAL_DEPENDENT_ERLE_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/spectrum_buffer.cc b/webrtc/modules/audio_processing/aec3/spectrum_buffer.cc
new file mode 100644
index 0000000..fe32ece
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/spectrum_buffer.cc
@@ -0,0 +1,30 @@
+/*
+ * 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/audio_processing/aec3/spectrum_buffer.h"
+
+#include <algorithm>
+
+namespace webrtc {
+
+SpectrumBuffer::SpectrumBuffer(size_t size, size_t num_channels)
+ : size(static_cast<int>(size)),
+ buffer(size,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>(num_channels)) {
+ for (auto& channel : buffer) {
+ for (auto& c : channel) {
+ std::fill(c.begin(), c.end(), 0.f);
+ }
+ }
+}
+
+SpectrumBuffer::~SpectrumBuffer() = default;
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/spectrum_buffer.h b/webrtc/modules/audio_processing/aec3/spectrum_buffer.h
new file mode 100644
index 0000000..51e1317
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/spectrum_buffer.h
@@ -0,0 +1,62 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_SPECTRUM_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SPECTRUM_BUFFER_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <vector>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// Struct for bundling a circular buffer of one dimensional vector objects
+// together with the read and write indices.
+struct SpectrumBuffer {
+ SpectrumBuffer(size_t size, size_t num_channels);
+ ~SpectrumBuffer();
+
+ int IncIndex(int index) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return index < size - 1 ? index + 1 : 0;
+ }
+
+ int DecIndex(int index) const {
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ return index > 0 ? index - 1 : size - 1;
+ }
+
+ int OffsetIndex(int index, int offset) const {
+ RTC_DCHECK_GE(size, offset);
+ RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(size));
+ RTC_DCHECK_GE(size + index + offset, 0);
+ return (size + index + offset) % size;
+ }
+
+ void UpdateWriteIndex(int offset) { write = OffsetIndex(write, offset); }
+ void IncWriteIndex() { write = IncIndex(write); }
+ void DecWriteIndex() { write = DecIndex(write); }
+ void UpdateReadIndex(int offset) { read = OffsetIndex(read, offset); }
+ void IncReadIndex() { read = IncIndex(read); }
+ void DecReadIndex() { read = DecIndex(read); }
+
+ const int size;
+ std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> buffer;
+ int write = 0;
+ int read = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SPECTRUM_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/aec3/stationarity_estimator.cc b/webrtc/modules/audio_processing/aec3/stationarity_estimator.cc
new file mode 100644
index 0000000..01628f3
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/stationarity_estimator.cc
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/stationarity_estimator.h"
+
+#include <algorithm>
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/spectrum_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+
+namespace webrtc {
+
+namespace {
+constexpr float kMinNoisePower = 10.f;
+constexpr int kHangoverBlocks = kNumBlocksPerSecond / 20;
+constexpr int kNBlocksAverageInitPhase = 20;
+constexpr int kNBlocksInitialPhase = kNumBlocksPerSecond * 2.;
+} // namespace
+
+StationarityEstimator::StationarityEstimator()
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))) {
+ Reset();
+}
+
+StationarityEstimator::~StationarityEstimator() = default;
+
+void StationarityEstimator::Reset() {
+ noise_.Reset();
+ hangovers_.fill(0);
+ stationarity_flags_.fill(false);
+}
+
+// Update just the noise estimator. Usefull until the delay is known
+void StationarityEstimator::UpdateNoiseEstimator(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum) {
+ noise_.Update(spectrum);
+ data_dumper_->DumpRaw("aec3_stationarity_noise_spectrum", noise_.Spectrum());
+ data_dumper_->DumpRaw("aec3_stationarity_is_block_stationary",
+ IsBlockStationary());
+}
+
+void StationarityEstimator::UpdateStationarityFlags(
+ const SpectrumBuffer& spectrum_buffer,
+ rtc::ArrayView<const float> render_reverb_contribution_spectrum,
+ int idx_current,
+ int num_lookahead) {
+ std::array<int, kWindowLength> indexes;
+ int num_lookahead_bounded = std::min(num_lookahead, kWindowLength - 1);
+ int idx = idx_current;
+
+ if (num_lookahead_bounded < kWindowLength - 1) {
+ int num_lookback = (kWindowLength - 1) - num_lookahead_bounded;
+ idx = spectrum_buffer.OffsetIndex(idx_current, num_lookback);
+ }
+ // For estimating the stationarity properties of the current frame, the
+ // power for each band is accumulated for several consecutive spectra in the
+ // method EstimateBandStationarity.
+ // In order to avoid getting the indexes of the spectra for every band with
+ // its associated overhead, those indexes are stored in an array and then use
+ // when the estimation is done.
+ indexes[0] = idx;
+ for (size_t k = 1; k < indexes.size(); ++k) {
+ indexes[k] = spectrum_buffer.DecIndex(indexes[k - 1]);
+ }
+ RTC_DCHECK_EQ(
+ spectrum_buffer.DecIndex(indexes[kWindowLength - 1]),
+ spectrum_buffer.OffsetIndex(idx_current, -(num_lookahead_bounded + 1)));
+
+ for (size_t k = 0; k < stationarity_flags_.size(); ++k) {
+ stationarity_flags_[k] = EstimateBandStationarity(
+ spectrum_buffer, render_reverb_contribution_spectrum, indexes, k);
+ }
+ UpdateHangover();
+ SmoothStationaryPerFreq();
+}
+
+bool StationarityEstimator::IsBlockStationary() const {
+ float acum_stationarity = 0.f;
+ RTC_DCHECK_EQ(stationarity_flags_.size(), kFftLengthBy2Plus1);
+ for (size_t band = 0; band < stationarity_flags_.size(); ++band) {
+ bool st = IsBandStationary(band);
+ acum_stationarity += static_cast<float>(st);
+ }
+ return ((acum_stationarity * (1.f / kFftLengthBy2Plus1)) > 0.75f);
+}
+
+bool StationarityEstimator::EstimateBandStationarity(
+ const SpectrumBuffer& spectrum_buffer,
+ rtc::ArrayView<const float> average_reverb,
+ const std::array<int, kWindowLength>& indexes,
+ size_t band) const {
+ constexpr float kThrStationarity = 10.f;
+ float acum_power = 0.f;
+ const int num_render_channels =
+ static_cast<int>(spectrum_buffer.buffer[0].size());
+ const float one_by_num_channels = 1.f / num_render_channels;
+ for (auto idx : indexes) {
+ for (int ch = 0; ch < num_render_channels; ++ch) {
+ acum_power += spectrum_buffer.buffer[idx][ch][band] * one_by_num_channels;
+ }
+ }
+ acum_power += average_reverb[band];
+ float noise = kWindowLength * GetStationarityPowerBand(band);
+ RTC_CHECK_LT(0.f, noise);
+ bool stationary = acum_power < kThrStationarity * noise;
+ data_dumper_->DumpRaw("aec3_stationarity_long_ratio", acum_power / noise);
+ return stationary;
+}
+
+bool StationarityEstimator::AreAllBandsStationary() {
+ for (auto b : stationarity_flags_) {
+ if (!b)
+ return false;
+ }
+ return true;
+}
+
+void StationarityEstimator::UpdateHangover() {
+ bool reduce_hangover = AreAllBandsStationary();
+ for (size_t k = 0; k < stationarity_flags_.size(); ++k) {
+ if (!stationarity_flags_[k]) {
+ hangovers_[k] = kHangoverBlocks;
+ } else if (reduce_hangover) {
+ hangovers_[k] = std::max(hangovers_[k] - 1, 0);
+ }
+ }
+}
+
+void StationarityEstimator::SmoothStationaryPerFreq() {
+ std::array<bool, kFftLengthBy2Plus1> all_ahead_stationary_smooth;
+ for (size_t k = 1; k < kFftLengthBy2Plus1 - 1; ++k) {
+ all_ahead_stationary_smooth[k] = stationarity_flags_[k - 1] &&
+ stationarity_flags_[k] &&
+ stationarity_flags_[k + 1];
+ }
+
+ all_ahead_stationary_smooth[0] = all_ahead_stationary_smooth[1];
+ all_ahead_stationary_smooth[kFftLengthBy2Plus1 - 1] =
+ all_ahead_stationary_smooth[kFftLengthBy2Plus1 - 2];
+
+ stationarity_flags_ = all_ahead_stationary_smooth;
+}
+
+int StationarityEstimator::instance_count_ = 0;
+
+StationarityEstimator::NoiseSpectrum::NoiseSpectrum() {
+ Reset();
+}
+
+StationarityEstimator::NoiseSpectrum::~NoiseSpectrum() = default;
+
+void StationarityEstimator::NoiseSpectrum::Reset() {
+ block_counter_ = 0;
+ noise_spectrum_.fill(kMinNoisePower);
+}
+
+void StationarityEstimator::NoiseSpectrum::Update(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum) {
+ RTC_DCHECK_LE(1, spectrum[0].size());
+ const int num_render_channels = static_cast<int>(spectrum.size());
+
+ std::array<float, kFftLengthBy2Plus1> avg_spectrum_data;
+ rtc::ArrayView<const float> avg_spectrum;
+ if (num_render_channels == 1) {
+ avg_spectrum = spectrum[0];
+ } else {
+ // For multiple channels, average the channel spectra before passing to the
+ // noise spectrum estimator.
+ avg_spectrum = avg_spectrum_data;
+ std::copy(spectrum[0].begin(), spectrum[0].end(),
+ avg_spectrum_data.begin());
+ for (int ch = 1; ch < num_render_channels; ++ch) {
+ for (size_t k = 1; k < kFftLengthBy2Plus1; ++k) {
+ avg_spectrum_data[k] += spectrum[ch][k];
+ }
+ }
+
+ const float one_by_num_channels = 1.f / num_render_channels;
+ for (size_t k = 1; k < kFftLengthBy2Plus1; ++k) {
+ avg_spectrum_data[k] *= one_by_num_channels;
+ }
+ }
+
+ ++block_counter_;
+ float alpha = GetAlpha();
+ for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
+ if (block_counter_ <= kNBlocksAverageInitPhase) {
+ noise_spectrum_[k] += (1.f / kNBlocksAverageInitPhase) * avg_spectrum[k];
+ } else {
+ noise_spectrum_[k] =
+ UpdateBandBySmoothing(avg_spectrum[k], noise_spectrum_[k], alpha);
+ }
+ }
+}
+
+float StationarityEstimator::NoiseSpectrum::GetAlpha() const {
+ constexpr float kAlpha = 0.004f;
+ constexpr float kAlphaInit = 0.04f;
+ constexpr float kTiltAlpha = (kAlphaInit - kAlpha) / kNBlocksInitialPhase;
+
+ if (block_counter_ > (kNBlocksInitialPhase + kNBlocksAverageInitPhase)) {
+ return kAlpha;
+ } else {
+ return kAlphaInit -
+ kTiltAlpha * (block_counter_ - kNBlocksAverageInitPhase);
+ }
+}
+
+float StationarityEstimator::NoiseSpectrum::UpdateBandBySmoothing(
+ float power_band,
+ float power_band_noise,
+ float alpha) const {
+ float power_band_noise_updated = power_band_noise;
+ if (power_band_noise < power_band) {
+ RTC_DCHECK_GT(power_band, 0.f);
+ float alpha_inc = alpha * (power_band_noise / power_band);
+ if (block_counter_ > kNBlocksInitialPhase) {
+ if (10.f * power_band_noise < power_band) {
+ alpha_inc *= 0.1f;
+ }
+ }
+ power_band_noise_updated += alpha_inc * (power_band - power_band_noise);
+ } else {
+ power_band_noise_updated += alpha * (power_band - power_band_noise);
+ power_band_noise_updated =
+ std::max(power_band_noise_updated, kMinNoisePower);
+ }
+ return power_band_noise_updated;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/stationarity_estimator.h b/webrtc/modules/audio_processing/aec3/stationarity_estimator.h
new file mode 100644
index 0000000..6f7ad40
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/stationarity_estimator.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_STATIONARITY_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_STATIONARITY_ESTIMATOR_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <memory>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h" // kFftLengthBy2Plus1...
+#include "modules/audio_processing/aec3/reverb_model.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+struct SpectrumBuffer;
+
+class StationarityEstimator {
+ public:
+ StationarityEstimator();
+ ~StationarityEstimator();
+
+ // Reset the stationarity estimator.
+ void Reset();
+
+ // Update just the noise estimator. Usefull until the delay is known
+ void UpdateNoiseEstimator(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum);
+
+ // Update the flag indicating whether this current frame is stationary. For
+ // getting a more robust estimation, it looks at future and/or past frames.
+ void UpdateStationarityFlags(
+ const SpectrumBuffer& spectrum_buffer,
+ rtc::ArrayView<const float> render_reverb_contribution_spectrum,
+ int idx_current,
+ int num_lookahead);
+
+ // Returns true if the current band is stationary.
+ bool IsBandStationary(size_t band) const {
+ return stationarity_flags_[band] && (hangovers_[band] == 0);
+ }
+
+ // Returns true if the current block is estimated as stationary.
+ bool IsBlockStationary() const;
+
+ private:
+ static constexpr int kWindowLength = 13;
+ // Returns the power of the stationary noise spectrum at a band.
+ float GetStationarityPowerBand(size_t k) const { return noise_.Power(k); }
+
+ // Get an estimation of the stationarity for the current band by looking
+ // at the past/present/future available data.
+ bool EstimateBandStationarity(const SpectrumBuffer& spectrum_buffer,
+ rtc::ArrayView<const float> average_reverb,
+ const std::array<int, kWindowLength>& indexes,
+ size_t band) const;
+
+ // True if all bands at the current point are stationary.
+ bool AreAllBandsStationary();
+
+ // Update the hangover depending on the stationary status of the current
+ // frame.
+ void UpdateHangover();
+
+ // Smooth the stationarity detection by looking at neighbouring frequency
+ // bands.
+ void SmoothStationaryPerFreq();
+
+ class NoiseSpectrum {
+ public:
+ NoiseSpectrum();
+ ~NoiseSpectrum();
+
+ // Reset the noise power spectrum estimate state.
+ void Reset();
+
+ // Update the noise power spectrum with a new frame.
+ void Update(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> spectrum);
+
+ // Get the noise estimation power spectrum.
+ rtc::ArrayView<const float> Spectrum() const { return noise_spectrum_; }
+
+ // Get the noise power spectrum at a certain band.
+ float Power(size_t band) const {
+ RTC_DCHECK_LT(band, noise_spectrum_.size());
+ return noise_spectrum_[band];
+ }
+
+ private:
+ // Get the update coefficient to be used for the current frame.
+ float GetAlpha() const;
+
+ // Update the noise power spectrum at a certain band with a new frame.
+ float UpdateBandBySmoothing(float power_band,
+ float power_band_noise,
+ float alpha) const;
+ std::array<float, kFftLengthBy2Plus1> noise_spectrum_;
+ size_t block_counter_;
+ };
+
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ NoiseSpectrum noise_;
+ std::array<int, kFftLengthBy2Plus1> hangovers_;
+ std::array<bool, kFftLengthBy2Plus1> stationarity_flags_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_STATIONARITY_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/subband_erle_estimator.cc b/webrtc/modules/audio_processing/aec3/subband_erle_estimator.cc
new file mode 100644
index 0000000..6c00091
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subband_erle_estimator.cc
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/subband_erle_estimator.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr float kX2BandEnergyThreshold = 44015068.0f;
+constexpr int kBlocksToHoldErle = 100;
+constexpr int kBlocksForOnsetDetection = kBlocksToHoldErle + 150;
+constexpr int kPointsToAccumulate = 6;
+
+std::array<float, kFftLengthBy2Plus1> SetMaxErleBands(float max_erle_l,
+ float max_erle_h) {
+ std::array<float, kFftLengthBy2Plus1> max_erle;
+ std::fill(max_erle.begin(), max_erle.begin() + kFftLengthBy2 / 2, max_erle_l);
+ std::fill(max_erle.begin() + kFftLengthBy2 / 2, max_erle.end(), max_erle_h);
+ return max_erle;
+}
+
+bool EnableMinErleDuringOnsets() {
+ return !field_trial::IsEnabled("WebRTC-Aec3MinErleDuringOnsetsKillSwitch");
+}
+
+} // namespace
+
+SubbandErleEstimator::SubbandErleEstimator(const EchoCanceller3Config& config,
+ size_t num_capture_channels)
+ : use_onset_detection_(config.erle.onset_detection),
+ min_erle_(config.erle.min),
+ max_erle_(SetMaxErleBands(config.erle.max_l, config.erle.max_h)),
+ use_min_erle_during_onsets_(EnableMinErleDuringOnsets()),
+ accum_spectra_(num_capture_channels),
+ erle_(num_capture_channels),
+ erle_onsets_(num_capture_channels),
+ coming_onset_(num_capture_channels),
+ hold_counters_(num_capture_channels) {
+ Reset();
+}
+
+SubbandErleEstimator::~SubbandErleEstimator() = default;
+
+void SubbandErleEstimator::Reset() {
+ for (auto& erle : erle_) {
+ erle.fill(min_erle_);
+ }
+ for (size_t ch = 0; ch < erle_onsets_.size(); ++ch) {
+ erle_onsets_[ch].fill(min_erle_);
+ coming_onset_[ch].fill(true);
+ hold_counters_[ch].fill(0);
+ }
+ ResetAccumulatedSpectra();
+}
+
+void SubbandErleEstimator::Update(
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ const std::vector<bool>& converged_filters) {
+ UpdateAccumulatedSpectra(X2, Y2, E2, converged_filters);
+ UpdateBands(converged_filters);
+
+ if (use_onset_detection_) {
+ DecreaseErlePerBandForLowRenderSignals();
+ }
+
+ for (auto& erle : erle_) {
+ erle[0] = erle[1];
+ erle[kFftLengthBy2] = erle[kFftLengthBy2 - 1];
+ }
+}
+
+void SubbandErleEstimator::Dump(
+ const std::unique_ptr<ApmDataDumper>& data_dumper) const {
+ data_dumper->DumpRaw("aec3_erle_onset", ErleOnsets()[0]);
+}
+
+void SubbandErleEstimator::UpdateBands(
+ const std::vector<bool>& converged_filters) {
+ const int num_capture_channels = static_cast<int>(accum_spectra_.Y2.size());
+ for (int ch = 0; ch < num_capture_channels; ++ch) {
+ // Note that the use of the converged_filter flag already imposed
+ // a minimum of the erle that can be estimated as that flag would
+ // be false if the filter is performing poorly.
+ if (!converged_filters[ch]) {
+ continue;
+ }
+
+ std::array<float, kFftLengthBy2> new_erle;
+ std::array<bool, kFftLengthBy2> is_erle_updated;
+ is_erle_updated.fill(false);
+
+ for (size_t k = 1; k < kFftLengthBy2; ++k) {
+ if (accum_spectra_.num_points[ch] == kPointsToAccumulate &&
+ accum_spectra_.E2[ch][k] > 0.f) {
+ new_erle[k] = accum_spectra_.Y2[ch][k] / accum_spectra_.E2[ch][k];
+ is_erle_updated[k] = true;
+ }
+ }
+
+ if (use_onset_detection_) {
+ for (size_t k = 1; k < kFftLengthBy2; ++k) {
+ if (is_erle_updated[k] && !accum_spectra_.low_render_energy[ch][k]) {
+ if (coming_onset_[ch][k]) {
+ coming_onset_[ch][k] = false;
+ if (!use_min_erle_during_onsets_) {
+ float alpha = new_erle[k] < erle_onsets_[ch][k] ? 0.3f : 0.15f;
+ erle_onsets_[ch][k] = rtc::SafeClamp(
+ erle_onsets_[ch][k] +
+ alpha * (new_erle[k] - erle_onsets_[ch][k]),
+ min_erle_, max_erle_[k]);
+ }
+ }
+ hold_counters_[ch][k] = kBlocksForOnsetDetection;
+ }
+ }
+ }
+
+ for (size_t k = 1; k < kFftLengthBy2; ++k) {
+ if (is_erle_updated[k]) {
+ float alpha = 0.05f;
+ if (new_erle[k] < erle_[ch][k]) {
+ alpha = accum_spectra_.low_render_energy[ch][k] ? 0.f : 0.1f;
+ }
+ erle_[ch][k] =
+ rtc::SafeClamp(erle_[ch][k] + alpha * (new_erle[k] - erle_[ch][k]),
+ min_erle_, max_erle_[k]);
+ }
+ }
+ }
+}
+
+void SubbandErleEstimator::DecreaseErlePerBandForLowRenderSignals() {
+ const int num_capture_channels = static_cast<int>(accum_spectra_.Y2.size());
+ for (int ch = 0; ch < num_capture_channels; ++ch) {
+ for (size_t k = 1; k < kFftLengthBy2; ++k) {
+ --hold_counters_[ch][k];
+ if (hold_counters_[ch][k] <=
+ (kBlocksForOnsetDetection - kBlocksToHoldErle)) {
+ if (erle_[ch][k] > erle_onsets_[ch][k]) {
+ erle_[ch][k] = std::max(erle_onsets_[ch][k], 0.97f * erle_[ch][k]);
+ RTC_DCHECK_LE(min_erle_, erle_[ch][k]);
+ }
+ if (hold_counters_[ch][k] <= 0) {
+ coming_onset_[ch][k] = true;
+ hold_counters_[ch][k] = 0;
+ }
+ }
+ }
+ }
+}
+
+void SubbandErleEstimator::ResetAccumulatedSpectra() {
+ for (size_t ch = 0; ch < erle_onsets_.size(); ++ch) {
+ accum_spectra_.Y2[ch].fill(0.f);
+ accum_spectra_.E2[ch].fill(0.f);
+ accum_spectra_.num_points[ch] = 0;
+ accum_spectra_.low_render_energy[ch].fill(false);
+ }
+}
+
+void SubbandErleEstimator::UpdateAccumulatedSpectra(
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ const std::vector<bool>& converged_filters) {
+ auto& st = accum_spectra_;
+ RTC_DCHECK_EQ(st.E2.size(), E2.size());
+ RTC_DCHECK_EQ(st.E2.size(), E2.size());
+ const int num_capture_channels = static_cast<int>(Y2.size());
+ for (int ch = 0; ch < num_capture_channels; ++ch) {
+ // Note that the use of the converged_filter flag already imposed
+ // a minimum of the erle that can be estimated as that flag would
+ // be false if the filter is performing poorly.
+ if (!converged_filters[ch]) {
+ continue;
+ }
+
+ if (st.num_points[ch] == kPointsToAccumulate) {
+ st.num_points[ch] = 0;
+ st.Y2[ch].fill(0.f);
+ st.E2[ch].fill(0.f);
+ st.low_render_energy[ch].fill(false);
+ }
+
+ std::transform(Y2[ch].begin(), Y2[ch].end(), st.Y2[ch].begin(),
+ st.Y2[ch].begin(), std::plus<float>());
+ std::transform(E2[ch].begin(), E2[ch].end(), st.E2[ch].begin(),
+ st.E2[ch].begin(), std::plus<float>());
+
+ for (size_t k = 0; k < X2.size(); ++k) {
+ st.low_render_energy[ch][k] =
+ st.low_render_energy[ch][k] || X2[k] < kX2BandEnergyThreshold;
+ }
+
+ ++st.num_points[ch];
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/subband_erle_estimator.h b/webrtc/modules/audio_processing/aec3/subband_erle_estimator.h
new file mode 100644
index 0000000..90363e0
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subband_erle_estimator.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_ERLE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_ERLE_ESTIMATOR_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+
+namespace webrtc {
+
+// Estimates the echo return loss enhancement for each frequency subband.
+class SubbandErleEstimator {
+ public:
+ SubbandErleEstimator(const EchoCanceller3Config& config,
+ size_t num_capture_channels);
+ ~SubbandErleEstimator();
+
+ // Resets the ERLE estimator.
+ void Reset();
+
+ // Updates the ERLE estimate.
+ void Update(rtc::ArrayView<const float, kFftLengthBy2Plus1> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ const std::vector<bool>& converged_filters);
+
+ // Returns the ERLE estimate.
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
+ return erle_;
+ }
+
+ // Returns the ERLE estimate at onsets (only used for testing).
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> ErleOnsets()
+ const {
+ return erle_onsets_;
+ }
+
+ void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper) const;
+
+ private:
+ struct AccumulatedSpectra {
+ explicit AccumulatedSpectra(size_t num_capture_channels)
+ : Y2(num_capture_channels),
+ E2(num_capture_channels),
+ low_render_energy(num_capture_channels),
+ num_points(num_capture_channels) {}
+ std::vector<std::array<float, kFftLengthBy2Plus1>> Y2;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> E2;
+ std::vector<std::array<bool, kFftLengthBy2Plus1>> low_render_energy;
+ std::vector<int> num_points;
+ };
+
+ void UpdateAccumulatedSpectra(
+ rtc::ArrayView<const float, kFftLengthBy2Plus1> X2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
+ const std::vector<bool>& converged_filters);
+
+ void ResetAccumulatedSpectra();
+
+ void UpdateBands(const std::vector<bool>& converged_filters);
+ void DecreaseErlePerBandForLowRenderSignals();
+
+ const bool use_onset_detection_;
+ const float min_erle_;
+ const std::array<float, kFftLengthBy2Plus1> max_erle_;
+ const bool use_min_erle_during_onsets_;
+ AccumulatedSpectra accum_spectra_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> erle_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> erle_onsets_;
+ std::vector<std::array<bool, kFftLengthBy2Plus1>> coming_onset_;
+ std::vector<std::array<int, kFftLengthBy2Plus1>> hold_counters_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_ERLE_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/subband_nearend_detector.cc b/webrtc/modules/audio_processing/aec3/subband_nearend_detector.cc
new file mode 100644
index 0000000..2aa400c
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subband_nearend_detector.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/subband_nearend_detector.h"
+
+#include <numeric>
+
+namespace webrtc {
+SubbandNearendDetector::SubbandNearendDetector(
+ const EchoCanceller3Config::Suppressor::SubbandNearendDetection& config,
+ size_t num_capture_channels)
+ : config_(config),
+ num_capture_channels_(num_capture_channels),
+ nearend_smoothers_(num_capture_channels_,
+ aec3::MovingAverage(kFftLengthBy2Plus1,
+ config_.nearend_average_blocks)),
+ one_over_subband_length1_(
+ 1.f / (config_.subband1.high - config_.subband1.low + 1)),
+ one_over_subband_length2_(
+ 1.f / (config_.subband2.high - config_.subband2.low + 1)) {}
+
+void SubbandNearendDetector::Update(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ nearend_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ residual_echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ bool initial_state) {
+ nearend_state_ = false;
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ const std::array<float, kFftLengthBy2Plus1>& noise =
+ comfort_noise_spectrum[ch];
+ std::array<float, kFftLengthBy2Plus1> nearend;
+ nearend_smoothers_[ch].Average(nearend_spectrum[ch], nearend);
+
+ // Noise power of the first region.
+ float noise_power =
+ std::accumulate(noise.begin() + config_.subband1.low,
+ noise.begin() + config_.subband1.high + 1, 0.f) *
+ one_over_subband_length1_;
+
+ // Nearend power of the first region.
+ float nearend_power_subband1 =
+ std::accumulate(nearend.begin() + config_.subband1.low,
+ nearend.begin() + config_.subband1.high + 1, 0.f) *
+ one_over_subband_length1_;
+
+ // Nearend power of the second region.
+ float nearend_power_subband2 =
+ std::accumulate(nearend.begin() + config_.subband2.low,
+ nearend.begin() + config_.subband2.high + 1, 0.f) *
+ one_over_subband_length2_;
+
+ // One channel is sufficient to trigger nearend state.
+ nearend_state_ =
+ nearend_state_ ||
+ (nearend_power_subband1 <
+ config_.nearend_threshold * nearend_power_subband2 &&
+ (nearend_power_subband1 > config_.snr_threshold * noise_power));
+ }
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/subband_nearend_detector.h b/webrtc/modules/audio_processing/aec3/subband_nearend_detector.h
new file mode 100644
index 0000000..8357edb
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subband_nearend_detector.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_NEAREND_DETECTOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_NEAREND_DETECTOR_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/moving_average.h"
+#include "modules/audio_processing/aec3/nearend_detector.h"
+
+namespace webrtc {
+// Class for selecting whether the suppressor is in the nearend or echo state.
+class SubbandNearendDetector : public NearendDetector {
+ public:
+ SubbandNearendDetector(
+ const EchoCanceller3Config::Suppressor::SubbandNearendDetection& config,
+ size_t num_capture_channels);
+
+ // Returns whether the current state is the nearend state.
+ bool IsNearendState() const override { return nearend_state_; }
+
+ // Updates the state selection based on latest spectral estimates.
+ void Update(rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ nearend_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ residual_echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ bool initial_state) override;
+
+ private:
+ const EchoCanceller3Config::Suppressor::SubbandNearendDetection config_;
+ const size_t num_capture_channels_;
+ std::vector<aec3::MovingAverage> nearend_smoothers_;
+ const float one_over_subband_length1_;
+ const float one_over_subband_length2_;
+ bool nearend_state_ = false;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SUBBAND_NEAREND_DETECTOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/subtractor.cc b/webrtc/modules/audio_processing/aec3/subtractor.cc
new file mode 100644
index 0000000..d152299
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subtractor.cc
@@ -0,0 +1,325 @@
+/*
+ * 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/audio_processing/aec3/subtractor.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+
+namespace {
+
+void PredictionError(const Aec3Fft& fft,
+ const FftData& S,
+ rtc::ArrayView<const float> y,
+ std::array<float, kBlockSize>* e,
+ std::array<float, kBlockSize>* s) {
+ std::array<float, kFftLength> tmp;
+ fft.Ifft(S, &tmp);
+ constexpr float kScale = 1.0f / kFftLengthBy2;
+ std::transform(y.begin(), y.end(), tmp.begin() + kFftLengthBy2, e->begin(),
+ [&](float a, float b) { return a - b * kScale; });
+
+ if (s) {
+ for (size_t k = 0; k < s->size(); ++k) {
+ (*s)[k] = kScale * tmp[k + kFftLengthBy2];
+ }
+ }
+}
+
+void ScaleFilterOutput(rtc::ArrayView<const float> y,
+ float factor,
+ rtc::ArrayView<float> e,
+ rtc::ArrayView<float> s) {
+ RTC_DCHECK_EQ(y.size(), e.size());
+ RTC_DCHECK_EQ(y.size(), s.size());
+ for (size_t k = 0; k < y.size(); ++k) {
+ s[k] *= factor;
+ e[k] = y[k] - s[k];
+ }
+}
+
+} // namespace
+
+Subtractor::Subtractor(const EchoCanceller3Config& config,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ ApmDataDumper* data_dumper,
+ Aec3Optimization optimization)
+ : fft_(),
+ data_dumper_(data_dumper),
+ optimization_(optimization),
+ config_(config),
+ num_capture_channels_(num_capture_channels),
+ refined_filters_(num_capture_channels_),
+ coarse_filter_(num_capture_channels_),
+ refined_gains_(num_capture_channels_),
+ coarse_gains_(num_capture_channels_),
+ filter_misadjustment_estimators_(num_capture_channels_),
+ poor_coarse_filter_counters_(num_capture_channels_, 0),
+ refined_frequency_responses_(
+ num_capture_channels_,
+ std::vector<std::array<float, kFftLengthBy2Plus1>>(
+ std::max(config_.filter.refined_initial.length_blocks,
+ config_.filter.refined.length_blocks),
+ std::array<float, kFftLengthBy2Plus1>())),
+ refined_impulse_responses_(
+ num_capture_channels_,
+ std::vector<float>(GetTimeDomainLength(std::max(
+ config_.filter.refined_initial.length_blocks,
+ config_.filter.refined.length_blocks)),
+ 0.f)) {
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ refined_filters_[ch] = std::make_unique<AdaptiveFirFilter>(
+ config_.filter.refined.length_blocks,
+ config_.filter.refined_initial.length_blocks,
+ config.filter.config_change_duration_blocks, num_render_channels,
+ optimization, data_dumper_);
+
+ coarse_filter_[ch] = std::make_unique<AdaptiveFirFilter>(
+ config_.filter.coarse.length_blocks,
+ config_.filter.coarse_initial.length_blocks,
+ config.filter.config_change_duration_blocks, num_render_channels,
+ optimization, data_dumper_);
+ refined_gains_[ch] = std::make_unique<RefinedFilterUpdateGain>(
+ config_.filter.refined_initial,
+ config_.filter.config_change_duration_blocks);
+ coarse_gains_[ch] = std::make_unique<CoarseFilterUpdateGain>(
+ config_.filter.coarse_initial,
+ config.filter.config_change_duration_blocks);
+ }
+
+ RTC_DCHECK(data_dumper_);
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ for (auto& H2_k : refined_frequency_responses_[ch]) {
+ H2_k.fill(0.f);
+ }
+ }
+}
+
+Subtractor::~Subtractor() = default;
+
+void Subtractor::HandleEchoPathChange(
+ const EchoPathVariability& echo_path_variability) {
+ const auto full_reset = [&]() {
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ refined_filters_[ch]->HandleEchoPathChange();
+ coarse_filter_[ch]->HandleEchoPathChange();
+ refined_gains_[ch]->HandleEchoPathChange(echo_path_variability);
+ coarse_gains_[ch]->HandleEchoPathChange();
+ refined_gains_[ch]->SetConfig(config_.filter.refined_initial, true);
+ coarse_gains_[ch]->SetConfig(config_.filter.coarse_initial, true);
+ refined_filters_[ch]->SetSizePartitions(
+ config_.filter.refined_initial.length_blocks, true);
+ coarse_filter_[ch]->SetSizePartitions(
+ config_.filter.coarse_initial.length_blocks, true);
+ }
+ };
+
+ if (echo_path_variability.delay_change !=
+ EchoPathVariability::DelayAdjustment::kNone) {
+ full_reset();
+ }
+
+ if (echo_path_variability.gain_change) {
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ refined_gains_[ch]->HandleEchoPathChange(echo_path_variability);
+ }
+ }
+}
+
+void Subtractor::ExitInitialState() {
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ refined_gains_[ch]->SetConfig(config_.filter.refined, false);
+ coarse_gains_[ch]->SetConfig(config_.filter.coarse, false);
+ refined_filters_[ch]->SetSizePartitions(
+ config_.filter.refined.length_blocks, false);
+ coarse_filter_[ch]->SetSizePartitions(config_.filter.coarse.length_blocks,
+ false);
+ }
+}
+
+void Subtractor::Process(const RenderBuffer& render_buffer,
+ const std::vector<std::vector<float>>& capture,
+ const RenderSignalAnalyzer& render_signal_analyzer,
+ const AecState& aec_state,
+ rtc::ArrayView<SubtractorOutput> outputs) {
+ RTC_DCHECK_EQ(num_capture_channels_, capture.size());
+
+ // Compute the render powers.
+ const bool same_filter_sizes = refined_filters_[0]->SizePartitions() ==
+ coarse_filter_[0]->SizePartitions();
+ std::array<float, kFftLengthBy2Plus1> X2_refined;
+ std::array<float, kFftLengthBy2Plus1> X2_coarse_data;
+ auto& X2_coarse = same_filter_sizes ? X2_refined : X2_coarse_data;
+ if (same_filter_sizes) {
+ render_buffer.SpectralSum(refined_filters_[0]->SizePartitions(),
+ &X2_refined);
+ } else if (refined_filters_[0]->SizePartitions() >
+ coarse_filter_[0]->SizePartitions()) {
+ render_buffer.SpectralSums(coarse_filter_[0]->SizePartitions(),
+ refined_filters_[0]->SizePartitions(),
+ &X2_coarse, &X2_refined);
+ } else {
+ render_buffer.SpectralSums(refined_filters_[0]->SizePartitions(),
+ coarse_filter_[0]->SizePartitions(), &X2_refined,
+ &X2_coarse);
+ }
+
+ // Process all capture channels
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ RTC_DCHECK_EQ(kBlockSize, capture[ch].size());
+ SubtractorOutput& output = outputs[ch];
+ rtc::ArrayView<const float> y = capture[ch];
+ FftData& E_refined = output.E_refined;
+ FftData E_coarse;
+ std::array<float, kBlockSize>& e_refined = output.e_refined;
+ std::array<float, kBlockSize>& e_coarse = output.e_coarse;
+
+ FftData S;
+ FftData& G = S;
+
+ // Form the outputs of the refined and coarse filters.
+ refined_filters_[ch]->Filter(render_buffer, &S);
+ PredictionError(fft_, S, y, &e_refined, &output.s_refined);
+
+ coarse_filter_[ch]->Filter(render_buffer, &S);
+ PredictionError(fft_, S, y, &e_coarse, &output.s_coarse);
+
+ // Compute the signal powers in the subtractor output.
+ output.ComputeMetrics(y);
+
+ // Adjust the filter if needed.
+ bool refined_filters_adjusted = false;
+ filter_misadjustment_estimators_[ch].Update(output);
+ if (filter_misadjustment_estimators_[ch].IsAdjustmentNeeded()) {
+ float scale = filter_misadjustment_estimators_[ch].GetMisadjustment();
+ refined_filters_[ch]->ScaleFilter(scale);
+ for (auto& h_k : refined_impulse_responses_[ch]) {
+ h_k *= scale;
+ }
+ ScaleFilterOutput(y, scale, e_refined, output.s_refined);
+ filter_misadjustment_estimators_[ch].Reset();
+ refined_filters_adjusted = true;
+ }
+
+ // Compute the FFts of the refined and coarse filter outputs.
+ fft_.ZeroPaddedFft(e_refined, Aec3Fft::Window::kHanning, &E_refined);
+ fft_.ZeroPaddedFft(e_coarse, Aec3Fft::Window::kHanning, &E_coarse);
+
+ // Compute spectra for future use.
+ E_coarse.Spectrum(optimization_, output.E2_coarse);
+ E_refined.Spectrum(optimization_, output.E2_refined);
+
+ // Update the refined filter.
+ if (!refined_filters_adjusted) {
+ std::array<float, kFftLengthBy2Plus1> erl;
+ ComputeErl(optimization_, refined_frequency_responses_[ch], erl);
+ refined_gains_[ch]->Compute(X2_refined, render_signal_analyzer, output,
+ erl, refined_filters_[ch]->SizePartitions(),
+ aec_state.SaturatedCapture(), &G);
+ } else {
+ G.re.fill(0.f);
+ G.im.fill(0.f);
+ }
+ refined_filters_[ch]->Adapt(render_buffer, G,
+ &refined_impulse_responses_[ch]);
+ refined_filters_[ch]->ComputeFrequencyResponse(
+ &refined_frequency_responses_[ch]);
+
+ if (ch == 0) {
+ data_dumper_->DumpRaw("aec3_subtractor_G_refined", G.re);
+ data_dumper_->DumpRaw("aec3_subtractor_G_refined", G.im);
+ }
+
+ // Update the coarse filter.
+ poor_coarse_filter_counters_[ch] =
+ output.e2_refined < output.e2_coarse
+ ? poor_coarse_filter_counters_[ch] + 1
+ : 0;
+ if (poor_coarse_filter_counters_[ch] < 5) {
+ coarse_gains_[ch]->Compute(X2_coarse, render_signal_analyzer, E_coarse,
+ coarse_filter_[ch]->SizePartitions(),
+ aec_state.SaturatedCapture(), &G);
+ } else {
+ poor_coarse_filter_counters_[ch] = 0;
+ coarse_filter_[ch]->SetFilter(refined_filters_[ch]->SizePartitions(),
+ refined_filters_[ch]->GetFilter());
+ coarse_gains_[ch]->Compute(X2_coarse, render_signal_analyzer, E_refined,
+ coarse_filter_[ch]->SizePartitions(),
+ aec_state.SaturatedCapture(), &G);
+ }
+
+ coarse_filter_[ch]->Adapt(render_buffer, G);
+ if (ch == 0) {
+ data_dumper_->DumpRaw("aec3_subtractor_G_coarse", G.re);
+ data_dumper_->DumpRaw("aec3_subtractor_G_coarse", G.im);
+ filter_misadjustment_estimators_[ch].Dump(data_dumper_);
+ DumpFilters();
+ }
+
+ std::for_each(e_refined.begin(), e_refined.end(),
+ [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
+
+ if (ch == 0) {
+ data_dumper_->DumpWav("aec3_refined_filters_output", kBlockSize,
+ &e_refined[0], 16000, 1);
+ data_dumper_->DumpWav("aec3_coarse_filter_output", kBlockSize,
+ &e_coarse[0], 16000, 1);
+ }
+ }
+}
+
+void Subtractor::FilterMisadjustmentEstimator::Update(
+ const SubtractorOutput& output) {
+ e2_acum_ += output.e2_refined;
+ y2_acum_ += output.y2;
+ if (++n_blocks_acum_ == n_blocks_) {
+ if (y2_acum_ > n_blocks_ * 200.f * 200.f * kBlockSize) {
+ float update = (e2_acum_ / y2_acum_);
+ if (e2_acum_ > n_blocks_ * 7500.f * 7500.f * kBlockSize) {
+ // Duration equal to blockSizeMs * n_blocks_ * 4.
+ overhang_ = 4;
+ } else {
+ overhang_ = std::max(overhang_ - 1, 0);
+ }
+
+ if ((update < inv_misadjustment_) || (overhang_ > 0)) {
+ inv_misadjustment_ += 0.1f * (update - inv_misadjustment_);
+ }
+ }
+ e2_acum_ = 0.f;
+ y2_acum_ = 0.f;
+ n_blocks_acum_ = 0;
+ }
+}
+
+void Subtractor::FilterMisadjustmentEstimator::Reset() {
+ e2_acum_ = 0.f;
+ y2_acum_ = 0.f;
+ n_blocks_acum_ = 0;
+ inv_misadjustment_ = 0.f;
+ overhang_ = 0.f;
+}
+
+void Subtractor::FilterMisadjustmentEstimator::Dump(
+ ApmDataDumper* data_dumper) const {
+ data_dumper->DumpRaw("aec3_inv_misadjustment_factor", inv_misadjustment_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/subtractor.h b/webrtc/modules/audio_processing/aec3/subtractor.h
new file mode 100644
index 0000000..42ca372
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subtractor.h
@@ -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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_H_
+
+#include <math.h>
+#include <stddef.h>
+
+#include <array>
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/adaptive_fir_filter.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec3_fft.h"
+#include "modules/audio_processing/aec3/aec_state.h"
+#include "modules/audio_processing/aec3/coarse_filter_update_gain.h"
+#include "modules/audio_processing/aec3/echo_path_variability.h"
+#include "modules/audio_processing/aec3/refined_filter_update_gain.h"
+#include "modules/audio_processing/aec3/render_buffer.h"
+#include "modules/audio_processing/aec3/render_signal_analyzer.h"
+#include "modules/audio_processing/aec3/subtractor_output.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// Proves linear echo cancellation functionality
+class Subtractor {
+ public:
+ Subtractor(const EchoCanceller3Config& config,
+ size_t num_render_channels,
+ size_t num_capture_channels,
+ ApmDataDumper* data_dumper,
+ Aec3Optimization optimization);
+ ~Subtractor();
+ Subtractor(const Subtractor&) = delete;
+ Subtractor& operator=(const Subtractor&) = delete;
+
+ // Performs the echo subtraction.
+ void Process(const RenderBuffer& render_buffer,
+ const std::vector<std::vector<float>>& capture,
+ const RenderSignalAnalyzer& render_signal_analyzer,
+ const AecState& aec_state,
+ rtc::ArrayView<SubtractorOutput> outputs);
+
+ void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
+
+ // Exits the initial state.
+ void ExitInitialState();
+
+ // Returns the block-wise frequency responses for the refined adaptive
+ // filters.
+ const std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>&
+ FilterFrequencyResponses() const {
+ return refined_frequency_responses_;
+ }
+
+ // Returns the estimates of the impulse responses for the refined adaptive
+ // filters.
+ const std::vector<std::vector<float>>& FilterImpulseResponses() const {
+ return refined_impulse_responses_;
+ }
+
+ void DumpFilters() {
+ data_dumper_->DumpRaw(
+ "aec3_subtractor_h_refined",
+ rtc::ArrayView<const float>(
+ refined_impulse_responses_[0].data(),
+ GetTimeDomainLength(
+ refined_filters_[0]->max_filter_size_partitions())));
+
+ refined_filters_[0]->DumpFilter("aec3_subtractor_H_refined");
+ coarse_filter_[0]->DumpFilter("aec3_subtractor_H_coarse");
+ }
+
+ private:
+ class FilterMisadjustmentEstimator {
+ public:
+ FilterMisadjustmentEstimator() = default;
+ ~FilterMisadjustmentEstimator() = default;
+ // Update the misadjustment estimator.
+ void Update(const SubtractorOutput& output);
+ // GetMisadjustment() Returns a recommended scale for the filter so the
+ // prediction error energy gets closer to the energy that is seen at the
+ // microphone input.
+ float GetMisadjustment() const {
+ RTC_DCHECK_GT(inv_misadjustment_, 0.0f);
+ // It is not aiming to adjust all the estimated mismatch. Instead,
+ // it adjusts half of that estimated mismatch.
+ return 2.f / sqrtf(inv_misadjustment_);
+ }
+ // Returns true if the prediciton error energy is significantly larger
+ // than the microphone signal energy and, therefore, an adjustment is
+ // recommended.
+ bool IsAdjustmentNeeded() const { return inv_misadjustment_ > 10.f; }
+ void Reset();
+ void Dump(ApmDataDumper* data_dumper) const;
+
+ private:
+ const int n_blocks_ = 4;
+ int n_blocks_acum_ = 0;
+ float e2_acum_ = 0.f;
+ float y2_acum_ = 0.f;
+ float inv_misadjustment_ = 0.f;
+ int overhang_ = 0.f;
+ };
+
+ const Aec3Fft fft_;
+ ApmDataDumper* data_dumper_;
+ const Aec3Optimization optimization_;
+ const EchoCanceller3Config config_;
+ const size_t num_capture_channels_;
+
+ std::vector<std::unique_ptr<AdaptiveFirFilter>> refined_filters_;
+ std::vector<std::unique_ptr<AdaptiveFirFilter>> coarse_filter_;
+ std::vector<std::unique_ptr<RefinedFilterUpdateGain>> refined_gains_;
+ std::vector<std::unique_ptr<CoarseFilterUpdateGain>> coarse_gains_;
+ std::vector<FilterMisadjustmentEstimator> filter_misadjustment_estimators_;
+ std::vector<size_t> poor_coarse_filter_counters_;
+ std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
+ refined_frequency_responses_;
+ std::vector<std::vector<float>> refined_impulse_responses_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_H_
diff --git a/webrtc/modules/audio_processing/aec3/subtractor_output.cc b/webrtc/modules/audio_processing/aec3/subtractor_output.cc
new file mode 100644
index 0000000..ed80101
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subtractor_output.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/subtractor_output.h"
+
+#include <numeric>
+
+namespace webrtc {
+
+SubtractorOutput::SubtractorOutput() = default;
+SubtractorOutput::~SubtractorOutput() = default;
+
+void SubtractorOutput::Reset() {
+ s_refined.fill(0.f);
+ s_coarse.fill(0.f);
+ e_refined.fill(0.f);
+ e_coarse.fill(0.f);
+ E_refined.re.fill(0.f);
+ E_refined.im.fill(0.f);
+ E2_refined.fill(0.f);
+ E2_coarse.fill(0.f);
+ e2_refined = 0.f;
+ e2_coarse = 0.f;
+ s2_refined = 0.f;
+ s2_coarse = 0.f;
+ y2 = 0.f;
+}
+
+void SubtractorOutput::ComputeMetrics(rtc::ArrayView<const float> y) {
+ const auto sum_of_squares = [](float a, float b) { return a + b * b; };
+ y2 = std::accumulate(y.begin(), y.end(), 0.f, sum_of_squares);
+ e2_refined =
+ std::accumulate(e_refined.begin(), e_refined.end(), 0.f, sum_of_squares);
+ e2_coarse =
+ std::accumulate(e_coarse.begin(), e_coarse.end(), 0.f, sum_of_squares);
+ s2_refined =
+ std::accumulate(s_refined.begin(), s_refined.end(), 0.f, sum_of_squares);
+ s2_coarse =
+ std::accumulate(s_coarse.begin(), s_coarse.end(), 0.f, sum_of_squares);
+
+ s_refined_max_abs = *std::max_element(s_refined.begin(), s_refined.end());
+ s_refined_max_abs =
+ std::max(s_refined_max_abs,
+ -(*std::min_element(s_refined.begin(), s_refined.end())));
+
+ s_coarse_max_abs = *std::max_element(s_coarse.begin(), s_coarse.end());
+ s_coarse_max_abs = std::max(
+ s_coarse_max_abs, -(*std::min_element(s_coarse.begin(), s_coarse.end())));
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/subtractor_output.h b/webrtc/modules/audio_processing/aec3/subtractor_output.h
new file mode 100644
index 0000000..d2d1208
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subtractor_output.h
@@ -0,0 +1,52 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+
+namespace webrtc {
+
+// Stores the values being returned from the echo subtractor for a single
+// capture channel.
+struct SubtractorOutput {
+ SubtractorOutput();
+ ~SubtractorOutput();
+
+ std::array<float, kBlockSize> s_refined;
+ std::array<float, kBlockSize> s_coarse;
+ std::array<float, kBlockSize> e_refined;
+ std::array<float, kBlockSize> e_coarse;
+ FftData E_refined;
+ std::array<float, kFftLengthBy2Plus1> E2_refined;
+ std::array<float, kFftLengthBy2Plus1> E2_coarse;
+ float s2_refined = 0.f;
+ float s2_coarse = 0.f;
+ float e2_refined = 0.f;
+ float e2_coarse = 0.f;
+ float y2 = 0.f;
+ float s_refined_max_abs = 0.f;
+ float s_coarse_max_abs = 0.f;
+
+ // Reset the struct content.
+ void Reset();
+
+ // Updates the powers of the signals.
+ void ComputeMetrics(rtc::ArrayView<const float> y);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_H_
diff --git a/webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.cc b/webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.cc
new file mode 100644
index 0000000..8b22185
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
+
+#include <algorithm>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+SubtractorOutputAnalyzer::SubtractorOutputAnalyzer(size_t num_capture_channels)
+ : filters_converged_(num_capture_channels, false) {}
+
+void SubtractorOutputAnalyzer::Update(
+ rtc::ArrayView<const SubtractorOutput> subtractor_output,
+ bool* any_filter_converged,
+ bool* all_filters_diverged) {
+ RTC_DCHECK(any_filter_converged);
+ RTC_DCHECK(all_filters_diverged);
+ RTC_DCHECK_EQ(subtractor_output.size(), filters_converged_.size());
+
+ *any_filter_converged = false;
+ *all_filters_diverged = true;
+
+ for (size_t ch = 0; ch < subtractor_output.size(); ++ch) {
+ const float y2 = subtractor_output[ch].y2;
+ const float e2_refined = subtractor_output[ch].e2_refined;
+ const float e2_coarse = subtractor_output[ch].e2_coarse;
+
+ constexpr float kConvergenceThreshold = 50 * 50 * kBlockSize;
+ bool refined_filter_converged =
+ e2_refined < 0.5f * y2 && y2 > kConvergenceThreshold;
+ bool coarse_filter_converged =
+ e2_coarse < 0.05f * y2 && y2 > kConvergenceThreshold;
+ float min_e2 = std::min(e2_refined, e2_coarse);
+ bool filter_diverged = min_e2 > 1.5f * y2 && y2 > 30.f * 30.f * kBlockSize;
+ filters_converged_[ch] =
+ refined_filter_converged || coarse_filter_converged;
+
+ *any_filter_converged = *any_filter_converged || filters_converged_[ch];
+ *all_filters_diverged = *all_filters_diverged && filter_diverged;
+ }
+}
+
+void SubtractorOutputAnalyzer::HandleEchoPathChange() {
+ std::fill(filters_converged_.begin(), filters_converged_.end(), false);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.h b/webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.h
new file mode 100644
index 0000000..5328ae7
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/subtractor_output_analyzer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_
+
+#include <vector>
+
+#include "modules/audio_processing/aec3/subtractor_output.h"
+
+namespace webrtc {
+
+// Class for analyzing the properties subtractor output.
+class SubtractorOutputAnalyzer {
+ public:
+ explicit SubtractorOutputAnalyzer(size_t num_capture_channels);
+ ~SubtractorOutputAnalyzer() = default;
+
+ // Analyses the subtractor output.
+ void Update(rtc::ArrayView<const SubtractorOutput> subtractor_output,
+ bool* any_filter_converged,
+ bool* all_filters_diverged);
+
+ const std::vector<bool>& ConvergedFilters() const {
+ return filters_converged_;
+ }
+
+ // Handle echo path change.
+ void HandleEchoPathChange();
+
+ private:
+ std::vector<bool> filters_converged_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SUBTRACTOR_OUTPUT_ANALYZER_H_
diff --git a/webrtc/modules/audio_processing/aec3/suppression_filter.cc b/webrtc/modules/audio_processing/aec3/suppression_filter.cc
new file mode 100644
index 0000000..8a813d9
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/suppression_filter.cc
@@ -0,0 +1,179 @@
+/*
+ * 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/audio_processing/aec3/suppression_filter.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstring>
+#include <functional>
+#include <iterator>
+
+#include "modules/audio_processing/aec3/vector_math.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+namespace {
+
+// Hanning window from Matlab command win = sqrt(hanning(128)).
+const float kSqrtHanning[kFftLength] = {
+ 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
+ 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
+ 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
+ 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
+ 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
+ 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
+ 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
+ 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
+ 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
+ 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
+ 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
+ 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
+ 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
+ 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
+ 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
+ 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
+ 1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
+ 0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f,
+ 0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f,
+ 0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
+ 0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f,
+ 0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f,
+ 0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
+ 0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f,
+ 0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f,
+ 0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
+ 0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f,
+ 0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f,
+ 0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
+ 0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f,
+ 0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f,
+ 0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f};
+
+} // namespace
+
+SuppressionFilter::SuppressionFilter(Aec3Optimization optimization,
+ int sample_rate_hz,
+ size_t num_capture_channels)
+ : optimization_(optimization),
+ sample_rate_hz_(sample_rate_hz),
+ num_capture_channels_(num_capture_channels),
+ fft_(),
+ e_output_old_(NumBandsForRate(sample_rate_hz_),
+ std::vector<std::array<float, kFftLengthBy2>>(
+ num_capture_channels_)) {
+ RTC_DCHECK(ValidFullBandRate(sample_rate_hz_));
+ for (size_t b = 0; b < e_output_old_.size(); ++b) {
+ for (size_t ch = 0; ch < e_output_old_[b].size(); ++ch) {
+ e_output_old_[b][ch].fill(0.f);
+ }
+ }
+}
+
+SuppressionFilter::~SuppressionFilter() = default;
+
+void SuppressionFilter::ApplyGain(
+ rtc::ArrayView<const FftData> comfort_noise,
+ rtc::ArrayView<const FftData> comfort_noise_high_band,
+ const std::array<float, kFftLengthBy2Plus1>& suppression_gain,
+ float high_bands_gain,
+ rtc::ArrayView<const FftData> E_lowest_band,
+ std::vector<std::vector<std::vector<float>>>* e) {
+ RTC_DCHECK(e);
+ RTC_DCHECK_EQ(e->size(), NumBandsForRate(sample_rate_hz_));
+
+ // Comfort noise gain is sqrt(1-g^2), where g is the suppression gain.
+ std::array<float, kFftLengthBy2Plus1> noise_gain;
+ for (size_t i = 0; i < kFftLengthBy2Plus1; ++i) {
+ noise_gain[i] = 1.f - suppression_gain[i] * suppression_gain[i];
+ }
+ aec3::VectorMath(optimization_).Sqrt(noise_gain);
+
+ const float high_bands_noise_scaling =
+ 0.4f * std::sqrt(1.f - high_bands_gain * high_bands_gain);
+
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ FftData E;
+
+ // Analysis filterbank.
+ E.Assign(E_lowest_band[ch]);
+
+ for (size_t i = 0; i < kFftLengthBy2Plus1; ++i) {
+ // Apply suppression gains.
+ E.re[i] *= suppression_gain[i];
+ E.im[i] *= suppression_gain[i];
+
+ // Scale and add the comfort noise.
+ E.re[i] += noise_gain[i] * comfort_noise[ch].re[i];
+ E.im[i] += noise_gain[i] * comfort_noise[ch].im[i];
+ }
+
+ // Synthesis filterbank.
+ std::array<float, kFftLength> e_extended;
+ constexpr float kIfftNormalization = 2.f / kFftLength;
+ fft_.Ifft(E, &e_extended);
+
+ auto& e0 = (*e)[0][ch];
+ auto& e0_old = e_output_old_[0][ch];
+
+ // Window and add the first half of e_extended with the second half of
+ // e_extended from the previous block.
+ for (size_t i = 0; i < kFftLengthBy2; ++i) {
+ e0[i] = e0_old[i] * kSqrtHanning[kFftLengthBy2 + i];
+ e0[i] += e_extended[i] * kSqrtHanning[i];
+ e0[i] *= kIfftNormalization;
+ }
+
+ // The second half of e_extended is stored for the succeeding frame.
+ std::copy(e_extended.begin() + kFftLengthBy2,
+ e_extended.begin() + kFftLength, std::begin(e0_old));
+
+ // Apply suppression gain to upper bands.
+ for (size_t b = 1; b < e->size(); ++b) {
+ auto& e_band = (*e)[b][ch];
+ for (size_t i = 0; i < kFftLengthBy2; ++i) {
+ e_band[i] *= high_bands_gain;
+ }
+ }
+
+ // Add comfort noise to band 1.
+ if (e->size() > 1) {
+ E.Assign(comfort_noise_high_band[ch]);
+ std::array<float, kFftLength> time_domain_high_band_noise;
+ fft_.Ifft(E, &time_domain_high_band_noise);
+
+ auto& e1 = (*e)[1][ch];
+ const float gain = high_bands_noise_scaling * kIfftNormalization;
+ for (size_t i = 0; i < kFftLengthBy2; ++i) {
+ e1[i] += time_domain_high_band_noise[i] * gain;
+ }
+ }
+
+ // Delay upper bands to match the delay of the filter bank.
+ for (size_t b = 1; b < e->size(); ++b) {
+ auto& e_band = (*e)[b][ch];
+ auto& e_band_old = e_output_old_[b][ch];
+ for (size_t i = 0; i < kFftLengthBy2; ++i) {
+ std::swap(e_band[i], e_band_old[i]);
+ }
+ }
+
+ // Clamp output of all bands.
+ for (size_t b = 0; b < e->size(); ++b) {
+ auto& e_band = (*e)[b][ch];
+ for (size_t i = 0; i < kFftLengthBy2; ++i) {
+ e_band[i] = rtc::SafeClamp(e_band[i], -32768.f, 32767.f);
+ }
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/suppression_filter.h b/webrtc/modules/audio_processing/aec3/suppression_filter.h
new file mode 100644
index 0000000..dcf2292
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/suppression_filter.h
@@ -0,0 +1,48 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_SUPPRESSION_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_FILTER_H_
+
+#include <array>
+#include <vector>
+
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec3_fft.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class SuppressionFilter {
+ public:
+ SuppressionFilter(Aec3Optimization optimization,
+ int sample_rate_hz,
+ size_t num_capture_channels_);
+ ~SuppressionFilter();
+ void ApplyGain(rtc::ArrayView<const FftData> comfort_noise,
+ rtc::ArrayView<const FftData> comfort_noise_high_bands,
+ const std::array<float, kFftLengthBy2Plus1>& suppression_gain,
+ float high_bands_gain,
+ rtc::ArrayView<const FftData> E_lowest_band,
+ std::vector<std::vector<std::vector<float>>>* e);
+
+ private:
+ const Aec3Optimization optimization_;
+ const int sample_rate_hz_;
+ const size_t num_capture_channels_;
+ const Aec3Fft fft_;
+ std::vector<std::vector<std::array<float, kFftLengthBy2>>> e_output_old_;
+ RTC_DISALLOW_COPY_AND_ASSIGN(SuppressionFilter);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_FILTER_H_
diff --git a/webrtc/modules/audio_processing/aec3/suppression_gain.cc b/webrtc/modules/audio_processing/aec3/suppression_gain.cc
new file mode 100644
index 0000000..c1f12b7
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/suppression_gain.cc
@@ -0,0 +1,438 @@
+/*
+ * 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/audio_processing/aec3/suppression_gain.h"
+
+#include <math.h>
+#include <stddef.h>
+
+#include <algorithm>
+#include <numeric>
+
+#include "modules/audio_processing/aec3/dominant_nearend_detector.h"
+#include "modules/audio_processing/aec3/moving_average.h"
+#include "modules/audio_processing/aec3/subband_nearend_detector.h"
+#include "modules/audio_processing/aec3/vector_math.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+void PostprocessGains(std::array<float, kFftLengthBy2Plus1>* gain) {
+ // TODO(gustaf): Investigate if this can be relaxed to achieve higher
+ // transparency above 2 kHz.
+
+ // Limit the low frequency gains to avoid the impact of the high-pass filter
+ // on the lower-frequency gain influencing the overall achieved gain.
+ (*gain)[0] = (*gain)[1] = std::min((*gain)[1], (*gain)[2]);
+
+ // Limit the high frequency gains to avoid the impact of the anti-aliasing
+ // filter on the upper-frequency gains influencing the overall achieved
+ // gain. TODO(peah): Update this when new anti-aliasing filters are
+ // implemented.
+ constexpr size_t kAntiAliasingImpactLimit = (64 * 2000) / 8000;
+ const float min_upper_gain = (*gain)[kAntiAliasingImpactLimit];
+ std::for_each(
+ gain->begin() + kAntiAliasingImpactLimit, gain->end() - 1,
+ [min_upper_gain](float& a) { a = std::min(a, min_upper_gain); });
+ (*gain)[kFftLengthBy2] = (*gain)[kFftLengthBy2Minus1];
+
+ // Limits the gain in the frequencies for which the adaptive filter has not
+ // converged.
+ // TODO(peah): Make adaptive to take the actual filter error into account.
+ constexpr size_t kUpperAccurateBandPlus1 = 29;
+
+ constexpr float oneByBandsInSum =
+ 1 / static_cast<float>(kUpperAccurateBandPlus1 - 20);
+ const float hf_gain_bound =
+ std::accumulate(gain->begin() + 20,
+ gain->begin() + kUpperAccurateBandPlus1, 0.f) *
+ oneByBandsInSum;
+
+ std::for_each(gain->begin() + kUpperAccurateBandPlus1, gain->end(),
+ [hf_gain_bound](float& a) { a = std::min(a, hf_gain_bound); });
+}
+
+// Scales the echo according to assessed audibility at the other end.
+void WeightEchoForAudibility(const EchoCanceller3Config& config,
+ rtc::ArrayView<const float> echo,
+ rtc::ArrayView<float> weighted_echo) {
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, echo.size());
+ RTC_DCHECK_EQ(kFftLengthBy2Plus1, weighted_echo.size());
+
+ auto weigh = [](float threshold, float normalizer, size_t begin, size_t end,
+ rtc::ArrayView<const float> echo,
+ rtc::ArrayView<float> weighted_echo) {
+ for (size_t k = begin; k < end; ++k) {
+ if (echo[k] < threshold) {
+ float tmp = (threshold - echo[k]) * normalizer;
+ weighted_echo[k] = echo[k] * std::max(0.f, 1.f - tmp * tmp);
+ } else {
+ weighted_echo[k] = echo[k];
+ }
+ }
+ };
+
+ float threshold = config.echo_audibility.floor_power *
+ config.echo_audibility.audibility_threshold_lf;
+ float normalizer = 1.f / (threshold - config.echo_audibility.floor_power);
+ weigh(threshold, normalizer, 0, 3, echo, weighted_echo);
+
+ threshold = config.echo_audibility.floor_power *
+ config.echo_audibility.audibility_threshold_mf;
+ normalizer = 1.f / (threshold - config.echo_audibility.floor_power);
+ weigh(threshold, normalizer, 3, 7, echo, weighted_echo);
+
+ threshold = config.echo_audibility.floor_power *
+ config.echo_audibility.audibility_threshold_hf;
+ normalizer = 1.f / (threshold - config.echo_audibility.floor_power);
+ weigh(threshold, normalizer, 7, kFftLengthBy2Plus1, echo, weighted_echo);
+}
+
+} // namespace
+
+int SuppressionGain::instance_count_ = 0;
+
+float SuppressionGain::UpperBandsGain(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ const absl::optional<int>& narrow_peak_band,
+ bool saturated_echo,
+ const std::vector<std::vector<std::vector<float>>>& render,
+ const std::array<float, kFftLengthBy2Plus1>& low_band_gain) const {
+ RTC_DCHECK_LT(0, render.size());
+ if (render.size() == 1) {
+ return 1.f;
+ }
+ const size_t num_render_channels = render[0].size();
+
+ if (narrow_peak_band &&
+ (*narrow_peak_band > static_cast<int>(kFftLengthBy2Plus1 - 10))) {
+ return 0.001f;
+ }
+
+ constexpr size_t kLowBandGainLimit = kFftLengthBy2 / 2;
+ const float gain_below_8_khz = *std::min_element(
+ low_band_gain.begin() + kLowBandGainLimit, low_band_gain.end());
+
+ // Always attenuate the upper bands when there is saturated echo.
+ if (saturated_echo) {
+ return std::min(0.001f, gain_below_8_khz);
+ }
+
+ // Compute the upper and lower band energies.
+ const auto sum_of_squares = [](float a, float b) { return a + b * b; };
+ float low_band_energy = 0.f;
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const float channel_energy = std::accumulate(
+ render[0][0].begin(), render[0][0].end(), 0.f, sum_of_squares);
+ low_band_energy = std::max(low_band_energy, channel_energy);
+ }
+ float high_band_energy = 0.f;
+ for (size_t k = 1; k < render.size(); ++k) {
+ for (size_t ch = 0; ch < num_render_channels; ++ch) {
+ const float energy = std::accumulate(
+ render[k][ch].begin(), render[k][ch].end(), 0.f, sum_of_squares);
+ high_band_energy = std::max(high_band_energy, energy);
+ }
+ }
+
+ // If there is more power in the lower frequencies than the upper frequencies,
+ // or if the power in upper frequencies is low, do not bound the gain in the
+ // upper bands.
+ float anti_howling_gain;
+ const float activation_threshold =
+ kBlockSize * config_.suppressor.high_bands_suppression
+ .anti_howling_activation_threshold;
+ if (high_band_energy < std::max(low_band_energy, activation_threshold)) {
+ anti_howling_gain = 1.f;
+ } else {
+ // In all other cases, bound the gain for upper frequencies.
+ RTC_DCHECK_LE(low_band_energy, high_band_energy);
+ RTC_DCHECK_NE(0.f, high_band_energy);
+ anti_howling_gain =
+ config_.suppressor.high_bands_suppression.anti_howling_gain *
+ sqrtf(low_band_energy / high_band_energy);
+ }
+
+ float gain_bound = 1.f;
+ if (!dominant_nearend_detector_->IsNearendState()) {
+ // Bound the upper gain during significant echo activity.
+ const auto& cfg = config_.suppressor.high_bands_suppression;
+ auto low_frequency_energy = [](rtc::ArrayView<const float> spectrum) {
+ RTC_DCHECK_LE(16, spectrum.size());
+ return std::accumulate(spectrum.begin() + 1, spectrum.begin() + 16, 0.f);
+ };
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ const float echo_sum = low_frequency_energy(echo_spectrum[ch]);
+ const float noise_sum = low_frequency_energy(comfort_noise_spectrum[ch]);
+ if (echo_sum > cfg.enr_threshold * noise_sum) {
+ gain_bound = cfg.max_gain_during_echo;
+ break;
+ }
+ }
+ }
+
+ // Choose the gain as the minimum of the lower and upper gains.
+ return std::min(std::min(gain_below_8_khz, anti_howling_gain), gain_bound);
+}
+
+// Computes the gain to reduce the echo to a non audible level.
+void SuppressionGain::GainToNoAudibleEcho(
+ const std::array<float, kFftLengthBy2Plus1>& nearend,
+ const std::array<float, kFftLengthBy2Plus1>& echo,
+ const std::array<float, kFftLengthBy2Plus1>& masker,
+ std::array<float, kFftLengthBy2Plus1>* gain) const {
+ const auto& p = dominant_nearend_detector_->IsNearendState() ? nearend_params_
+ : normal_params_;
+ for (size_t k = 0; k < gain->size(); ++k) {
+ float enr = echo[k] / (nearend[k] + 1.f); // Echo-to-nearend ratio.
+ float emr = echo[k] / (masker[k] + 1.f); // Echo-to-masker (noise) ratio.
+ float g = 1.0f;
+ if (enr > p.enr_transparent_[k] && emr > p.emr_transparent_[k]) {
+ g = (p.enr_suppress_[k] - enr) /
+ (p.enr_suppress_[k] - p.enr_transparent_[k]);
+ g = std::max(g, p.emr_transparent_[k] / emr);
+ }
+ (*gain)[k] = g;
+ }
+}
+
+// Compute the minimum gain as the attenuating gain to put the signal just
+// above the zero sample values.
+void SuppressionGain::GetMinGain(
+ rtc::ArrayView<const float> weighted_residual_echo,
+ rtc::ArrayView<const float> last_nearend,
+ rtc::ArrayView<const float> last_echo,
+ bool low_noise_render,
+ bool saturated_echo,
+ rtc::ArrayView<float> min_gain) const {
+ if (!saturated_echo) {
+ const float min_echo_power =
+ low_noise_render ? config_.echo_audibility.low_render_limit
+ : config_.echo_audibility.normal_render_limit;
+
+ for (size_t k = 0; k < min_gain.size(); ++k) {
+ min_gain[k] = weighted_residual_echo[k] > 0.f
+ ? min_echo_power / weighted_residual_echo[k]
+ : 1.f;
+ min_gain[k] = std::min(min_gain[k], 1.f);
+ }
+
+ const bool is_nearend_state = dominant_nearend_detector_->IsNearendState();
+ for (size_t k = 0; k < 6; ++k) {
+ const auto& dec = is_nearend_state ? nearend_params_.max_dec_factor_lf
+ : normal_params_.max_dec_factor_lf;
+
+ // Make sure the gains of the low frequencies do not decrease too
+ // quickly after strong nearend.
+ if (last_nearend[k] > last_echo[k]) {
+ min_gain[k] = std::max(min_gain[k], last_gain_[k] * dec);
+ min_gain[k] = std::min(min_gain[k], 1.f);
+ }
+ }
+ } else {
+ std::fill(min_gain.begin(), min_gain.end(), 0.f);
+ }
+}
+
+// Compute the maximum gain by limiting the gain increase from the previous
+// gain.
+void SuppressionGain::GetMaxGain(rtc::ArrayView<float> max_gain) const {
+ const auto& inc = dominant_nearend_detector_->IsNearendState()
+ ? nearend_params_.max_inc_factor
+ : normal_params_.max_inc_factor;
+ const auto& floor = config_.suppressor.floor_first_increase;
+ for (size_t k = 0; k < max_gain.size(); ++k) {
+ max_gain[k] = std::min(std::max(last_gain_[k] * inc, floor), 1.f);
+ }
+}
+
+void SuppressionGain::LowerBandGain(
+ bool low_noise_render,
+ const AecState& aec_state,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ suppressor_input,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise,
+ std::array<float, kFftLengthBy2Plus1>* gain) {
+ gain->fill(1.f);
+ const bool saturated_echo = aec_state.SaturatedEcho();
+ std::array<float, kFftLengthBy2Plus1> max_gain;
+ GetMaxGain(max_gain);
+
+ for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
+ std::array<float, kFftLengthBy2Plus1> G;
+ std::array<float, kFftLengthBy2Plus1> nearend;
+ nearend_smoothers_[ch].Average(suppressor_input[ch], nearend);
+
+ // Weight echo power in terms of audibility.
+ std::array<float, kFftLengthBy2Plus1> weighted_residual_echo;
+ WeightEchoForAudibility(config_, residual_echo[ch], weighted_residual_echo);
+
+ std::array<float, kFftLengthBy2Plus1> min_gain;
+ GetMinGain(weighted_residual_echo, last_nearend_[ch], last_echo_[ch],
+ low_noise_render, saturated_echo, min_gain);
+
+ GainToNoAudibleEcho(nearend, weighted_residual_echo, comfort_noise[0], &G);
+
+ // Clamp gains.
+ for (size_t k = 0; k < gain->size(); ++k) {
+ G[k] = std::max(std::min(G[k], max_gain[k]), min_gain[k]);
+ (*gain)[k] = std::min((*gain)[k], G[k]);
+ }
+
+ // Store data required for the gain computation of the next block.
+ std::copy(nearend.begin(), nearend.end(), last_nearend_[ch].begin());
+ std::copy(weighted_residual_echo.begin(), weighted_residual_echo.end(),
+ last_echo_[ch].begin());
+ }
+
+ // Limit high-frequency gains.
+ PostprocessGains(gain);
+
+ // Store computed gains.
+ std::copy(gain->begin(), gain->end(), last_gain_.begin());
+
+ // Transform gains to amplitude domain.
+ aec3::VectorMath(optimization_).Sqrt(*gain);
+}
+
+SuppressionGain::SuppressionGain(const EchoCanceller3Config& config,
+ Aec3Optimization optimization,
+ int sample_rate_hz,
+ size_t num_capture_channels)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ optimization_(optimization),
+ config_(config),
+ num_capture_channels_(num_capture_channels),
+ state_change_duration_blocks_(
+ static_cast<int>(config_.filter.config_change_duration_blocks)),
+ last_nearend_(num_capture_channels_, {0}),
+ last_echo_(num_capture_channels_, {0}),
+ nearend_smoothers_(
+ num_capture_channels_,
+ aec3::MovingAverage(kFftLengthBy2Plus1,
+ config.suppressor.nearend_average_blocks)),
+ nearend_params_(config_.suppressor.nearend_tuning),
+ normal_params_(config_.suppressor.normal_tuning) {
+ RTC_DCHECK_LT(0, state_change_duration_blocks_);
+ last_gain_.fill(1.f);
+ if (config_.suppressor.use_subband_nearend_detection) {
+ dominant_nearend_detector_ = std::make_unique<SubbandNearendDetector>(
+ config_.suppressor.subband_nearend_detection, num_capture_channels_);
+ } else {
+ dominant_nearend_detector_ = std::make_unique<DominantNearendDetector>(
+ config_.suppressor.dominant_nearend_detection, num_capture_channels_);
+ }
+ RTC_DCHECK(dominant_nearend_detector_);
+}
+
+SuppressionGain::~SuppressionGain() = default;
+
+void SuppressionGain::GetGain(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ nearend_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ residual_echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ const RenderSignalAnalyzer& render_signal_analyzer,
+ const AecState& aec_state,
+ const std::vector<std::vector<std::vector<float>>>& render,
+ float* high_bands_gain,
+ std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
+ RTC_DCHECK(high_bands_gain);
+ RTC_DCHECK(low_band_gain);
+
+ // Update the nearend state selection.
+ dominant_nearend_detector_->Update(nearend_spectrum, residual_echo_spectrum,
+ comfort_noise_spectrum, initial_state_);
+
+ // Compute gain for the lower band.
+ bool low_noise_render = low_render_detector_.Detect(render);
+ LowerBandGain(low_noise_render, aec_state, nearend_spectrum,
+ residual_echo_spectrum, comfort_noise_spectrum, low_band_gain);
+
+ // Compute the gain for the upper bands.
+ const absl::optional<int> narrow_peak_band =
+ render_signal_analyzer.NarrowPeakBand();
+
+ *high_bands_gain =
+ UpperBandsGain(echo_spectrum, comfort_noise_spectrum, narrow_peak_band,
+ aec_state.SaturatedEcho(), render, *low_band_gain);
+}
+
+void SuppressionGain::SetInitialState(bool state) {
+ initial_state_ = state;
+ if (state) {
+ initial_state_change_counter_ = state_change_duration_blocks_;
+ } else {
+ initial_state_change_counter_ = 0;
+ }
+}
+
+// Detects when the render signal can be considered to have low power and
+// consist of stationary noise.
+bool SuppressionGain::LowNoiseRenderDetector::Detect(
+ const std::vector<std::vector<std::vector<float>>>& render) {
+ float x2_sum = 0.f;
+ float x2_max = 0.f;
+ for (const auto& x_ch : render[0]) {
+ for (const auto& x_k : x_ch) {
+ const float x2 = x_k * x_k;
+ x2_sum += x2;
+ x2_max = std::max(x2_max, x2);
+ }
+ }
+ const size_t num_render_channels = render[0].size();
+ x2_sum = x2_sum / num_render_channels;
+ ;
+
+ constexpr float kThreshold = 50.f * 50.f * 64.f;
+ const bool low_noise_render =
+ average_power_ < kThreshold && x2_max < 3 * average_power_;
+ average_power_ = average_power_ * 0.9f + x2_sum * 0.1f;
+ return low_noise_render;
+}
+
+SuppressionGain::GainParameters::GainParameters(
+ const EchoCanceller3Config::Suppressor::Tuning& tuning)
+ : max_inc_factor(tuning.max_inc_factor),
+ max_dec_factor_lf(tuning.max_dec_factor_lf) {
+ // Compute per-band masking thresholds.
+ constexpr size_t kLastLfBand = 5;
+ constexpr size_t kFirstHfBand = 8;
+ RTC_DCHECK_LT(kLastLfBand, kFirstHfBand);
+ auto& lf = tuning.mask_lf;
+ auto& hf = tuning.mask_hf;
+ RTC_DCHECK_LT(lf.enr_transparent, lf.enr_suppress);
+ RTC_DCHECK_LT(hf.enr_transparent, hf.enr_suppress);
+ for (size_t k = 0; k < kFftLengthBy2Plus1; k++) {
+ float a;
+ if (k <= kLastLfBand) {
+ a = 0.f;
+ } else if (k < kFirstHfBand) {
+ a = (k - kLastLfBand) / static_cast<float>(kFirstHfBand - kLastLfBand);
+ } else {
+ a = 1.f;
+ }
+ enr_transparent_[k] = (1 - a) * lf.enr_transparent + a * hf.enr_transparent;
+ enr_suppress_[k] = (1 - a) * lf.enr_suppress + a * hf.enr_suppress;
+ emr_transparent_[k] = (1 - a) * lf.emr_transparent + a * hf.emr_transparent;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/suppression_gain.h b/webrtc/modules/audio_processing/aec3/suppression_gain.h
new file mode 100644
index 0000000..f46db0b
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/suppression_gain.h
@@ -0,0 +1,130 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_H_
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "modules/audio_processing/aec3/aec_state.h"
+#include "modules/audio_processing/aec3/fft_data.h"
+#include "modules/audio_processing/aec3/moving_average.h"
+#include "modules/audio_processing/aec3/nearend_detector.h"
+#include "modules/audio_processing/aec3/render_signal_analyzer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class SuppressionGain {
+ public:
+ SuppressionGain(const EchoCanceller3Config& config,
+ Aec3Optimization optimization,
+ int sample_rate_hz,
+ size_t num_capture_channels);
+ ~SuppressionGain();
+ void GetGain(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ nearend_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ residual_echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ const RenderSignalAnalyzer& render_signal_analyzer,
+ const AecState& aec_state,
+ const std::vector<std::vector<std::vector<float>>>& render,
+ float* high_bands_gain,
+ std::array<float, kFftLengthBy2Plus1>* low_band_gain);
+
+ // Toggles the usage of the initial state.
+ void SetInitialState(bool state);
+
+ private:
+ // Computes the gain to apply for the bands beyond the first band.
+ float UpperBandsGain(
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> echo_spectrum,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ comfort_noise_spectrum,
+ const absl::optional<int>& narrow_peak_band,
+ bool saturated_echo,
+ const std::vector<std::vector<std::vector<float>>>& render,
+ const std::array<float, kFftLengthBy2Plus1>& low_band_gain) const;
+
+ void GainToNoAudibleEcho(const std::array<float, kFftLengthBy2Plus1>& nearend,
+ const std::array<float, kFftLengthBy2Plus1>& echo,
+ const std::array<float, kFftLengthBy2Plus1>& masker,
+ std::array<float, kFftLengthBy2Plus1>* gain) const;
+
+ void LowerBandGain(
+ bool stationary_with_low_power,
+ const AecState& aec_state,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
+ suppressor_input,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> residual_echo,
+ rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> comfort_noise,
+ std::array<float, kFftLengthBy2Plus1>* gain);
+
+ void GetMinGain(rtc::ArrayView<const float> weighted_residual_echo,
+ rtc::ArrayView<const float> last_nearend,
+ rtc::ArrayView<const float> last_echo,
+ bool low_noise_render,
+ bool saturated_echo,
+ rtc::ArrayView<float> min_gain) const;
+
+ void GetMaxGain(rtc::ArrayView<float> max_gain) const;
+
+ class LowNoiseRenderDetector {
+ public:
+ bool Detect(const std::vector<std::vector<std::vector<float>>>& render);
+
+ private:
+ float average_power_ = 32768.f * 32768.f;
+ };
+
+ struct GainParameters {
+ explicit GainParameters(
+ const EchoCanceller3Config::Suppressor::Tuning& tuning);
+ const float max_inc_factor;
+ const float max_dec_factor_lf;
+ std::array<float, kFftLengthBy2Plus1> enr_transparent_;
+ std::array<float, kFftLengthBy2Plus1> enr_suppress_;
+ std::array<float, kFftLengthBy2Plus1> emr_transparent_;
+ };
+
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ const Aec3Optimization optimization_;
+ const EchoCanceller3Config config_;
+ const size_t num_capture_channels_;
+ const int state_change_duration_blocks_;
+ std::array<float, kFftLengthBy2Plus1> last_gain_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> last_nearend_;
+ std::vector<std::array<float, kFftLengthBy2Plus1>> last_echo_;
+ LowNoiseRenderDetector low_render_detector_;
+ bool initial_state_ = true;
+ int initial_state_change_counter_ = 0;
+ std::vector<aec3::MovingAverage> nearend_smoothers_;
+ const GainParameters nearend_params_;
+ const GainParameters normal_params_;
+ std::unique_ptr<NearendDetector> dominant_nearend_detector_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(SuppressionGain);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_H_
diff --git a/webrtc/modules/audio_processing/aec3/transparent_mode.cc b/webrtc/modules/audio_processing/aec3/transparent_mode.cc
new file mode 100644
index 0000000..1820e16
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/transparent_mode.cc
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/transparent_mode.h"
+
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+namespace {
+
+constexpr size_t kBlocksSinceConvergencedFilterInit = 10000;
+constexpr size_t kBlocksSinceConsistentEstimateInit = 10000;
+
+bool DeactivateTransparentMode() {
+ return field_trial::IsEnabled("WebRTC-Aec3TransparentModeKillSwitch");
+}
+
+bool DeactivateTransparentModeHmm() {
+ return field_trial::IsEnabled("WebRTC-Aec3TransparentModeHmmKillSwitch");
+}
+
+} // namespace
+
+// Classifier that toggles transparent mode which reduces echo suppression when
+// headsets are used.
+class TransparentModeImpl : public TransparentMode {
+ public:
+ bool Active() const override { return transparency_activated_; }
+
+ void Reset() override {
+ // Determines if transparent mode is used.
+ transparency_activated_ = false;
+
+ // The estimated probability of being transparent mode.
+ prob_transparent_state_ = 0.f;
+ }
+
+ void Update(int filter_delay_blocks,
+ bool any_filter_consistent,
+ bool any_filter_converged,
+ bool all_filters_diverged,
+ bool active_render,
+ bool saturated_capture) override {
+ // The classifier is implemented as a Hidden Markov Model (HMM) with two
+ // hidden states: "normal" and "transparent". The estimated probabilities of
+ // the two states are updated by observing filter convergence during active
+ // render. The filters are less likely to be reported as converged when
+ // there is no echo present in the microphone signal.
+
+ // The constants have been obtained by observing active_render and
+ // any_filter_converged under varying call scenarios. They have further been
+ // hand tuned to prefer normal state during uncertain regions (to avoid echo
+ // leaks).
+
+ // The model is only updated during active render.
+ if (!active_render)
+ return;
+
+ // Probability of switching from one state to the other.
+ constexpr float kSwitch = 0.000001f;
+
+ // Probability of observing converged filters in states "normal" and
+ // "transparent" during active render.
+ constexpr float kConvergedNormal = 0.03f;
+ constexpr float kConvergedTransparent = 0.005f;
+
+ // Probability of transitioning to transparent state from normal state and
+ // transparent state respectively.
+ constexpr float kA[2] = {kSwitch, 1.f - kSwitch};
+
+ // Probability of the two observations (converged filter or not converged
+ // filter) in normal state and transparent state respectively.
+ constexpr float kB[2][2] = {
+ {1.f - kConvergedNormal, kConvergedNormal},
+ {1.f - kConvergedTransparent, kConvergedTransparent}};
+
+ // Probability of the two states before the update.
+ const float prob_transparent = prob_transparent_state_;
+ const float prob_normal = 1.f - prob_transparent;
+
+ // Probability of transitioning to transparent state.
+ const float prob_transition_transparent =
+ prob_normal * kA[0] + prob_transparent * kA[1];
+ const float prob_transition_normal = 1.f - prob_transition_transparent;
+
+ // Observed output.
+ const int out = any_filter_converged;
+
+ // Joint probabilites of the observed output and respective states.
+ const float prob_joint_normal = prob_transition_normal * kB[0][out];
+ const float prob_joint_transparent =
+ prob_transition_transparent * kB[1][out];
+
+ // Conditional probability of transparent state and the observed output.
+ RTC_DCHECK_GT(prob_joint_normal + prob_joint_transparent, 0.f);
+ prob_transparent_state_ =
+ prob_joint_transparent / (prob_joint_normal + prob_joint_transparent);
+
+ // Transparent mode is only activated when its state probability is high.
+ // Dead zone between activation/deactivation thresholds to avoid switching
+ // back and forth.
+ if (prob_transparent_state_ > 0.95f) {
+ transparency_activated_ = true;
+ } else if (prob_transparent_state_ < 0.5f) {
+ transparency_activated_ = false;
+ }
+ }
+
+ private:
+ bool transparency_activated_ = false;
+ float prob_transparent_state_ = 0.f;
+};
+
+// Legacy classifier for toggling transparent mode.
+class LegacyTransparentModeImpl : public TransparentMode {
+ public:
+ explicit LegacyTransparentModeImpl(const EchoCanceller3Config& config)
+ : linear_and_stable_echo_path_(
+ config.echo_removal_control.linear_and_stable_echo_path),
+ active_blocks_since_sane_filter_(kBlocksSinceConsistentEstimateInit),
+ non_converged_sequence_size_(kBlocksSinceConvergencedFilterInit) {}
+
+ bool Active() const override { return transparency_activated_; }
+
+ void Reset() override {
+ non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
+ diverged_sequence_size_ = 0;
+ strong_not_saturated_render_blocks_ = 0;
+ if (linear_and_stable_echo_path_) {
+ recent_convergence_during_activity_ = false;
+ }
+ }
+
+ void Update(int filter_delay_blocks,
+ bool any_filter_consistent,
+ bool any_filter_converged,
+ bool all_filters_diverged,
+ bool active_render,
+ bool saturated_capture) override {
+ ++capture_block_counter_;
+ strong_not_saturated_render_blocks_ +=
+ active_render && !saturated_capture ? 1 : 0;
+
+ if (any_filter_consistent && filter_delay_blocks < 5) {
+ sane_filter_observed_ = true;
+ active_blocks_since_sane_filter_ = 0;
+ } else if (active_render) {
+ ++active_blocks_since_sane_filter_;
+ }
+
+ bool sane_filter_recently_seen;
+ if (!sane_filter_observed_) {
+ sane_filter_recently_seen =
+ capture_block_counter_ <= 5 * kNumBlocksPerSecond;
+ } else {
+ sane_filter_recently_seen =
+ active_blocks_since_sane_filter_ <= 30 * kNumBlocksPerSecond;
+ }
+
+ if (any_filter_converged) {
+ recent_convergence_during_activity_ = true;
+ active_non_converged_sequence_size_ = 0;
+ non_converged_sequence_size_ = 0;
+ ++num_converged_blocks_;
+ } else {
+ if (++non_converged_sequence_size_ > 20 * kNumBlocksPerSecond) {
+ num_converged_blocks_ = 0;
+ }
+
+ if (active_render &&
+ ++active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
+ recent_convergence_during_activity_ = false;
+ }
+ }
+
+ if (!all_filters_diverged) {
+ diverged_sequence_size_ = 0;
+ } else if (++diverged_sequence_size_ >= 60) {
+ // TODO(peah): Change these lines to ensure proper triggering of usable
+ // filter.
+ non_converged_sequence_size_ = kBlocksSinceConvergencedFilterInit;
+ }
+
+ if (active_non_converged_sequence_size_ > 60 * kNumBlocksPerSecond) {
+ finite_erl_recently_detected_ = false;
+ }
+ if (num_converged_blocks_ > 50) {
+ finite_erl_recently_detected_ = true;
+ }
+
+ if (finite_erl_recently_detected_) {
+ transparency_activated_ = false;
+ } else if (sane_filter_recently_seen &&
+ recent_convergence_during_activity_) {
+ transparency_activated_ = false;
+ } else {
+ const bool filter_should_have_converged =
+ strong_not_saturated_render_blocks_ > 6 * kNumBlocksPerSecond;
+ transparency_activated_ = filter_should_have_converged;
+ }
+ }
+
+ private:
+ const bool linear_and_stable_echo_path_;
+ size_t capture_block_counter_ = 0;
+ bool transparency_activated_ = false;
+ size_t active_blocks_since_sane_filter_;
+ bool sane_filter_observed_ = false;
+ bool finite_erl_recently_detected_ = false;
+ size_t non_converged_sequence_size_;
+ size_t diverged_sequence_size_ = 0;
+ size_t active_non_converged_sequence_size_ = 0;
+ size_t num_converged_blocks_ = 0;
+ bool recent_convergence_during_activity_ = false;
+ size_t strong_not_saturated_render_blocks_ = 0;
+};
+
+std::unique_ptr<TransparentMode> TransparentMode::Create(
+ const EchoCanceller3Config& config) {
+ if (config.ep_strength.bounded_erl || DeactivateTransparentMode()) {
+ return nullptr;
+ }
+ if (DeactivateTransparentModeHmm()) {
+ return std::make_unique<LegacyTransparentModeImpl>(config);
+ }
+ return std::make_unique<TransparentModeImpl>();
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/transparent_mode.h b/webrtc/modules/audio_processing/aec3/transparent_mode.h
new file mode 100644
index 0000000..b1be69b
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/transparent_mode.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AEC3_TRANSPARENT_MODE_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_TRANSPARENT_MODE_H_
+
+#include <memory>
+
+#include "api/audio/echo_canceller3_config.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+
+namespace webrtc {
+
+// Class for detecting and toggling the transparent mode which causes the
+// suppressor to apply less suppression.
+class TransparentMode {
+ public:
+ static std::unique_ptr<TransparentMode> Create(
+ const EchoCanceller3Config& config);
+
+ virtual ~TransparentMode() {}
+
+ // Returns whether the transparent mode should be active.
+ virtual bool Active() const = 0;
+
+ // Resets the state of the detector.
+ virtual void Reset() = 0;
+
+ // Updates the detection decision based on new data.
+ virtual void Update(int filter_delay_blocks,
+ bool any_filter_consistent,
+ bool any_filter_converged,
+ bool all_filters_diverged,
+ bool active_render,
+ bool saturated_capture) = 0;
+};
+
+} // namespace webrtc
+#endif // MODULES_AUDIO_PROCESSING_AEC3_TRANSPARENT_MODE_H_
diff --git a/webrtc/modules/audio_processing/aec3/vector_math.h b/webrtc/modules/audio_processing/aec3/vector_math.h
new file mode 100644
index 0000000..e4d1381
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/vector_math.h
@@ -0,0 +1,229 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC3_VECTOR_MATH_H_
+#define MODULES_AUDIO_PROCESSING_AEC3_VECTOR_MATH_H_
+
+// Defines WEBRTC_ARCH_X86_FAMILY, used below.
+#include "rtc_base/system/arch.h"
+
+#if defined(WEBRTC_HAS_NEON)
+#include <arm_neon.h>
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#include <emmintrin.h>
+#endif
+#include <math.h>
+
+#include <algorithm>
+#include <array>
+#include <functional>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/aec3/aec3_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace aec3 {
+
+// Provides optimizations for mathematical operations based on vectors.
+class VectorMath {
+ public:
+ explicit VectorMath(Aec3Optimization optimization)
+ : optimization_(optimization) {}
+
+ // Elementwise square root.
+ void SqrtAVX2(rtc::ArrayView<float> x);
+ void Sqrt(rtc::ArrayView<float> x) {
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2: {
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 2;
+
+ int j = 0;
+ for (; j < vector_limit * 4; j += 4) {
+ __m128 g = _mm_loadu_ps(&x[j]);
+ g = _mm_sqrt_ps(g);
+ _mm_storeu_ps(&x[j], g);
+ }
+
+ for (; j < x_size; ++j) {
+ x[j] = sqrtf(x[j]);
+ }
+ } break;
+ case Aec3Optimization::kAvx2:
+ SqrtAVX2(x);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Aec3Optimization::kNeon: {
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 2;
+
+ int j = 0;
+ for (; j < vector_limit * 4; j += 4) {
+ float32x4_t g = vld1q_f32(&x[j]);
+#if !defined(WEBRTC_ARCH_ARM64)
+ float32x4_t y = vrsqrteq_f32(g);
+
+ // Code to handle sqrt(0).
+ // If the input to sqrtf() is zero, a zero will be returned.
+ // If the input to vrsqrteq_f32() is zero, positive infinity is
+ // returned.
+ const uint32x4_t vec_p_inf = vdupq_n_u32(0x7F800000);
+ // check for divide by zero
+ const uint32x4_t div_by_zero =
+ vceqq_u32(vec_p_inf, vreinterpretq_u32_f32(y));
+ // zero out the positive infinity results
+ y = vreinterpretq_f32_u32(
+ vandq_u32(vmvnq_u32(div_by_zero), vreinterpretq_u32_f32(y)));
+ // from arm documentation
+ // The Newton-Raphson iteration:
+ // y[n+1] = y[n] * (3 - d * (y[n] * y[n])) / 2)
+ // converges to (1/√d) if y0 is the result of VRSQRTE applied to d.
+ //
+ // Note: The precision did not improve after 2 iterations.
+ for (int i = 0; i < 2; i++) {
+ y = vmulq_f32(vrsqrtsq_f32(vmulq_f32(y, y), g), y);
+ }
+ // sqrt(g) = g * 1/sqrt(g)
+ g = vmulq_f32(g, y);
+#else
+ g = vsqrtq_f32(g);
+#endif
+ vst1q_f32(&x[j], g);
+ }
+
+ for (; j < x_size; ++j) {
+ x[j] = sqrtf(x[j]);
+ }
+ }
+#endif
+ break;
+ default:
+ std::for_each(x.begin(), x.end(), [](float& a) { a = sqrtf(a); });
+ }
+ }
+
+ // Elementwise vector multiplication z = x * y.
+ void MultiplyAVX2(rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> z);
+ void Multiply(rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> z) {
+ RTC_DCHECK_EQ(z.size(), x.size());
+ RTC_DCHECK_EQ(z.size(), y.size());
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2: {
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 2;
+
+ int j = 0;
+ for (; j < vector_limit * 4; j += 4) {
+ const __m128 x_j = _mm_loadu_ps(&x[j]);
+ const __m128 y_j = _mm_loadu_ps(&y[j]);
+ const __m128 z_j = _mm_mul_ps(x_j, y_j);
+ _mm_storeu_ps(&z[j], z_j);
+ }
+
+ for (; j < x_size; ++j) {
+ z[j] = x[j] * y[j];
+ }
+ } break;
+ case Aec3Optimization::kAvx2:
+ MultiplyAVX2(x, y, z);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Aec3Optimization::kNeon: {
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 2;
+
+ int j = 0;
+ for (; j < vector_limit * 4; j += 4) {
+ const float32x4_t x_j = vld1q_f32(&x[j]);
+ const float32x4_t y_j = vld1q_f32(&y[j]);
+ const float32x4_t z_j = vmulq_f32(x_j, y_j);
+ vst1q_f32(&z[j], z_j);
+ }
+
+ for (; j < x_size; ++j) {
+ z[j] = x[j] * y[j];
+ }
+ } break;
+#endif
+ default:
+ std::transform(x.begin(), x.end(), y.begin(), z.begin(),
+ std::multiplies<float>());
+ }
+ }
+
+ // Elementwise vector accumulation z += x.
+ void AccumulateAVX2(rtc::ArrayView<const float> x, rtc::ArrayView<float> z);
+ void Accumulate(rtc::ArrayView<const float> x, rtc::ArrayView<float> z) {
+ RTC_DCHECK_EQ(z.size(), x.size());
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Aec3Optimization::kSse2: {
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 2;
+
+ int j = 0;
+ for (; j < vector_limit * 4; j += 4) {
+ const __m128 x_j = _mm_loadu_ps(&x[j]);
+ __m128 z_j = _mm_loadu_ps(&z[j]);
+ z_j = _mm_add_ps(x_j, z_j);
+ _mm_storeu_ps(&z[j], z_j);
+ }
+
+ for (; j < x_size; ++j) {
+ z[j] += x[j];
+ }
+ } break;
+ case Aec3Optimization::kAvx2:
+ AccumulateAVX2(x, z);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Aec3Optimization::kNeon: {
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 2;
+
+ int j = 0;
+ for (; j < vector_limit * 4; j += 4) {
+ const float32x4_t x_j = vld1q_f32(&x[j]);
+ float32x4_t z_j = vld1q_f32(&z[j]);
+ z_j = vaddq_f32(z_j, x_j);
+ vst1q_f32(&z[j], z_j);
+ }
+
+ for (; j < x_size; ++j) {
+ z[j] += x[j];
+ }
+ } break;
+#endif
+ default:
+ std::transform(x.begin(), x.end(), z.begin(), z.begin(),
+ std::plus<float>());
+ }
+ }
+
+ private:
+ Aec3Optimization optimization_;
+};
+
+} // namespace aec3
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC3_VECTOR_MATH_H_
diff --git a/webrtc/modules/audio_processing/aec3/vector_math_avx2.cc b/webrtc/modules/audio_processing/aec3/vector_math_avx2.cc
new file mode 100644
index 0000000..0b5f3c1
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec3/vector_math_avx2.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/aec3/vector_math.h"
+
+#include <immintrin.h>
+#include <math.h>
+
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace aec3 {
+
+// Elementwise square root.
+void VectorMath::SqrtAVX2(rtc::ArrayView<float> x) {
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 3;
+
+ int j = 0;
+ for (; j < vector_limit * 8; j += 8) {
+ __m256 g = _mm256_loadu_ps(&x[j]);
+ g = _mm256_sqrt_ps(g);
+ _mm256_storeu_ps(&x[j], g);
+ }
+
+ for (; j < x_size; ++j) {
+ x[j] = sqrtf(x[j]);
+ }
+}
+
+// Elementwise vector multiplication z = x * y.
+void VectorMath::MultiplyAVX2(rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float> z) {
+ RTC_DCHECK_EQ(z.size(), x.size());
+ RTC_DCHECK_EQ(z.size(), y.size());
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 3;
+
+ int j = 0;
+ for (; j < vector_limit * 8; j += 8) {
+ const __m256 x_j = _mm256_loadu_ps(&x[j]);
+ const __m256 y_j = _mm256_loadu_ps(&y[j]);
+ const __m256 z_j = _mm256_mul_ps(x_j, y_j);
+ _mm256_storeu_ps(&z[j], z_j);
+ }
+
+ for (; j < x_size; ++j) {
+ z[j] = x[j] * y[j];
+ }
+}
+
+// Elementwise vector accumulation z += x.
+void VectorMath::AccumulateAVX2(rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> z) {
+ RTC_DCHECK_EQ(z.size(), x.size());
+ const int x_size = static_cast<int>(x.size());
+ const int vector_limit = x_size >> 3;
+
+ int j = 0;
+ for (; j < vector_limit * 8; j += 8) {
+ const __m256 x_j = _mm256_loadu_ps(&x[j]);
+ __m256 z_j = _mm256_loadu_ps(&z[j]);
+ z_j = _mm256_add_ps(x_j, z_j);
+ _mm256_storeu_ps(&z[j], z_j);
+ }
+
+ for (; j < x_size; ++j) {
+ z[j] += x[j];
+ }
+}
+
+} // namespace aec3
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec_dump/BUILD.gn b/webrtc/modules/audio_processing/aec_dump/BUILD.gn
new file mode 100644
index 0000000..9887f7d
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec_dump/BUILD.gn
@@ -0,0 +1,110 @@
+# 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.
+
+import("../../../webrtc.gni") # This contains def of 'rtc_enable_protobuf'
+
+rtc_source_set("aec_dump") {
+ visibility = [ "*" ]
+ sources = [ "aec_dump_factory.h" ]
+
+ deps = [
+ "..:aec_dump_interface",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base/system:file_wrapper",
+ "../../../rtc_base/system:rtc_export",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("mock_aec_dump") {
+ testonly = true
+ sources = [
+ "mock_aec_dump.cc",
+ "mock_aec_dump.h",
+ ]
+
+ deps = [
+ "..:aec_dump_interface",
+ "..:audioproc_test_utils",
+ "../",
+ "../../../test:test_support",
+ ]
+ }
+
+ rtc_library("mock_aec_dump_unittests") {
+ testonly = true
+ configs += [ "..:apm_debug_dump" ]
+ sources = [ "aec_dump_integration_test.cc" ]
+
+ deps = [
+ ":mock_aec_dump",
+ "..:api",
+ "..:audioproc_test_utils",
+ "../",
+ "../../../rtc_base:rtc_base_approved",
+ "//testing/gtest",
+ ]
+ }
+}
+
+if (rtc_enable_protobuf) {
+ rtc_library("aec_dump_impl") {
+ sources = [
+ "aec_dump_impl.cc",
+ "aec_dump_impl.h",
+ "capture_stream_info.cc",
+ "capture_stream_info.h",
+ "write_to_file_task.cc",
+ "write_to_file_task.h",
+ ]
+
+ deps = [
+ ":aec_dump",
+ "..:aec_dump_interface",
+ "../../../api/audio:audio_frame_api",
+ "../../../api/task_queue",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:ignore_wundef",
+ "../../../rtc_base:protobuf_utils",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:rtc_task_queue",
+ "../../../rtc_base/system:file_wrapper",
+ "../../../system_wrappers",
+ ]
+
+ deps += [ "../:audioproc_debug_proto" ]
+ }
+
+ if (rtc_include_tests) {
+ rtc_library("aec_dump_unittests") {
+ testonly = true
+ defines = []
+ deps = [
+ ":aec_dump",
+ ":aec_dump_impl",
+ "..:audioproc_debug_proto",
+ "../",
+ "../../../rtc_base:task_queue_for_test",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "//testing/gtest",
+ ]
+ sources = [ "aec_dump_unittest.cc" ]
+ }
+ }
+}
+
+rtc_library("null_aec_dump_factory") {
+ assert_no_deps = [ ":aec_dump_impl" ]
+ sources = [ "null_aec_dump_factory.cc" ]
+
+ deps = [
+ ":aec_dump",
+ "..:aec_dump_interface",
+ ]
+}
diff --git a/webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h b/webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h
new file mode 100644
index 0000000..429a8a5
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h
@@ -0,0 +1,48 @@
+/*
+ * 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_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_
+#define MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_
+
+#include <memory>
+#include <string>
+
+#include "modules/audio_processing/include/aec_dump.h"
+#include "rtc_base/system/file_wrapper.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace rtc {
+class TaskQueue;
+} // namespace rtc
+
+namespace webrtc {
+
+class RTC_EXPORT AecDumpFactory {
+ public:
+ // The |worker_queue| may not be null and must outlive the created
+ // AecDump instance. |max_log_size_bytes == -1| means the log size
+ // will be unlimited. |handle| may not be null. The AecDump takes
+ // responsibility for |handle| and closes it in the destructor. A
+ // non-null return value indicates that the file has been
+ // sucessfully opened.
+ static std::unique_ptr<AecDump> Create(webrtc::FileWrapper file,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue);
+ static std::unique_ptr<AecDump> Create(std::string file_name,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue);
+ static std::unique_ptr<AecDump> Create(FILE* handle,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_
diff --git a/webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc b/webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc
new file mode 100644
index 0000000..126adeb
--- /dev/null
+++ b/webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc
@@ -0,0 +1,33 @@
+/*
+ * 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/audio_processing/aec_dump/aec_dump_factory.h"
+#include "modules/audio_processing/include/aec_dump.h"
+
+namespace webrtc {
+
+std::unique_ptr<AecDump> AecDumpFactory::Create(webrtc::FileWrapper file,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) {
+ return nullptr;
+}
+
+std::unique_ptr<AecDump> AecDumpFactory::Create(std::string file_name,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) {
+ return nullptr;
+}
+
+std::unique_ptr<AecDump> AecDumpFactory::Create(FILE* handle,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) {
+ return nullptr;
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aecm/BUILD.gn b/webrtc/modules/audio_processing/aecm/BUILD.gn
new file mode 100644
index 0000000..61e9aff
--- /dev/null
+++ b/webrtc/modules/audio_processing/aecm/BUILD.gn
@@ -0,0 +1,44 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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_library("aecm_core") {
+ sources = [
+ "aecm_core.cc",
+ "aecm_core.h",
+ "aecm_defines.h",
+ "echo_control_mobile.cc",
+ "echo_control_mobile.h",
+ ]
+ deps = [
+ "../../../common_audio:common_audio_c",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:sanitizer",
+ "../../../system_wrappers",
+ "../utility:legacy_delay_estimator",
+ ]
+ cflags = []
+
+ if (rtc_build_with_neon) {
+ sources += [ "aecm_core_neon.cc" ]
+
+ if (current_cpu != "arm64") {
+ # Enable compilation for the NEON instruction set.
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags += [ "-mfpu=neon" ]
+ }
+ }
+
+ if (current_cpu == "mipsel") {
+ sources += [ "aecm_core_mips.cc" ]
+ } else {
+ sources += [ "aecm_core_c.cc" ]
+ }
+}
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core.c b/webrtc/modules/audio_processing/aecm/aecm_core.c
deleted file mode 100644
index f0d85d5..0000000
--- a/webrtc/modules/audio_processing/aecm/aecm_core.c
+++ /dev/null
@@ -1,1233 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-#include "webrtc/common_audio/ring_buffer.h"
-#include "webrtc/common_audio/signal_processing/include/real_fft.h"
-#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
-#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
-#include "webrtc/system_wrappers/include/compile_assert_c.h"
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
-#include "webrtc/typedefs.h"
-
-#ifdef AEC_DEBUG
-FILE *dfile;
-FILE *testfile;
-#endif
-
-const int16_t WebRtcAecm_kCosTable[] = {
- 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112,
- 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834,
- 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362,
- 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710,
- 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892,
- 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930,
- 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845,
- 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667,
- 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422,
- 1281, 1140, 998, 856, 713, 571, 428, 285, 142,
- 0, -142, -285, -428, -571, -713, -856, -998, -1140,
- -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
- -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591,
- -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
- -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690,
- -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542,
- -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233,
- -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745,
- -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067,
- -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190,
- -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112,
- -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
- -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
- -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710,
- -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892,
- -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930,
- -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845,
- -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667,
- -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422,
- -1281, -1140, -998, -856, -713, -571, -428, -285, -142,
- 0, 142, 285, 428, 571, 713, 856, 998, 1140,
- 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395,
- 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591,
- 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698,
- 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690,
- 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542,
- 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233,
- 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745,
- 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067,
- 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190
-};
-
-const int16_t WebRtcAecm_kSinTable[] = {
- 0, 142, 285, 428, 571, 713, 856, 998,
- 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120,
- 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200,
- 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219,
- 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155,
- 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991,
- 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710,
- 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299,
- 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745,
- 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041,
- 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180,
- 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160,
- 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982,
- 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647,
- 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164,
- 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542,
- 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792,
- 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930,
- 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971,
- 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935,
- 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842,
- 1703, 1563, 1422, 1281, 1140, 998, 856, 713,
- 571, 428, 285, 142, 0, -142, -285, -428,
- -571, -713, -856, -998, -1140, -1281, -1422, -1563,
- -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667,
- -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719,
- -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698,
- -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586,
- -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366,
- -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021,
- -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540,
- -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912,
- -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130,
- -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190,
- -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091,
- -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
- -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424,
- -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870,
- -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182,
- -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374,
- -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461,
- -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462,
- -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395,
- -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281,
- -1140, -998, -856, -713, -571, -428, -285, -142
-};
-
-// Initialization table for echo channel in 8 kHz
-static const int16_t kChannelStored8kHz[PART_LEN1] = {
- 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418,
- 1451, 1506, 1562, 1644, 1726, 1804, 1882, 1918,
- 1953, 1982, 2010, 2025, 2040, 2034, 2027, 2021,
- 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683,
- 1635, 1604, 1572, 1545, 1517, 1481, 1444, 1405,
- 1367, 1331, 1294, 1270, 1245, 1239, 1233, 1247,
- 1260, 1282, 1303, 1338, 1373, 1407, 1441, 1470,
- 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649,
- 1676
-};
-
-// Initialization table for echo channel in 16 kHz
-static const int16_t kChannelStored16kHz[PART_LEN1] = {
- 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882,
- 1953, 2010, 2040, 2027, 2014, 1980, 1869, 1732,
- 1635, 1572, 1517, 1444, 1367, 1294, 1245, 1233,
- 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621,
- 1676, 1741, 1802, 1861, 1921, 1983, 2040, 2102,
- 2170, 2265, 2375, 2515, 2651, 2781, 2922, 3075,
- 3253, 3471, 3738, 3976, 4151, 4258, 4308, 4288,
- 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484,
- 3153
-};
-
-// Moves the pointer to the next entry and inserts |far_spectrum| and
-// corresponding Q-domain in its buffer.
-//
-// Inputs:
-// - self : Pointer to the delay estimation instance
-// - far_spectrum : Pointer to the far end spectrum
-// - far_q : Q-domain of far end spectrum
-//
-void WebRtcAecm_UpdateFarHistory(AecmCore* self,
- uint16_t* far_spectrum,
- int far_q) {
- // Get new buffer position
- self->far_history_pos++;
- if (self->far_history_pos >= MAX_DELAY) {
- self->far_history_pos = 0;
- }
- // Update Q-domain buffer
- self->far_q_domains[self->far_history_pos] = far_q;
- // Update far end spectrum buffer
- memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]),
- far_spectrum,
- sizeof(uint16_t) * PART_LEN1);
-}
-
-// Returns a pointer to the far end spectrum aligned to current near end
-// spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
-// called before AlignedFarend(...). Otherwise, you get the pointer to the
-// previous frame. The memory is only valid until the next call of
-// WebRtc_DelayEstimatorProcessFix(...).
-//
-// Inputs:
-// - self : Pointer to the AECM instance.
-// - delay : Current delay estimate.
-//
-// Output:
-// - far_q : The Q-domain of the aligned far end spectrum
-//
-// Return value:
-// - far_spectrum : Pointer to the aligned far end spectrum
-// NULL - Error
-//
-const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self,
- int* far_q,
- int delay) {
- int buffer_position = 0;
- assert(self != NULL);
- buffer_position = self->far_history_pos - delay;
-
- // Check buffer position
- if (buffer_position < 0) {
- buffer_position += MAX_DELAY;
- }
- // Get Q-domain
- *far_q = self->far_q_domains[buffer_position];
- // Return far end spectrum
- return &(self->far_history[buffer_position * PART_LEN1]);
-}
-
-// Declare function pointers.
-CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
-StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
-ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
-
-AecmCore* WebRtcAecm_CreateCore() {
- AecmCore* aecm = malloc(sizeof(AecmCore));
-
- aecm->farFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
- sizeof(int16_t));
- if (!aecm->farFrameBuf)
- {
- WebRtcAecm_FreeCore(aecm);
- return NULL;
- }
-
- aecm->nearNoisyFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
- sizeof(int16_t));
- if (!aecm->nearNoisyFrameBuf)
- {
- WebRtcAecm_FreeCore(aecm);
- return NULL;
- }
-
- aecm->nearCleanFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
- sizeof(int16_t));
- if (!aecm->nearCleanFrameBuf)
- {
- WebRtcAecm_FreeCore(aecm);
- return NULL;
- }
-
- aecm->outFrameBuf = WebRtc_CreateBuffer(FRAME_LEN + PART_LEN,
- sizeof(int16_t));
- if (!aecm->outFrameBuf)
- {
- WebRtcAecm_FreeCore(aecm);
- return NULL;
- }
-
- aecm->delay_estimator_farend = WebRtc_CreateDelayEstimatorFarend(PART_LEN1,
- MAX_DELAY);
- if (aecm->delay_estimator_farend == NULL) {
- WebRtcAecm_FreeCore(aecm);
- return NULL;
- }
- aecm->delay_estimator =
- WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
- if (aecm->delay_estimator == NULL) {
- WebRtcAecm_FreeCore(aecm);
- return NULL;
- }
- // TODO(bjornv): Explicitly disable robust delay validation until no
- // performance regression has been established. Then remove the line.
- WebRtc_enable_robust_validation(aecm->delay_estimator, 0);
-
- aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
- if (aecm->real_fft == NULL) {
- WebRtcAecm_FreeCore(aecm);
- return NULL;
- }
-
- // Init some aecm pointers. 16 and 32 byte alignment is only necessary
- // for Neon code currently.
- aecm->xBuf = (int16_t*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31);
- aecm->dBufClean = (int16_t*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31);
- aecm->dBufNoisy = (int16_t*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31);
- aecm->outBuf = (int16_t*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15);
- aecm->channelStored = (int16_t*) (((uintptr_t)
- aecm->channelStored_buf + 15) & ~ 15);
- aecm->channelAdapt16 = (int16_t*) (((uintptr_t)
- aecm->channelAdapt16_buf + 15) & ~ 15);
- aecm->channelAdapt32 = (int32_t*) (((uintptr_t)
- aecm->channelAdapt32_buf + 31) & ~ 31);
-
- return aecm;
-}
-
-void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) {
- int i = 0;
-
- // Reset the stored channel
- memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
- // Reset the adapted channels
- memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
- for (i = 0; i < PART_LEN1; i++)
- {
- aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16;
- }
-
- // Reset channel storing variables
- aecm->mseAdaptOld = 1000;
- aecm->mseStoredOld = 1000;
- aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
- aecm->mseChannelCount = 0;
-}
-
-static void CalcLinearEnergiesC(AecmCore* aecm,
- const uint16_t* far_spectrum,
- int32_t* echo_est,
- uint32_t* far_energy,
- uint32_t* echo_energy_adapt,
- uint32_t* echo_energy_stored) {
- int i;
-
- // Get energy for the delayed far end signal and estimated
- // echo using both stored and adapted channels.
- for (i = 0; i < PART_LEN1; i++)
- {
- echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- far_spectrum[i]);
- (*far_energy) += (uint32_t)(far_spectrum[i]);
- *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
- (*echo_energy_stored) += (uint32_t)echo_est[i];
- }
-}
-
-static void StoreAdaptiveChannelC(AecmCore* aecm,
- const uint16_t* far_spectrum,
- int32_t* echo_est) {
- int i;
-
- // During startup we store the channel every block.
- memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(int16_t) * PART_LEN1);
- // Recalculate echo estimate
- for (i = 0; i < PART_LEN; i += 4)
- {
- echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- far_spectrum[i]);
- echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
- far_spectrum[i + 1]);
- echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
- far_spectrum[i + 2]);
- echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
- far_spectrum[i + 3]);
- }
- echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- far_spectrum[i]);
-}
-
-static void ResetAdaptiveChannelC(AecmCore* aecm) {
- int i;
-
- // The stored channel has a significantly lower MSE than the adaptive one for
- // two consecutive calculations. Reset the adaptive channel.
- memcpy(aecm->channelAdapt16, aecm->channelStored,
- sizeof(int16_t) * PART_LEN1);
- // Restore the W32 channel
- for (i = 0; i < PART_LEN; i += 4)
- {
- aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
- aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16;
- aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16;
- aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16;
- }
- aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
-}
-
-// Initialize function pointers for ARM Neon platform.
-#if (defined WEBRTC_DETECT_NEON || defined WEBRTC_HAS_NEON)
-static void WebRtcAecm_InitNeon(void)
-{
- WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon;
- WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon;
- WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon;
-}
-#endif
-
-// Initialize function pointers for MIPS platform.
-#if defined(MIPS32_LE)
-static void WebRtcAecm_InitMips(void)
-{
-#if defined(MIPS_DSP_R1_LE)
- WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips;
- WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips;
-#endif
- WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips;
-}
-#endif
-
-// WebRtcAecm_InitCore(...)
-//
-// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
-// Input:
-// - aecm : Pointer to the Echo Suppression instance
-// - samplingFreq : Sampling Frequency
-//
-// Output:
-// - aecm : Initialized instance
-//
-// Return value : 0 - Ok
-// -1 - Error
-//
-int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq) {
- int i = 0;
- int32_t tmp32 = PART_LEN1 * PART_LEN1;
- int16_t tmp16 = PART_LEN1;
-
- if (samplingFreq != 8000 && samplingFreq != 16000)
- {
- samplingFreq = 8000;
- return -1;
- }
- // sanity check of sampling frequency
- aecm->mult = (int16_t)samplingFreq / 8000;
-
- aecm->farBufWritePos = 0;
- aecm->farBufReadPos = 0;
- aecm->knownDelay = 0;
- aecm->lastKnownDelay = 0;
-
- WebRtc_InitBuffer(aecm->farFrameBuf);
- WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
- WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
- WebRtc_InitBuffer(aecm->outFrameBuf);
-
- memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
- memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
- memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
- memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
-
- aecm->seed = 666;
- aecm->totCount = 0;
-
- if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
- return -1;
- }
- if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
- return -1;
- }
- // Set far end histories to zero
- memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
- memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
- aecm->far_history_pos = MAX_DELAY;
-
- aecm->nlpFlag = 1;
- aecm->fixedDelay = -1;
-
- aecm->dfaCleanQDomain = 0;
- aecm->dfaCleanQDomainOld = 0;
- aecm->dfaNoisyQDomain = 0;
- aecm->dfaNoisyQDomainOld = 0;
-
- memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
- aecm->farLogEnergy = 0;
- memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
- memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
-
- // Initialize the echo channels with a stored shape.
- if (samplingFreq == 8000)
- {
- WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
- }
- else
- {
- WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
- }
-
- memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
- memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
- aecm->noiseEstCtr = 0;
-
- aecm->cngMode = AecmTrue;
-
- memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
- memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
- // Shape the initial noise level to an approximate pink noise.
- for (i = 0; i < (PART_LEN1 >> 1) - 1; i++)
- {
- aecm->noiseEst[i] = (tmp32 << 8);
- tmp16--;
- tmp32 -= (int32_t)((tmp16 << 1) + 1);
- }
- for (; i < PART_LEN1; i++)
- {
- aecm->noiseEst[i] = (tmp32 << 8);
- }
-
- aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
- aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
- aecm->farEnergyMaxMin = 0;
- aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the
- // beginning.
- aecm->farEnergyMSE = 0;
- aecm->currentVADValue = 0;
- aecm->vadUpdateCount = 0;
- aecm->firstVAD = 1;
-
- aecm->startupState = 0;
- aecm->supGain = SUPGAIN_DEFAULT;
- aecm->supGainOld = SUPGAIN_DEFAULT;
-
- aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
- aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
- aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
- aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
-
- // Assert a preprocessor definition at compile-time. It's an assumption
- // used in assembly code, so check the assembly files before any change.
- COMPILE_ASSERT(PART_LEN % 16 == 0);
-
- // Initialize function pointers.
- WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
- WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
- WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
-
-#ifdef WEBRTC_DETECT_NEON
- uint64_t features = WebRtc_GetCPUFeaturesARM();
- if ((features & kCPUFeatureNEON) != 0)
- {
- WebRtcAecm_InitNeon();
- }
-#elif defined(WEBRTC_HAS_NEON)
- WebRtcAecm_InitNeon();
-#endif
-
-#if defined(MIPS32_LE)
- WebRtcAecm_InitMips();
-#endif
- return 0;
-}
-
-// TODO(bjornv): This function is currently not used. Add support for these
-// parameters from a higher level
-int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) {
- aecm->nlpFlag = nlpFlag;
- aecm->fixedDelay = delay;
-
- return 0;
-}
-
-void WebRtcAecm_FreeCore(AecmCore* aecm) {
- if (aecm == NULL) {
- return;
- }
-
- WebRtc_FreeBuffer(aecm->farFrameBuf);
- WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
- WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
- WebRtc_FreeBuffer(aecm->outFrameBuf);
-
- WebRtc_FreeDelayEstimator(aecm->delay_estimator);
- WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
- WebRtcSpl_FreeRealFFT(aecm->real_fft);
-
- free(aecm);
-}
-
-int WebRtcAecm_ProcessFrame(AecmCore* aecm,
- const int16_t* farend,
- const int16_t* nearendNoisy,
- const int16_t* nearendClean,
- int16_t* out) {
- int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
- int16_t* outBlock = (int16_t*) (((uintptr_t) outBlock_buf + 15) & ~ 15);
-
- int16_t farFrame[FRAME_LEN];
- const int16_t* out_ptr = NULL;
- int size = 0;
-
- // Buffer the current frame.
- // Fetch an older one corresponding to the delay.
- WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
- WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
-
- // Buffer the synchronized far and near frames,
- // to pass the smaller blocks individually.
- WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
- WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
- if (nearendClean != NULL)
- {
- WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
- }
-
- // Process as many blocks as possible.
- while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN)
- {
- int16_t far_block[PART_LEN];
- const int16_t* far_block_ptr = NULL;
- int16_t near_noisy_block[PART_LEN];
- const int16_t* near_noisy_block_ptr = NULL;
-
- WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block,
- PART_LEN);
- WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf,
- (void**) &near_noisy_block_ptr,
- near_noisy_block,
- PART_LEN);
- if (nearendClean != NULL)
- {
- int16_t near_clean_block[PART_LEN];
- const int16_t* near_clean_block_ptr = NULL;
-
- WebRtc_ReadBuffer(aecm->nearCleanFrameBuf,
- (void**) &near_clean_block_ptr,
- near_clean_block,
- PART_LEN);
- if (WebRtcAecm_ProcessBlock(aecm,
- far_block_ptr,
- near_noisy_block_ptr,
- near_clean_block_ptr,
- outBlock) == -1)
- {
- return -1;
- }
- } else
- {
- if (WebRtcAecm_ProcessBlock(aecm,
- far_block_ptr,
- near_noisy_block_ptr,
- NULL,
- outBlock) == -1)
- {
- return -1;
- }
- }
-
- WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
- }
-
- // Stuff the out buffer if we have less than a frame to output.
- // This should only happen for the first frame.
- size = (int) WebRtc_available_read(aecm->outFrameBuf);
- if (size < FRAME_LEN)
- {
- WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
- }
-
- // Obtain an output frame.
- WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN);
- if (out_ptr != out) {
- // ReadBuffer() hasn't copied to |out| in this case.
- memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
- }
-
- return 0;
-}
-
-// WebRtcAecm_AsymFilt(...)
-//
-// Performs asymmetric filtering.
-//
-// Inputs:
-// - filtOld : Previous filtered value.
-// - inVal : New input value.
-// - stepSizePos : Step size when we have a positive contribution.
-// - stepSizeNeg : Step size when we have a negative contribution.
-//
-// Output:
-//
-// Return: - Filtered value.
-//
-int16_t WebRtcAecm_AsymFilt(const int16_t filtOld, const int16_t inVal,
- const int16_t stepSizePos,
- const int16_t stepSizeNeg)
-{
- int16_t retVal;
-
- if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN))
- {
- return inVal;
- }
- retVal = filtOld;
- if (filtOld > inVal)
- {
- retVal -= (filtOld - inVal) >> stepSizeNeg;
- } else
- {
- retVal += (inVal - filtOld) >> stepSizePos;
- }
-
- return retVal;
-}
-
-// ExtractFractionPart(a, zeros)
-//
-// returns the fraction part of |a|, with |zeros| number of leading zeros, as an
-// int16_t scaled to Q8. There is no sanity check of |a| in the sense that the
-// number of zeros match.
-static int16_t ExtractFractionPart(uint32_t a, int zeros) {
- return (int16_t)(((a << zeros) & 0x7FFFFFFF) >> 23);
-}
-
-// Calculates and returns the log of |energy| in Q8. The input |energy| is
-// supposed to be in Q(|q_domain|).
-static int16_t LogOfEnergyInQ8(uint32_t energy, int q_domain) {
- static const int16_t kLogLowValue = PART_LEN_SHIFT << 7;
- int16_t log_energy_q8 = kLogLowValue;
- if (energy > 0) {
- int zeros = WebRtcSpl_NormU32(energy);
- int16_t frac = ExtractFractionPart(energy, zeros);
- // log2 of |energy| in Q8.
- log_energy_q8 += ((31 - zeros) << 8) + frac - (q_domain << 8);
- }
- return log_energy_q8;
-}
-
-// WebRtcAecm_CalcEnergies(...)
-//
-// This function calculates the log of energies for nearend, farend and estimated
-// echoes. There is also an update of energy decision levels, i.e. internal VAD.
-//
-//
-// @param aecm [i/o] Handle of the AECM instance.
-// @param far_spectrum [in] Pointer to farend spectrum.
-// @param far_q [in] Q-domain of farend spectrum.
-// @param nearEner [in] Near end energy for current block in
-// Q(aecm->dfaQDomain).
-// @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
-//
-void WebRtcAecm_CalcEnergies(AecmCore* aecm,
- const uint16_t* far_spectrum,
- const int16_t far_q,
- const uint32_t nearEner,
- int32_t* echoEst) {
- // Local variables
- uint32_t tmpAdapt = 0;
- uint32_t tmpStored = 0;
- uint32_t tmpFar = 0;
-
- int i;
-
- int16_t tmp16;
- int16_t increase_max_shifts = 4;
- int16_t decrease_max_shifts = 11;
- int16_t increase_min_shifts = 11;
- int16_t decrease_min_shifts = 3;
-
- // Get log of near end energy and store in buffer
-
- // Shift buffer
- memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
- sizeof(int16_t) * (MAX_BUF_LEN - 1));
-
- // Logarithm of integrated magnitude spectrum (nearEner)
- aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain);
-
- WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored);
-
- // Shift buffers
- memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
- sizeof(int16_t) * (MAX_BUF_LEN - 1));
- memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
- sizeof(int16_t) * (MAX_BUF_LEN - 1));
-
- // Logarithm of delayed far end energy
- aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q);
-
- // Logarithm of estimated echo energy through adapted channel
- aecm->echoAdaptLogEnergy[0] = LogOfEnergyInQ8(tmpAdapt,
- RESOLUTION_CHANNEL16 + far_q);
-
- // Logarithm of estimated echo energy through stored channel
- aecm->echoStoredLogEnergy[0] =
- LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q);
-
- // Update farend energy levels (min, max, vad, mse)
- if (aecm->farLogEnergy > FAR_ENERGY_MIN)
- {
- if (aecm->startupState == 0)
- {
- increase_max_shifts = 2;
- decrease_min_shifts = 2;
- increase_min_shifts = 8;
- }
-
- aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
- increase_min_shifts, decrease_min_shifts);
- aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
- increase_max_shifts, decrease_max_shifts);
- aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
-
- // Dynamic VAD region size
- tmp16 = 2560 - aecm->farEnergyMin;
- if (tmp16 > 0)
- {
- tmp16 = (int16_t)((tmp16 * FAR_ENERGY_VAD_REGION) >> 9);
- } else
- {
- tmp16 = 0;
- }
- tmp16 += FAR_ENERGY_VAD_REGION;
-
- if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024))
- {
- // In startup phase or VAD update halted
- aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
- } else
- {
- if (aecm->farEnergyVAD > aecm->farLogEnergy)
- {
- aecm->farEnergyVAD +=
- (aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> 6;
- aecm->vadUpdateCount = 0;
- } else
- {
- aecm->vadUpdateCount++;
- }
- }
- // Put MSE threshold higher than VAD
- aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
- }
-
- // Update VAD variables
- if (aecm->farLogEnergy > aecm->farEnergyVAD)
- {
- if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF))
- {
- // We are in startup or have significant dynamics in input speech level
- aecm->currentVADValue = 1;
- }
- } else
- {
- aecm->currentVADValue = 0;
- }
- if ((aecm->currentVADValue) && (aecm->firstVAD))
- {
- aecm->firstVAD = 0;
- if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0])
- {
- // The estimated echo has higher energy than the near end signal.
- // This means that the initialization was too aggressive. Scale
- // down by a factor 8
- for (i = 0; i < PART_LEN1; i++)
- {
- aecm->channelAdapt16[i] >>= 3;
- }
- // Compensate the adapted echo energy level accordingly.
- aecm->echoAdaptLogEnergy[0] -= (3 << 8);
- aecm->firstVAD = 1;
- }
- }
-}
-
-// WebRtcAecm_CalcStepSize(...)
-//
-// This function calculates the step size used in channel estimation
-//
-//
-// @param aecm [in] Handle of the AECM instance.
-// @param mu [out] (Return value) Stepsize in log2(), i.e. number of shifts.
-//
-//
-int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm) {
- int32_t tmp32;
- int16_t tmp16;
- int16_t mu = MU_MAX;
-
- // Here we calculate the step size mu used in the
- // following NLMS based Channel estimation algorithm
- if (!aecm->currentVADValue)
- {
- // Far end energy level too low, no channel update
- mu = 0;
- } else if (aecm->startupState > 0)
- {
- if (aecm->farEnergyMin >= aecm->farEnergyMax)
- {
- mu = MU_MIN;
- } else
- {
- tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
- tmp32 = tmp16 * MU_DIFF;
- tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
- mu = MU_MIN - 1 - (int16_t)(tmp32);
- // The -1 is an alternative to rounding. This way we get a larger
- // stepsize, so we in some sense compensate for truncation in NLMS
- }
- if (mu < MU_MAX)
- {
- mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
- }
- }
-
- return mu;
-}
-
-// WebRtcAecm_UpdateChannel(...)
-//
-// This function performs channel estimation. NLMS and decision on channel storage.
-//
-//
-// @param aecm [i/o] Handle of the AECM instance.
-// @param far_spectrum [in] Absolute value of the farend signal in Q(far_q)
-// @param far_q [in] Q-domain of the farend signal
-// @param dfa [in] Absolute value of the nearend signal (Q[aecm->dfaQDomain])
-// @param mu [in] NLMS step size.
-// @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
-//
-void WebRtcAecm_UpdateChannel(AecmCore* aecm,
- const uint16_t* far_spectrum,
- const int16_t far_q,
- const uint16_t* const dfa,
- const int16_t mu,
- int32_t* echoEst) {
- uint32_t tmpU32no1, tmpU32no2;
- int32_t tmp32no1, tmp32no2;
- int32_t mseStored;
- int32_t mseAdapt;
-
- int i;
-
- int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
- int16_t shiftChFar, shiftNum, shift2ResChan;
- int16_t tmp16no1;
- int16_t xfaQ, dfaQ;
-
- // This is the channel estimation algorithm. It is base on NLMS but has a variable step
- // length, which was calculated above.
- if (mu)
- {
- for (i = 0; i < PART_LEN1; i++)
- {
- // Determine norm of channel and farend to make sure we don't get overflow in
- // multiplication
- zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
- zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
- if (zerosCh + zerosFar > 31)
- {
- // Multiplication is safe
- tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i],
- far_spectrum[i]);
- shiftChFar = 0;
- } else
- {
- // We need to shift down before multiplication
- shiftChFar = 32 - zerosCh - zerosFar;
- tmpU32no1 = (aecm->channelAdapt32[i] >> shiftChFar) *
- far_spectrum[i];
- }
- // Determine Q-domain of numerator
- zerosNum = WebRtcSpl_NormU32(tmpU32no1);
- if (dfa[i])
- {
- zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
- } else
- {
- zerosDfa = 32;
- }
- tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain -
- RESOLUTION_CHANNEL32 - far_q + shiftChFar;
- if (zerosNum > tmp16no1 + 1)
- {
- xfaQ = tmp16no1;
- dfaQ = zerosDfa - 2;
- } else
- {
- xfaQ = zerosNum - 2;
- dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
- shiftChFar + xfaQ;
- }
- // Add in the same Q-domain
- tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
- tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
- tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
- zerosNum = WebRtcSpl_NormW32(tmp32no1);
- if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q)))
- {
- //
- // Update is needed
- //
- // This is what we would like to compute
- //
- // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
- // tmp32norm = (i + 1)
- // aecm->channelAdapt[i] += (2^mu) * tmp32no1
- // / (tmp32norm * far_spectrum[i])
- //
-
- // Make sure we don't get overflow in multiplication.
- if (zerosNum + zerosFar > 31)
- {
- if (tmp32no1 > 0)
- {
- tmp32no2 = (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1,
- far_spectrum[i]);
- } else
- {
- tmp32no2 = -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1,
- far_spectrum[i]);
- }
- shiftNum = 0;
- } else
- {
- shiftNum = 32 - (zerosNum + zerosFar);
- if (tmp32no1 > 0)
- {
- tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i];
- } else
- {
- tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]);
- }
- }
- // Normalize with respect to frequency bin
- tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
- // Make sure we are in the right Q-domain
- shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
- if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan)
- {
- tmp32no2 = WEBRTC_SPL_WORD32_MAX;
- } else
- {
- tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
- }
- aecm->channelAdapt32[i] =
- WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2);
- if (aecm->channelAdapt32[i] < 0)
- {
- // We can never have negative channel gain
- aecm->channelAdapt32[i] = 0;
- }
- aecm->channelAdapt16[i] =
- (int16_t)(aecm->channelAdapt32[i] >> 16);
- }
- }
- }
- // END: Adaptive channel update
-
- // Determine if we should store or restore the channel
- if ((aecm->startupState == 0) & (aecm->currentVADValue))
- {
- // During startup we store the channel every block,
- // and we recalculate echo estimate
- WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
- } else
- {
- if (aecm->farLogEnergy < aecm->farEnergyMSE)
- {
- aecm->mseChannelCount = 0;
- } else
- {
- aecm->mseChannelCount++;
- }
- // Enough data for validation. Store channel if we can.
- if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10))
- {
- // We have enough data.
- // Calculate MSE of "Adapt" and "Stored" versions.
- // It is actually not MSE, but average absolute error.
- mseStored = 0;
- mseAdapt = 0;
- for (i = 0; i < MIN_MSE_COUNT; i++)
- {
- tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i]
- - (int32_t)aecm->nearLogEnergy[i]);
- tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
- mseStored += tmp32no2;
-
- tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i]
- - (int32_t)aecm->nearLogEnergy[i]);
- tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
- mseAdapt += tmp32no2;
- }
- if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt))
- & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF
- * aecm->mseAdaptOld)))
- {
- // The stored channel has a significantly lower MSE than the adaptive one for
- // two consecutive calculations. Reset the adaptive channel.
- WebRtcAecm_ResetAdaptiveChannel(aecm);
- } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt
- < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold))
- {
- // The adaptive channel has a significantly lower MSE than the stored one.
- // The MSE for the adaptive channel has also been low for two consecutive
- // calculations. Store the adaptive channel.
- WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
-
- // Update threshold
- if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX)
- {
- aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
- } else
- {
- int scaled_threshold = aecm->mseThreshold * 5 / 8;
- aecm->mseThreshold +=
- ((mseAdapt - scaled_threshold) * 205) >> 8;
- }
-
- }
-
- // Reset counter
- aecm->mseChannelCount = 0;
-
- // Store the MSE values.
- aecm->mseStoredOld = mseStored;
- aecm->mseAdaptOld = mseAdapt;
- }
- }
- // END: Determine if we should store or reset channel estimate.
-}
-
-// CalcSuppressionGain(...)
-//
-// This function calculates the suppression gain that is used in the Wiener filter.
-//
-//
-// @param aecm [i/n] Handle of the AECM instance.
-// @param supGain [out] (Return value) Suppression gain with which to scale the noise
-// level (Q14).
-//
-//
-int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm) {
- int32_t tmp32no1;
-
- int16_t supGain = SUPGAIN_DEFAULT;
- int16_t tmp16no1;
- int16_t dE = 0;
-
- // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far
- // end energy and echo estimation error.
- // Adjust for the far end signal level. A low signal level indicates no far end signal,
- // hence we set the suppression gain to 0
- if (!aecm->currentVADValue)
- {
- supGain = 0;
- } else
- {
- // Adjust for possible double talk. If we have large variations in estimation error we
- // likely have double talk (or poor channel).
- tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET);
- dE = WEBRTC_SPL_ABS_W16(tmp16no1);
-
- if (dE < ENERGY_DEV_TOL)
- {
- // Likely no double talk. The better estimation, the more we can suppress signal.
- // Update counters
- if (dE < SUPGAIN_EPC_DT)
- {
- tmp32no1 = aecm->supGainErrParamDiffAB * dE;
- tmp32no1 += (SUPGAIN_EPC_DT >> 1);
- tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
- supGain = aecm->supGainErrParamA - tmp16no1;
- } else
- {
- tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE);
- tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
- tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL
- - SUPGAIN_EPC_DT));
- supGain = aecm->supGainErrParamD + tmp16no1;
- }
- } else
- {
- // Likely in double talk. Use default value
- supGain = aecm->supGainErrParamD;
- }
- }
-
- if (supGain > aecm->supGainOld)
- {
- tmp16no1 = supGain;
- } else
- {
- tmp16no1 = aecm->supGainOld;
- }
- aecm->supGainOld = supGain;
- if (tmp16no1 < aecm->supGain)
- {
- aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
- } else
- {
- aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
- }
-
- // END: Update suppression gain
-
- return aecm->supGain;
-}
-
-void WebRtcAecm_BufferFarFrame(AecmCore* const aecm,
- const int16_t* const farend,
- const int farLen) {
- int writeLen = farLen, writePos = 0;
-
- // Check if the write position must be wrapped
- while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN)
- {
- // Write to remaining buffer space before wrapping
- writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
- memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
- sizeof(int16_t) * writeLen);
- aecm->farBufWritePos = 0;
- writePos = writeLen;
- writeLen = farLen - writeLen;
- }
-
- memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
- sizeof(int16_t) * writeLen);
- aecm->farBufWritePos += writeLen;
-}
-
-void WebRtcAecm_FetchFarFrame(AecmCore* const aecm,
- int16_t* const farend,
- const int farLen,
- const int knownDelay) {
- int readLen = farLen;
- int readPos = 0;
- int delayChange = knownDelay - aecm->lastKnownDelay;
-
- aecm->farBufReadPos -= delayChange;
-
- // Check if delay forces a read position wrap
- while (aecm->farBufReadPos < 0)
- {
- aecm->farBufReadPos += FAR_BUF_LEN;
- }
- while (aecm->farBufReadPos > FAR_BUF_LEN - 1)
- {
- aecm->farBufReadPos -= FAR_BUF_LEN;
- }
-
- aecm->lastKnownDelay = knownDelay;
-
- // Check if read position must be wrapped
- while (aecm->farBufReadPos + readLen > FAR_BUF_LEN)
- {
-
- // Read from remaining buffer space before wrapping
- readLen = FAR_BUF_LEN - aecm->farBufReadPos;
- memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
- sizeof(int16_t) * readLen);
- aecm->farBufReadPos = 0;
- readPos = readLen;
- readLen = farLen - readLen;
- }
- memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
- sizeof(int16_t) * readLen);
- aecm->farBufReadPos += readLen;
-}
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core.cc b/webrtc/modules/audio_processing/aecm/aecm_core.cc
new file mode 100644
index 0000000..78c0133
--- /dev/null
+++ b/webrtc/modules/audio_processing/aecm/aecm_core.cc
@@ -0,0 +1,1125 @@
+/*
+ * 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/audio_processing/aecm/aecm_core.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+#include "common_audio/ring_buffer.h"
+#include "common_audio/signal_processing/include/real_fft.h"
+}
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "modules/audio_processing/aecm/echo_control_mobile.h"
+#include "modules/audio_processing/utility/delay_estimator_wrapper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+namespace {
+
+#ifdef AEC_DEBUG
+FILE* dfile;
+FILE* testfile;
+#endif
+
+// Initialization table for echo channel in 8 kHz
+static const int16_t kChannelStored8kHz[PART_LEN1] = {
+ 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418, 1451, 1506, 1562,
+ 1644, 1726, 1804, 1882, 1918, 1953, 1982, 2010, 2025, 2040, 2034,
+ 2027, 2021, 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683, 1635,
+ 1604, 1572, 1545, 1517, 1481, 1444, 1405, 1367, 1331, 1294, 1270,
+ 1245, 1239, 1233, 1247, 1260, 1282, 1303, 1338, 1373, 1407, 1441,
+ 1470, 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649, 1676};
+
+// Initialization table for echo channel in 16 kHz
+static const int16_t kChannelStored16kHz[PART_LEN1] = {
+ 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882, 1953, 2010, 2040,
+ 2027, 2014, 1980, 1869, 1732, 1635, 1572, 1517, 1444, 1367, 1294,
+ 1245, 1233, 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621, 1676,
+ 1741, 1802, 1861, 1921, 1983, 2040, 2102, 2170, 2265, 2375, 2515,
+ 2651, 2781, 2922, 3075, 3253, 3471, 3738, 3976, 4151, 4258, 4308,
+ 4288, 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484, 3153};
+
+} // namespace
+
+const int16_t WebRtcAecm_kCosTable[] = {
+ 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, 8091, 8067,
+ 8041, 8012, 7982, 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647,
+ 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 7094, 7021, 6947,
+ 6870, 6791, 6710, 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991,
+ 5892, 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, 4815,
+ 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 3719, 3591, 3462,
+ 3331, 3200, 3068, 2935, 2801, 2667, 2531, 2395, 2258, 2120, 1981,
+ 1842, 1703, 1563, 1422, 1281, 1140, 998, 856, 713, 571, 428,
+ 285, 142, 0, -142, -285, -428, -571, -713, -856, -998, -1140,
+ -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667,
+ -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845, -3971, -4095,
+ -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155, -5265, -5374,
+ -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455,
+ -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, -7299,
+ -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791, -7834, -7874,
+ -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, -8147, -8160,
+ -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172, -8160, -8147,
+ -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
+ -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, -7299, -7233,
+ -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542, -6455, -6366,
+ -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, -5265,
+ -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971,
+ -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, -2531,
+ -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, -1140, -998,
+ -856, -713, -571, -428, -285, -142, 0, 142, 285, 428, 571,
+ 713, 856, 998, 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120,
+ 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591,
+ 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, 4815, 4930,
+ 5043, 5155, 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, 6087,
+ 6182, 6275, 6366, 6455, 6542, 6627, 6710, 6791, 6870, 6947, 7021,
+ 7094, 7164, 7233, 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697,
+ 7745, 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, 8091,
+ 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190};
+
+const int16_t WebRtcAecm_kSinTable[] = {
+ 0, 142, 285, 428, 571, 713, 856, 998, 1140, 1281, 1422,
+ 1563, 1703, 1842, 1981, 2120, 2258, 2395, 2531, 2667, 2801, 2935,
+ 3068, 3200, 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, 4341,
+ 4461, 4580, 4698, 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586,
+ 5690, 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, 6627,
+ 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, 7362, 7424,
+ 7483, 7540, 7595, 7647, 7697, 7745, 7791, 7834, 7874, 7912, 7948,
+ 7982, 8012, 8041, 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180,
+ 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112,
+ 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, 7791, 7745,
+ 7697, 7647, 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 7094,
+ 7021, 6947, 6870, 6791, 6710, 6627, 6542, 6455, 6366, 6275, 6182,
+ 6087, 5991, 5892, 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043,
+ 4930, 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 3719,
+ 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, 2531, 2395, 2258,
+ 2120, 1981, 1842, 1703, 1563, 1422, 1281, 1140, 998, 856, 713,
+ 571, 428, 285, 142, 0, -142, -285, -428, -571, -713, -856,
+ -998, -1140, -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
+ -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845,
+ -3971, -4095, -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155,
+ -5265, -5374, -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275,
+ -6366, -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164,
+ -7233, -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791,
+ -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130,
+ -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172,
+ -8160, -8147, -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912,
+ -7874, -7834, -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
+ -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542,
+ -6455, -6366, -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481,
+ -5374, -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219,
+ -4096, -3971, -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801,
+ -2667, -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281,
+ -1140, -998, -856, -713, -571, -428, -285, -142};
+
+
+// Moves the pointer to the next entry and inserts |far_spectrum| and
+// corresponding Q-domain in its buffer.
+//
+// Inputs:
+// - self : Pointer to the delay estimation instance
+// - far_spectrum : Pointer to the far end spectrum
+// - far_q : Q-domain of far end spectrum
+//
+void WebRtcAecm_UpdateFarHistory(AecmCore* self,
+ uint16_t* far_spectrum,
+ int far_q) {
+ // Get new buffer position
+ self->far_history_pos++;
+ if (self->far_history_pos >= MAX_DELAY) {
+ self->far_history_pos = 0;
+ }
+ // Update Q-domain buffer
+ self->far_q_domains[self->far_history_pos] = far_q;
+ // Update far end spectrum buffer
+ memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]), far_spectrum,
+ sizeof(uint16_t) * PART_LEN1);
+}
+
+// Returns a pointer to the far end spectrum aligned to current near end
+// spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
+// called before AlignedFarend(...). Otherwise, you get the pointer to the
+// previous frame. The memory is only valid until the next call of
+// WebRtc_DelayEstimatorProcessFix(...).
+//
+// Inputs:
+// - self : Pointer to the AECM instance.
+// - delay : Current delay estimate.
+//
+// Output:
+// - far_q : The Q-domain of the aligned far end spectrum
+//
+// Return value:
+// - far_spectrum : Pointer to the aligned far end spectrum
+// NULL - Error
+//
+const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self,
+ int* far_q,
+ int delay) {
+ int buffer_position = 0;
+ RTC_DCHECK(self);
+ buffer_position = self->far_history_pos - delay;
+
+ // Check buffer position
+ if (buffer_position < 0) {
+ buffer_position += MAX_DELAY;
+ }
+ // Get Q-domain
+ *far_q = self->far_q_domains[buffer_position];
+ // Return far end spectrum
+ return &(self->far_history[buffer_position * PART_LEN1]);
+}
+
+// Declare function pointers.
+CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
+StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
+ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
+
+AecmCore* WebRtcAecm_CreateCore() {
+ // Allocate zero-filled memory.
+ AecmCore* aecm = static_cast<AecmCore*>(calloc(1, sizeof(AecmCore)));
+
+ aecm->farFrameBuf =
+ WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
+ if (!aecm->farFrameBuf) {
+ WebRtcAecm_FreeCore(aecm);
+ return NULL;
+ }
+
+ aecm->nearNoisyFrameBuf =
+ WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
+ if (!aecm->nearNoisyFrameBuf) {
+ WebRtcAecm_FreeCore(aecm);
+ return NULL;
+ }
+
+ aecm->nearCleanFrameBuf =
+ WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
+ if (!aecm->nearCleanFrameBuf) {
+ WebRtcAecm_FreeCore(aecm);
+ return NULL;
+ }
+
+ aecm->outFrameBuf =
+ WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
+ if (!aecm->outFrameBuf) {
+ WebRtcAecm_FreeCore(aecm);
+ return NULL;
+ }
+
+ aecm->delay_estimator_farend =
+ WebRtc_CreateDelayEstimatorFarend(PART_LEN1, MAX_DELAY);
+ if (aecm->delay_estimator_farend == NULL) {
+ WebRtcAecm_FreeCore(aecm);
+ return NULL;
+ }
+ aecm->delay_estimator =
+ WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
+ if (aecm->delay_estimator == NULL) {
+ WebRtcAecm_FreeCore(aecm);
+ return NULL;
+ }
+ // TODO(bjornv): Explicitly disable robust delay validation until no
+ // performance regression has been established. Then remove the line.
+ WebRtc_enable_robust_validation(aecm->delay_estimator, 0);
+
+ aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
+ if (aecm->real_fft == NULL) {
+ WebRtcAecm_FreeCore(aecm);
+ return NULL;
+ }
+
+ // Init some aecm pointers. 16 and 32 byte alignment is only necessary
+ // for Neon code currently.
+ aecm->xBuf = (int16_t*)(((uintptr_t)aecm->xBuf_buf + 31) & ~31);
+ aecm->dBufClean = (int16_t*)(((uintptr_t)aecm->dBufClean_buf + 31) & ~31);
+ aecm->dBufNoisy = (int16_t*)(((uintptr_t)aecm->dBufNoisy_buf + 31) & ~31);
+ aecm->outBuf = (int16_t*)(((uintptr_t)aecm->outBuf_buf + 15) & ~15);
+ aecm->channelStored =
+ (int16_t*)(((uintptr_t)aecm->channelStored_buf + 15) & ~15);
+ aecm->channelAdapt16 =
+ (int16_t*)(((uintptr_t)aecm->channelAdapt16_buf + 15) & ~15);
+ aecm->channelAdapt32 =
+ (int32_t*)(((uintptr_t)aecm->channelAdapt32_buf + 31) & ~31);
+
+ return aecm;
+}
+
+void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) {
+ int i = 0;
+
+ // Reset the stored channel
+ memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
+ // Reset the adapted channels
+ memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
+ for (i = 0; i < PART_LEN1; i++) {
+ aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16;
+ }
+
+ // Reset channel storing variables
+ aecm->mseAdaptOld = 1000;
+ aecm->mseStoredOld = 1000;
+ aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
+ aecm->mseChannelCount = 0;
+}
+
+static void CalcLinearEnergiesC(AecmCore* aecm,
+ const uint16_t* far_spectrum,
+ int32_t* echo_est,
+ uint32_t* far_energy,
+ uint32_t* echo_energy_adapt,
+ uint32_t* echo_energy_stored) {
+ int i;
+
+ // Get energy for the delayed far end signal and estimated
+ // echo using both stored and adapted channels.
+ for (i = 0; i < PART_LEN1; i++) {
+ echo_est[i] =
+ WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
+ (*far_energy) += (uint32_t)(far_spectrum[i]);
+ *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
+ (*echo_energy_stored) += (uint32_t)echo_est[i];
+ }
+}
+
+static void StoreAdaptiveChannelC(AecmCore* aecm,
+ const uint16_t* far_spectrum,
+ int32_t* echo_est) {
+ int i;
+
+ // During startup we store the channel every block.
+ memcpy(aecm->channelStored, aecm->channelAdapt16,
+ sizeof(int16_t) * PART_LEN1);
+ // Recalculate echo estimate
+ for (i = 0; i < PART_LEN; i += 4) {
+ echo_est[i] =
+ WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
+ echo_est[i + 1] =
+ WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], far_spectrum[i + 1]);
+ echo_est[i + 2] =
+ WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], far_spectrum[i + 2]);
+ echo_est[i + 3] =
+ WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], far_spectrum[i + 3]);
+ }
+ echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
+}
+
+static void ResetAdaptiveChannelC(AecmCore* aecm) {
+ int i;
+
+ // The stored channel has a significantly lower MSE than the adaptive one for
+ // two consecutive calculations. Reset the adaptive channel.
+ memcpy(aecm->channelAdapt16, aecm->channelStored,
+ sizeof(int16_t) * PART_LEN1);
+ // Restore the W32 channel
+ for (i = 0; i < PART_LEN; i += 4) {
+ aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
+ aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16;
+ aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16;
+ aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16;
+ }
+ aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
+}
+
+// Initialize function pointers for ARM Neon platform.
+#if defined(WEBRTC_HAS_NEON)
+static void WebRtcAecm_InitNeon(void) {
+ WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon;
+ WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon;
+ WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon;
+}
+#endif
+
+// Initialize function pointers for MIPS platform.
+#if defined(MIPS32_LE)
+static void WebRtcAecm_InitMips(void) {
+#if defined(MIPS_DSP_R1_LE)
+ WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips;
+ WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips;
+#endif
+ WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips;
+}
+#endif
+
+// WebRtcAecm_InitCore(...)
+//
+// This function initializes the AECM instant created with
+// WebRtcAecm_CreateCore(...) Input:
+// - aecm : Pointer to the Echo Suppression instance
+// - samplingFreq : Sampling Frequency
+//
+// Output:
+// - aecm : Initialized instance
+//
+// Return value : 0 - Ok
+// -1 - Error
+//
+int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq) {
+ int i = 0;
+ int32_t tmp32 = PART_LEN1 * PART_LEN1;
+ int16_t tmp16 = PART_LEN1;
+
+ if (samplingFreq != 8000 && samplingFreq != 16000) {
+ samplingFreq = 8000;
+ return -1;
+ }
+ // sanity check of sampling frequency
+ aecm->mult = (int16_t)samplingFreq / 8000;
+
+ aecm->farBufWritePos = 0;
+ aecm->farBufReadPos = 0;
+ aecm->knownDelay = 0;
+ aecm->lastKnownDelay = 0;
+
+ WebRtc_InitBuffer(aecm->farFrameBuf);
+ WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
+ WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
+ WebRtc_InitBuffer(aecm->outFrameBuf);
+
+ memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
+ memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
+ memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
+ memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
+
+ aecm->seed = 666;
+ aecm->totCount = 0;
+
+ if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
+ return -1;
+ }
+ if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
+ return -1;
+ }
+ // Set far end histories to zero
+ memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
+ memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
+ aecm->far_history_pos = MAX_DELAY;
+
+ aecm->nlpFlag = 1;
+ aecm->fixedDelay = -1;
+
+ aecm->dfaCleanQDomain = 0;
+ aecm->dfaCleanQDomainOld = 0;
+ aecm->dfaNoisyQDomain = 0;
+ aecm->dfaNoisyQDomainOld = 0;
+
+ memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
+ aecm->farLogEnergy = 0;
+ memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
+ memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
+
+ // Initialize the echo channels with a stored shape.
+ if (samplingFreq == 8000) {
+ WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
+ } else {
+ WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
+ }
+
+ memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
+ memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
+ aecm->noiseEstCtr = 0;
+
+ aecm->cngMode = AecmTrue;
+
+ memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
+ memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
+ // Shape the initial noise level to an approximate pink noise.
+ for (i = 0; i < (PART_LEN1 >> 1) - 1; i++) {
+ aecm->noiseEst[i] = (tmp32 << 8);
+ tmp16--;
+ tmp32 -= (int32_t)((tmp16 << 1) + 1);
+ }
+ for (; i < PART_LEN1; i++) {
+ aecm->noiseEst[i] = (tmp32 << 8);
+ }
+
+ aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
+ aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
+ aecm->farEnergyMaxMin = 0;
+ aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection
+ // at the beginning.
+ aecm->farEnergyMSE = 0;
+ aecm->currentVADValue = 0;
+ aecm->vadUpdateCount = 0;
+ aecm->firstVAD = 1;
+
+ aecm->startupState = 0;
+ aecm->supGain = SUPGAIN_DEFAULT;
+ aecm->supGainOld = SUPGAIN_DEFAULT;
+
+ aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
+ aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
+ aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
+ aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
+
+ // Assert a preprocessor definition at compile-time. It's an assumption
+ // used in assembly code, so check the assembly files before any change.
+ static_assert(PART_LEN % 16 == 0, "PART_LEN is not a multiple of 16");
+
+ // Initialize function pointers.
+ WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
+ WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
+ WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
+
+#if defined(WEBRTC_HAS_NEON)
+ WebRtcAecm_InitNeon();
+#endif
+
+#if defined(MIPS32_LE)
+ WebRtcAecm_InitMips();
+#endif
+ return 0;
+}
+
+// TODO(bjornv): This function is currently not used. Add support for these
+// parameters from a higher level
+int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) {
+ aecm->nlpFlag = nlpFlag;
+ aecm->fixedDelay = delay;
+
+ return 0;
+}
+
+void WebRtcAecm_FreeCore(AecmCore* aecm) {
+ if (aecm == NULL) {
+ return;
+ }
+
+ WebRtc_FreeBuffer(aecm->farFrameBuf);
+ WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
+ WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
+ WebRtc_FreeBuffer(aecm->outFrameBuf);
+
+ WebRtc_FreeDelayEstimator(aecm->delay_estimator);
+ WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
+ WebRtcSpl_FreeRealFFT(aecm->real_fft);
+
+ free(aecm);
+}
+
+int WebRtcAecm_ProcessFrame(AecmCore* aecm,
+ const int16_t* farend,
+ const int16_t* nearendNoisy,
+ const int16_t* nearendClean,
+ int16_t* out) {
+ int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
+ int16_t* outBlock = (int16_t*)(((uintptr_t)outBlock_buf + 15) & ~15);
+
+ int16_t farFrame[FRAME_LEN];
+ const int16_t* out_ptr = NULL;
+ int size = 0;
+
+ // Buffer the current frame.
+ // Fetch an older one corresponding to the delay.
+ WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
+ WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
+
+ // Buffer the synchronized far and near frames,
+ // to pass the smaller blocks individually.
+ WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
+ WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
+ if (nearendClean != NULL) {
+ WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
+ }
+
+ // Process as many blocks as possible.
+ while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN) {
+ int16_t far_block[PART_LEN];
+ const int16_t* far_block_ptr = NULL;
+ int16_t near_noisy_block[PART_LEN];
+ const int16_t* near_noisy_block_ptr = NULL;
+
+ WebRtc_ReadBuffer(aecm->farFrameBuf, (void**)&far_block_ptr, far_block,
+ PART_LEN);
+ WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf, (void**)&near_noisy_block_ptr,
+ near_noisy_block, PART_LEN);
+ if (nearendClean != NULL) {
+ int16_t near_clean_block[PART_LEN];
+ const int16_t* near_clean_block_ptr = NULL;
+
+ WebRtc_ReadBuffer(aecm->nearCleanFrameBuf, (void**)&near_clean_block_ptr,
+ near_clean_block, PART_LEN);
+ if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr,
+ near_clean_block_ptr, outBlock) == -1) {
+ return -1;
+ }
+ } else {
+ if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr,
+ NULL, outBlock) == -1) {
+ return -1;
+ }
+ }
+
+ WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
+ }
+
+ // Stuff the out buffer if we have less than a frame to output.
+ // This should only happen for the first frame.
+ size = (int)WebRtc_available_read(aecm->outFrameBuf);
+ if (size < FRAME_LEN) {
+ WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
+ }
+
+ // Obtain an output frame.
+ WebRtc_ReadBuffer(aecm->outFrameBuf, (void**)&out_ptr, out, FRAME_LEN);
+ if (out_ptr != out) {
+ // ReadBuffer() hasn't copied to |out| in this case.
+ memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
+ }
+
+ return 0;
+}
+
+// WebRtcAecm_AsymFilt(...)
+//
+// Performs asymmetric filtering.
+//
+// Inputs:
+// - filtOld : Previous filtered value.
+// - inVal : New input value.
+// - stepSizePos : Step size when we have a positive contribution.
+// - stepSizeNeg : Step size when we have a negative contribution.
+//
+// Output:
+//
+// Return: - Filtered value.
+//
+int16_t WebRtcAecm_AsymFilt(const int16_t filtOld,
+ const int16_t inVal,
+ const int16_t stepSizePos,
+ const int16_t stepSizeNeg) {
+ int16_t retVal;
+
+ if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN)) {
+ return inVal;
+ }
+ retVal = filtOld;
+ if (filtOld > inVal) {
+ retVal -= (filtOld - inVal) >> stepSizeNeg;
+ } else {
+ retVal += (inVal - filtOld) >> stepSizePos;
+ }
+
+ return retVal;
+}
+
+// ExtractFractionPart(a, zeros)
+//
+// returns the fraction part of |a|, with |zeros| number of leading zeros, as an
+// int16_t scaled to Q8. There is no sanity check of |a| in the sense that the
+// number of zeros match.
+static int16_t ExtractFractionPart(uint32_t a, int zeros) {
+ return (int16_t)(((a << zeros) & 0x7FFFFFFF) >> 23);
+}
+
+// Calculates and returns the log of |energy| in Q8. The input |energy| is
+// supposed to be in Q(|q_domain|).
+static int16_t LogOfEnergyInQ8(uint32_t energy, int q_domain) {
+ static const int16_t kLogLowValue = PART_LEN_SHIFT << 7;
+ int16_t log_energy_q8 = kLogLowValue;
+ if (energy > 0) {
+ int zeros = WebRtcSpl_NormU32(energy);
+ int16_t frac = ExtractFractionPart(energy, zeros);
+ // log2 of |energy| in Q8.
+ log_energy_q8 += ((31 - zeros) << 8) + frac - (q_domain << 8);
+ }
+ return log_energy_q8;
+}
+
+// WebRtcAecm_CalcEnergies(...)
+//
+// This function calculates the log of energies for nearend, farend and
+// estimated echoes. There is also an update of energy decision levels, i.e.
+// internal VAD.
+//
+//
+// @param aecm [i/o] Handle of the AECM instance.
+// @param far_spectrum [in] Pointer to farend spectrum.
+// @param far_q [in] Q-domain of farend spectrum.
+// @param nearEner [in] Near end energy for current block in
+// Q(aecm->dfaQDomain).
+// @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
+//
+void WebRtcAecm_CalcEnergies(AecmCore* aecm,
+ const uint16_t* far_spectrum,
+ const int16_t far_q,
+ const uint32_t nearEner,
+ int32_t* echoEst) {
+ // Local variables
+ uint32_t tmpAdapt = 0;
+ uint32_t tmpStored = 0;
+ uint32_t tmpFar = 0;
+
+ int i;
+
+ int16_t tmp16;
+ int16_t increase_max_shifts = 4;
+ int16_t decrease_max_shifts = 11;
+ int16_t increase_min_shifts = 11;
+ int16_t decrease_min_shifts = 3;
+
+ // Get log of near end energy and store in buffer
+
+ // Shift buffer
+ memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
+ sizeof(int16_t) * (MAX_BUF_LEN - 1));
+
+ // Logarithm of integrated magnitude spectrum (nearEner)
+ aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain);
+
+ WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt,
+ &tmpStored);
+
+ // Shift buffers
+ memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
+ sizeof(int16_t) * (MAX_BUF_LEN - 1));
+ memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
+ sizeof(int16_t) * (MAX_BUF_LEN - 1));
+
+ // Logarithm of delayed far end energy
+ aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q);
+
+ // Logarithm of estimated echo energy through adapted channel
+ aecm->echoAdaptLogEnergy[0] =
+ LogOfEnergyInQ8(tmpAdapt, RESOLUTION_CHANNEL16 + far_q);
+
+ // Logarithm of estimated echo energy through stored channel
+ aecm->echoStoredLogEnergy[0] =
+ LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q);
+
+ // Update farend energy levels (min, max, vad, mse)
+ if (aecm->farLogEnergy > FAR_ENERGY_MIN) {
+ if (aecm->startupState == 0) {
+ increase_max_shifts = 2;
+ decrease_min_shifts = 2;
+ increase_min_shifts = 8;
+ }
+
+ aecm->farEnergyMin =
+ WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
+ increase_min_shifts, decrease_min_shifts);
+ aecm->farEnergyMax =
+ WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
+ increase_max_shifts, decrease_max_shifts);
+ aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
+
+ // Dynamic VAD region size
+ tmp16 = 2560 - aecm->farEnergyMin;
+ if (tmp16 > 0) {
+ tmp16 = (int16_t)((tmp16 * FAR_ENERGY_VAD_REGION) >> 9);
+ } else {
+ tmp16 = 0;
+ }
+ tmp16 += FAR_ENERGY_VAD_REGION;
+
+ if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024)) {
+ // In startup phase or VAD update halted
+ aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
+ } else {
+ if (aecm->farEnergyVAD > aecm->farLogEnergy) {
+ aecm->farEnergyVAD +=
+ (aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> 6;
+ aecm->vadUpdateCount = 0;
+ } else {
+ aecm->vadUpdateCount++;
+ }
+ }
+ // Put MSE threshold higher than VAD
+ aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
+ }
+
+ // Update VAD variables
+ if (aecm->farLogEnergy > aecm->farEnergyVAD) {
+ if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF)) {
+ // We are in startup or have significant dynamics in input speech level
+ aecm->currentVADValue = 1;
+ }
+ } else {
+ aecm->currentVADValue = 0;
+ }
+ if ((aecm->currentVADValue) && (aecm->firstVAD)) {
+ aecm->firstVAD = 0;
+ if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0]) {
+ // The estimated echo has higher energy than the near end signal.
+ // This means that the initialization was too aggressive. Scale
+ // down by a factor 8
+ for (i = 0; i < PART_LEN1; i++) {
+ aecm->channelAdapt16[i] >>= 3;
+ }
+ // Compensate the adapted echo energy level accordingly.
+ aecm->echoAdaptLogEnergy[0] -= (3 << 8);
+ aecm->firstVAD = 1;
+ }
+ }
+}
+
+// WebRtcAecm_CalcStepSize(...)
+//
+// This function calculates the step size used in channel estimation
+//
+//
+// @param aecm [in] Handle of the AECM instance.
+// @param mu [out] (Return value) Stepsize in log2(), i.e. number of
+// shifts.
+//
+//
+int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm) {
+ int32_t tmp32;
+ int16_t tmp16;
+ int16_t mu = MU_MAX;
+
+ // Here we calculate the step size mu used in the
+ // following NLMS based Channel estimation algorithm
+ if (!aecm->currentVADValue) {
+ // Far end energy level too low, no channel update
+ mu = 0;
+ } else if (aecm->startupState > 0) {
+ if (aecm->farEnergyMin >= aecm->farEnergyMax) {
+ mu = MU_MIN;
+ } else {
+ tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
+ tmp32 = tmp16 * MU_DIFF;
+ tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
+ mu = MU_MIN - 1 - (int16_t)(tmp32);
+ // The -1 is an alternative to rounding. This way we get a larger
+ // stepsize, so we in some sense compensate for truncation in NLMS
+ }
+ if (mu < MU_MAX) {
+ mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
+ }
+ }
+
+ return mu;
+}
+
+// WebRtcAecm_UpdateChannel(...)
+//
+// This function performs channel estimation. NLMS and decision on channel
+// storage.
+//
+//
+// @param aecm [i/o] Handle of the AECM instance.
+// @param far_spectrum [in] Absolute value of the farend signal in Q(far_q)
+// @param far_q [in] Q-domain of the farend signal
+// @param dfa [in] Absolute value of the nearend signal
+// (Q[aecm->dfaQDomain])
+// @param mu [in] NLMS step size.
+// @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
+//
+void WebRtcAecm_UpdateChannel(AecmCore* aecm,
+ const uint16_t* far_spectrum,
+ const int16_t far_q,
+ const uint16_t* const dfa,
+ const int16_t mu,
+ int32_t* echoEst) {
+ uint32_t tmpU32no1, tmpU32no2;
+ int32_t tmp32no1, tmp32no2;
+ int32_t mseStored;
+ int32_t mseAdapt;
+
+ int i;
+
+ int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
+ int16_t shiftChFar, shiftNum, shift2ResChan;
+ int16_t tmp16no1;
+ int16_t xfaQ, dfaQ;
+
+ // This is the channel estimation algorithm. It is base on NLMS but has a
+ // variable step length, which was calculated above.
+ if (mu) {
+ for (i = 0; i < PART_LEN1; i++) {
+ // Determine norm of channel and farend to make sure we don't get overflow
+ // in multiplication
+ zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
+ zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
+ if (zerosCh + zerosFar > 31) {
+ // Multiplication is safe
+ tmpU32no1 =
+ WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i], far_spectrum[i]);
+ shiftChFar = 0;
+ } else {
+ // We need to shift down before multiplication
+ shiftChFar = 32 - zerosCh - zerosFar;
+ // If zerosCh == zerosFar == 0, shiftChFar is 32. A
+ // right shift of 32 is undefined. To avoid that, we
+ // do this check.
+ tmpU32no1 =
+ rtc::dchecked_cast<uint32_t>(
+ shiftChFar >= 32 ? 0 : aecm->channelAdapt32[i] >> shiftChFar) *
+ far_spectrum[i];
+ }
+ // Determine Q-domain of numerator
+ zerosNum = WebRtcSpl_NormU32(tmpU32no1);
+ if (dfa[i]) {
+ zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
+ } else {
+ zerosDfa = 32;
+ }
+ tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - RESOLUTION_CHANNEL32 -
+ far_q + shiftChFar;
+ if (zerosNum > tmp16no1 + 1) {
+ xfaQ = tmp16no1;
+ dfaQ = zerosDfa - 2;
+ } else {
+ xfaQ = zerosNum - 2;
+ dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
+ shiftChFar + xfaQ;
+ }
+ // Add in the same Q-domain
+ tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
+ tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
+ tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
+ zerosNum = WebRtcSpl_NormW32(tmp32no1);
+ if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q))) {
+ //
+ // Update is needed
+ //
+ // This is what we would like to compute
+ //
+ // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
+ // tmp32norm = (i + 1)
+ // aecm->channelAdapt[i] += (2^mu) * tmp32no1
+ // / (tmp32norm * far_spectrum[i])
+ //
+
+ // Make sure we don't get overflow in multiplication.
+ if (zerosNum + zerosFar > 31) {
+ if (tmp32no1 > 0) {
+ tmp32no2 =
+ (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1, far_spectrum[i]);
+ } else {
+ tmp32no2 =
+ -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1, far_spectrum[i]);
+ }
+ shiftNum = 0;
+ } else {
+ shiftNum = 32 - (zerosNum + zerosFar);
+ if (tmp32no1 > 0) {
+ tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i];
+ } else {
+ tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]);
+ }
+ }
+ // Normalize with respect to frequency bin
+ tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
+ // Make sure we are in the right Q-domain
+ shift2ResChan =
+ shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
+ if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan) {
+ tmp32no2 = WEBRTC_SPL_WORD32_MAX;
+ } else {
+ tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
+ }
+ aecm->channelAdapt32[i] =
+ WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2);
+ if (aecm->channelAdapt32[i] < 0) {
+ // We can never have negative channel gain
+ aecm->channelAdapt32[i] = 0;
+ }
+ aecm->channelAdapt16[i] = (int16_t)(aecm->channelAdapt32[i] >> 16);
+ }
+ }
+ }
+ // END: Adaptive channel update
+
+ // Determine if we should store or restore the channel
+ if ((aecm->startupState == 0) & (aecm->currentVADValue)) {
+ // During startup we store the channel every block,
+ // and we recalculate echo estimate
+ WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
+ } else {
+ if (aecm->farLogEnergy < aecm->farEnergyMSE) {
+ aecm->mseChannelCount = 0;
+ } else {
+ aecm->mseChannelCount++;
+ }
+ // Enough data for validation. Store channel if we can.
+ if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10)) {
+ // We have enough data.
+ // Calculate MSE of "Adapt" and "Stored" versions.
+ // It is actually not MSE, but average absolute error.
+ mseStored = 0;
+ mseAdapt = 0;
+ for (i = 0; i < MIN_MSE_COUNT; i++) {
+ tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i] -
+ (int32_t)aecm->nearLogEnergy[i]);
+ tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
+ mseStored += tmp32no2;
+
+ tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i] -
+ (int32_t)aecm->nearLogEnergy[i]);
+ tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
+ mseAdapt += tmp32no2;
+ }
+ if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt)) &
+ ((aecm->mseStoredOld << MSE_RESOLUTION) <
+ (MIN_MSE_DIFF * aecm->mseAdaptOld))) {
+ // The stored channel has a significantly lower MSE than the adaptive
+ // one for two consecutive calculations. Reset the adaptive channel.
+ WebRtcAecm_ResetAdaptiveChannel(aecm);
+ } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) &
+ (mseAdapt < aecm->mseThreshold) &
+ (aecm->mseAdaptOld < aecm->mseThreshold)) {
+ // The adaptive channel has a significantly lower MSE than the stored
+ // one. The MSE for the adaptive channel has also been low for two
+ // consecutive calculations. Store the adaptive channel.
+ WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
+
+ // Update threshold
+ if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX) {
+ aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
+ } else {
+ int scaled_threshold = aecm->mseThreshold * 5 / 8;
+ aecm->mseThreshold += ((mseAdapt - scaled_threshold) * 205) >> 8;
+ }
+ }
+
+ // Reset counter
+ aecm->mseChannelCount = 0;
+
+ // Store the MSE values.
+ aecm->mseStoredOld = mseStored;
+ aecm->mseAdaptOld = mseAdapt;
+ }
+ }
+ // END: Determine if we should store or reset channel estimate.
+}
+
+// CalcSuppressionGain(...)
+//
+// This function calculates the suppression gain that is used in the Wiener
+// filter.
+//
+//
+// @param aecm [i/n] Handle of the AECM instance.
+// @param supGain [out] (Return value) Suppression gain with which to scale
+// the noise
+// level (Q14).
+//
+//
+int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm) {
+ int32_t tmp32no1;
+
+ int16_t supGain = SUPGAIN_DEFAULT;
+ int16_t tmp16no1;
+ int16_t dE = 0;
+
+ // Determine suppression gain used in the Wiener filter. The gain is based on
+ // a mix of far end energy and echo estimation error. Adjust for the far end
+ // signal level. A low signal level indicates no far end signal, hence we set
+ // the suppression gain to 0
+ if (!aecm->currentVADValue) {
+ supGain = 0;
+ } else {
+ // Adjust for possible double talk. If we have large variations in
+ // estimation error we likely have double talk (or poor channel).
+ tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] -
+ ENERGY_DEV_OFFSET);
+ dE = WEBRTC_SPL_ABS_W16(tmp16no1);
+
+ if (dE < ENERGY_DEV_TOL) {
+ // Likely no double talk. The better estimation, the more we can suppress
+ // signal. Update counters
+ if (dE < SUPGAIN_EPC_DT) {
+ tmp32no1 = aecm->supGainErrParamDiffAB * dE;
+ tmp32no1 += (SUPGAIN_EPC_DT >> 1);
+ tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
+ supGain = aecm->supGainErrParamA - tmp16no1;
+ } else {
+ tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE);
+ tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
+ tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(
+ tmp32no1, (ENERGY_DEV_TOL - SUPGAIN_EPC_DT));
+ supGain = aecm->supGainErrParamD + tmp16no1;
+ }
+ } else {
+ // Likely in double talk. Use default value
+ supGain = aecm->supGainErrParamD;
+ }
+ }
+
+ if (supGain > aecm->supGainOld) {
+ tmp16no1 = supGain;
+ } else {
+ tmp16no1 = aecm->supGainOld;
+ }
+ aecm->supGainOld = supGain;
+ if (tmp16no1 < aecm->supGain) {
+ aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
+ } else {
+ aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
+ }
+
+ // END: Update suppression gain
+
+ return aecm->supGain;
+}
+
+void WebRtcAecm_BufferFarFrame(AecmCore* const aecm,
+ const int16_t* const farend,
+ const int farLen) {
+ int writeLen = farLen, writePos = 0;
+
+ // Check if the write position must be wrapped
+ while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN) {
+ // Write to remaining buffer space before wrapping
+ writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
+ memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
+ sizeof(int16_t) * writeLen);
+ aecm->farBufWritePos = 0;
+ writePos = writeLen;
+ writeLen = farLen - writeLen;
+ }
+
+ memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
+ sizeof(int16_t) * writeLen);
+ aecm->farBufWritePos += writeLen;
+}
+
+void WebRtcAecm_FetchFarFrame(AecmCore* const aecm,
+ int16_t* const farend,
+ const int farLen,
+ const int knownDelay) {
+ int readLen = farLen;
+ int readPos = 0;
+ int delayChange = knownDelay - aecm->lastKnownDelay;
+
+ aecm->farBufReadPos -= delayChange;
+
+ // Check if delay forces a read position wrap
+ while (aecm->farBufReadPos < 0) {
+ aecm->farBufReadPos += FAR_BUF_LEN;
+ }
+ while (aecm->farBufReadPos > FAR_BUF_LEN - 1) {
+ aecm->farBufReadPos -= FAR_BUF_LEN;
+ }
+
+ aecm->lastKnownDelay = knownDelay;
+
+ // Check if read position must be wrapped
+ while (aecm->farBufReadPos + readLen > FAR_BUF_LEN) {
+ // Read from remaining buffer space before wrapping
+ readLen = FAR_BUF_LEN - aecm->farBufReadPos;
+ memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
+ sizeof(int16_t) * readLen);
+ aecm->farBufReadPos = 0;
+ readPos = readLen;
+ readLen = farLen - readLen;
+ }
+ memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
+ sizeof(int16_t) * readLen);
+ aecm->farBufReadPos += readLen;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core.h b/webrtc/modules/audio_processing/aecm/aecm_core.h
index b52bb62..aaa74e1 100644
--- a/webrtc/modules/audio_processing/aecm/aecm_core.h
+++ b/webrtc/modules/audio_processing/aecm/aecm_core.h
@@ -10,13 +10,18 @@
// Performs echo control (suppression) with fft routines in fixed-point.
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_
+#ifndef MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_
+#define MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_
-#include "webrtc/common_audio/ring_buffer.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/aecm/aecm_defines.h"
-#include "webrtc/typedefs.h"
+extern "C" {
+#include "common_audio/ring_buffer.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+}
+#include "modules/audio_processing/aecm/aecm_defines.h"
+
+struct RealFFT;
+
+namespace webrtc {
#ifdef _MSC_VER // visual c++
#define ALIGN8_BEG __declspec(align(8))
@@ -27,109 +32,109 @@
#endif
typedef struct {
- int16_t real;
- int16_t imag;
+ int16_t real;
+ int16_t imag;
} ComplexInt16;
typedef struct {
- int farBufWritePos;
- int farBufReadPos;
- int knownDelay;
- int lastKnownDelay;
- int firstVAD; // Parameter to control poorly initialized channels
-
- RingBuffer* farFrameBuf;
- RingBuffer* nearNoisyFrameBuf;
- RingBuffer* nearCleanFrameBuf;
- RingBuffer* outFrameBuf;
-
- int16_t farBuf[FAR_BUF_LEN];
-
- int16_t mult;
- uint32_t seed;
-
- // Delay estimation variables
- void* delay_estimator_farend;
- void* delay_estimator;
- uint16_t currentDelay;
- // Far end history variables
- // TODO(bjornv): Replace |far_history| with ring_buffer.
- uint16_t far_history[PART_LEN1 * MAX_DELAY];
- int far_history_pos;
- int far_q_domains[MAX_DELAY];
-
- int16_t nlpFlag;
- int16_t fixedDelay;
-
- uint32_t totCount;
-
- int16_t dfaCleanQDomain;
- int16_t dfaCleanQDomainOld;
- int16_t dfaNoisyQDomain;
- int16_t dfaNoisyQDomainOld;
-
- int16_t nearLogEnergy[MAX_BUF_LEN];
- int16_t farLogEnergy;
- int16_t echoAdaptLogEnergy[MAX_BUF_LEN];
- int16_t echoStoredLogEnergy[MAX_BUF_LEN];
-
- // The extra 16 or 32 bytes in the following buffers are for alignment based
- // Neon code.
- // It's designed this way since the current GCC compiler can't align a
- // buffer in 16 or 32 byte boundaries properly.
- int16_t channelStored_buf[PART_LEN1 + 8];
- int16_t channelAdapt16_buf[PART_LEN1 + 8];
- int32_t channelAdapt32_buf[PART_LEN1 + 8];
- int16_t xBuf_buf[PART_LEN2 + 16]; // farend
- int16_t dBufClean_buf[PART_LEN2 + 16]; // nearend
- int16_t dBufNoisy_buf[PART_LEN2 + 16]; // nearend
- int16_t outBuf_buf[PART_LEN + 8];
-
- // Pointers to the above buffers
- int16_t *channelStored;
- int16_t *channelAdapt16;
- int32_t *channelAdapt32;
- int16_t *xBuf;
- int16_t *dBufClean;
- int16_t *dBufNoisy;
- int16_t *outBuf;
-
- int32_t echoFilt[PART_LEN1];
- int16_t nearFilt[PART_LEN1];
- int32_t noiseEst[PART_LEN1];
- int noiseEstTooLowCtr[PART_LEN1];
- int noiseEstTooHighCtr[PART_LEN1];
- int16_t noiseEstCtr;
- int16_t cngMode;
-
- int32_t mseAdaptOld;
- int32_t mseStoredOld;
- int32_t mseThreshold;
-
- int16_t farEnergyMin;
- int16_t farEnergyMax;
- int16_t farEnergyMaxMin;
- int16_t farEnergyVAD;
- int16_t farEnergyMSE;
- int currentVADValue;
- int16_t vadUpdateCount;
-
- int16_t startupState;
- int16_t mseChannelCount;
- int16_t supGain;
- int16_t supGainOld;
-
- int16_t supGainErrParamA;
- int16_t supGainErrParamD;
- int16_t supGainErrParamDiffAB;
- int16_t supGainErrParamDiffBD;
-
- struct RealFFT* real_fft;
+ int farBufWritePos;
+ int farBufReadPos;
+ int knownDelay;
+ int lastKnownDelay;
+ int firstVAD; // Parameter to control poorly initialized channels
+
+ RingBuffer* farFrameBuf;
+ RingBuffer* nearNoisyFrameBuf;
+ RingBuffer* nearCleanFrameBuf;
+ RingBuffer* outFrameBuf;
+
+ int16_t farBuf[FAR_BUF_LEN];
+
+ int16_t mult;
+ uint32_t seed;
+
+ // Delay estimation variables
+ void* delay_estimator_farend;
+ void* delay_estimator;
+ uint16_t currentDelay;
+ // Far end history variables
+ // TODO(bjornv): Replace |far_history| with ring_buffer.
+ uint16_t far_history[PART_LEN1 * MAX_DELAY];
+ int far_history_pos;
+ int far_q_domains[MAX_DELAY];
+
+ int16_t nlpFlag;
+ int16_t fixedDelay;
+
+ uint32_t totCount;
+
+ int16_t dfaCleanQDomain;
+ int16_t dfaCleanQDomainOld;
+ int16_t dfaNoisyQDomain;
+ int16_t dfaNoisyQDomainOld;
+
+ int16_t nearLogEnergy[MAX_BUF_LEN];
+ int16_t farLogEnergy;
+ int16_t echoAdaptLogEnergy[MAX_BUF_LEN];
+ int16_t echoStoredLogEnergy[MAX_BUF_LEN];
+
+ // The extra 16 or 32 bytes in the following buffers are for alignment based
+ // Neon code.
+ // It's designed this way since the current GCC compiler can't align a
+ // buffer in 16 or 32 byte boundaries properly.
+ int16_t channelStored_buf[PART_LEN1 + 8];
+ int16_t channelAdapt16_buf[PART_LEN1 + 8];
+ int32_t channelAdapt32_buf[PART_LEN1 + 8];
+ int16_t xBuf_buf[PART_LEN2 + 16]; // farend
+ int16_t dBufClean_buf[PART_LEN2 + 16]; // nearend
+ int16_t dBufNoisy_buf[PART_LEN2 + 16]; // nearend
+ int16_t outBuf_buf[PART_LEN + 8];
+
+ // Pointers to the above buffers
+ int16_t* channelStored;
+ int16_t* channelAdapt16;
+ int32_t* channelAdapt32;
+ int16_t* xBuf;
+ int16_t* dBufClean;
+ int16_t* dBufNoisy;
+ int16_t* outBuf;
+
+ int32_t echoFilt[PART_LEN1];
+ int16_t nearFilt[PART_LEN1];
+ int32_t noiseEst[PART_LEN1];
+ int noiseEstTooLowCtr[PART_LEN1];
+ int noiseEstTooHighCtr[PART_LEN1];
+ int16_t noiseEstCtr;
+ int16_t cngMode;
+
+ int32_t mseAdaptOld;
+ int32_t mseStoredOld;
+ int32_t mseThreshold;
+
+ int16_t farEnergyMin;
+ int16_t farEnergyMax;
+ int16_t farEnergyMaxMin;
+ int16_t farEnergyVAD;
+ int16_t farEnergyMSE;
+ int currentVADValue;
+ int16_t vadUpdateCount;
+
+ int16_t startupState;
+ int16_t mseChannelCount;
+ int16_t supGain;
+ int16_t supGainOld;
+
+ int16_t supGainErrParamA;
+ int16_t supGainErrParamD;
+ int16_t supGainErrParamDiffAB;
+ int16_t supGainErrParamDiffBD;
+
+ struct RealFFT* real_fft;
#ifdef AEC_DEBUG
- FILE *farFile;
- FILE *nearFile;
- FILE *outFile;
+ FILE* farFile;
+ FILE* nearFile;
+ FILE* outFile;
#endif
} AecmCore;
@@ -400,7 +405,7 @@ extern ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
// For the above function pointers, functions for generic platforms are declared
// and defined as static in file aecm_core.c, while those for ARM Neon platforms
// are declared below and defined in file aecm_core_neon.c.
-#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
+#if defined(WEBRTC_HAS_NEON)
void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm,
const uint16_t* far_spectrum,
int32_t* echo_est,
@@ -431,4 +436,6 @@ void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm);
#endif
#endif
+} // namespace webrtc
+
#endif
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core_c.c b/webrtc/modules/audio_processing/aecm/aecm_core_c.cc
index df95e8b..7b6ca59 100644
--- a/webrtc/modules/audio_processing/aecm/aecm_core_c.c
+++ b/webrtc/modules/audio_processing/aecm/aecm_core_c.cc
@@ -8,49 +8,50 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
-
-#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
-#include "webrtc/common_audio/ring_buffer.h"
-#include "webrtc/common_audio/signal_processing/include/real_fft.h"
-#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
-#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
-#include "webrtc/system_wrappers/include/compile_assert_c.h"
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_processing/aecm/aecm_core.h"
+
+extern "C" {
+#include "common_audio/ring_buffer.h"
+#include "common_audio/signal_processing/include/real_fft.h"
+}
+#include "modules/audio_processing/aecm/echo_control_mobile.h"
+#include "modules/audio_processing/utility/delay_estimator_wrapper.h"
+extern "C" {
+#include "system_wrappers/include/cpu_features_wrapper.h"
+}
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/sanitizer.h"
+
+namespace webrtc {
+
+namespace {
// Square root of Hanning window in Q14.
-#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
-// Table is defined in an ARM assembly file.
-extern const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END;
-#else
static const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
- 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
- 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224,
- 6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040,
- 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
- 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553,
- 13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079,
- 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034,
- 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384
-};
-#endif
+ 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, 3562, 3951,
+ 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019,
+ 8364, 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
+ 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189,
+ 14384, 14571, 14749, 14918, 15079, 15231, 15373, 15506, 15631, 15746, 15851,
+ 15947, 16034, 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384};
#ifdef AECM_WITH_ABS_APPROX
-//Q15 alpha = 0.99439986968132 const Factor for magnitude approximation
+// Q15 alpha = 0.99439986968132 const Factor for magnitude approximation
static const uint16_t kAlpha1 = 32584;
-//Q15 beta = 0.12967166976970 const Factor for magnitude approximation
+// Q15 beta = 0.12967166976970 const Factor for magnitude approximation
static const uint16_t kBeta1 = 4249;
-//Q15 alpha = 0.94234827210087 const Factor for magnitude approximation
+// Q15 alpha = 0.94234827210087 const Factor for magnitude approximation
static const uint16_t kAlpha2 = 30879;
-//Q15 beta = 0.33787806009150 const Factor for magnitude approximation
+// Q15 beta = 0.33787806009150 const Factor for magnitude approximation
static const uint16_t kBeta2 = 11072;
-//Q15 alpha = 0.82247698684306 const Factor for magnitude approximation
+// Q15 alpha = 0.82247698684306 const Factor for magnitude approximation
static const uint16_t kAlpha3 = 26951;
-//Q15 beta = 0.57762063060713 const Factor for magnitude approximation
+// Q15 beta = 0.57762063060713 const Factor for magnitude approximation
static const uint16_t kBeta3 = 18927;
#endif
@@ -60,7 +61,115 @@ static const int16_t kNoiseEstIncCount = 5;
static void ComfortNoise(AecmCore* aecm,
const uint16_t* dfa,
ComplexInt16* out,
- const int16_t* lambda);
+ const int16_t* lambda) {
+ int16_t i;
+ int16_t tmp16;
+ int32_t tmp32;
+
+ int16_t randW16[PART_LEN];
+ int16_t uReal[PART_LEN1];
+ int16_t uImag[PART_LEN1];
+ int32_t outLShift32;
+ int16_t noiseRShift16[PART_LEN1];
+
+ int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
+ int16_t minTrackShift;
+
+ RTC_DCHECK_GE(shiftFromNearToNoise, 0);
+ RTC_DCHECK_LT(shiftFromNearToNoise, 16);
+
+ if (aecm->noiseEstCtr < 100) {
+ // Track the minimum more quickly initially.
+ aecm->noiseEstCtr++;
+ minTrackShift = 6;
+ } else {
+ minTrackShift = 9;
+ }
+
+ // Estimate noise power.
+ for (i = 0; i < PART_LEN1; i++) {
+ // Shift to the noise domain.
+ tmp32 = (int32_t)dfa[i];
+ outLShift32 = tmp32 << shiftFromNearToNoise;
+
+ if (outLShift32 < aecm->noiseEst[i]) {
+ // Reset "too low" counter
+ aecm->noiseEstTooLowCtr[i] = 0;
+ // Track the minimum.
+ if (aecm->noiseEst[i] < (1 << minTrackShift)) {
+ // For small values, decrease noiseEst[i] every
+ // |kNoiseEstIncCount| block. The regular approach below can not
+ // go further down due to truncation.
+ aecm->noiseEstTooHighCtr[i]++;
+ if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) {
+ aecm->noiseEst[i]--;
+ aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
+ }
+ } else {
+ aecm->noiseEst[i] -=
+ ((aecm->noiseEst[i] - outLShift32) >> minTrackShift);
+ }
+ } else {
+ // Reset "too high" counter
+ aecm->noiseEstTooHighCtr[i] = 0;
+ // Ramp slowly upwards until we hit the minimum again.
+ if ((aecm->noiseEst[i] >> 19) > 0) {
+ // Avoid overflow.
+ // Multiplication with 2049 will cause wrap around. Scale
+ // down first and then multiply
+ aecm->noiseEst[i] >>= 11;
+ aecm->noiseEst[i] *= 2049;
+ } else if ((aecm->noiseEst[i] >> 11) > 0) {
+ // Large enough for relative increase
+ aecm->noiseEst[i] *= 2049;
+ aecm->noiseEst[i] >>= 11;
+ } else {
+ // Make incremental increases based on size every
+ // |kNoiseEstIncCount| block
+ aecm->noiseEstTooLowCtr[i]++;
+ if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) {
+ aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1;
+ aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < PART_LEN1; i++) {
+ tmp32 = aecm->noiseEst[i] >> shiftFromNearToNoise;
+ if (tmp32 > 32767) {
+ tmp32 = 32767;
+ aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise;
+ }
+ noiseRShift16[i] = (int16_t)tmp32;
+
+ tmp16 = ONE_Q14 - lambda[i];
+ noiseRShift16[i] = (int16_t)((tmp16 * noiseRShift16[i]) >> 14);
+ }
+
+ // Generate a uniform random array on [0 2^15-1].
+ WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
+
+ // Generate noise according to estimated energy.
+ uReal[0] = 0; // Reject LF noise.
+ uImag[0] = 0;
+ for (i = 1; i < PART_LEN1; i++) {
+ // Get a random index for the cos and sin tables over [0 359].
+ tmp16 = (int16_t)((359 * randW16[i - 1]) >> 15);
+
+ // Tables are in Q13.
+ uReal[i] =
+ (int16_t)((noiseRShift16[i] * WebRtcAecm_kCosTable[tmp16]) >> 13);
+ uImag[i] =
+ (int16_t)((-noiseRShift16[i] * WebRtcAecm_kSinTable[tmp16]) >> 13);
+ }
+ uImag[PART_LEN] = 0;
+
+ for (i = 0; i < PART_LEN1; i++) {
+ out[i].real = WebRtcSpl_AddSatW16(out[i].real, uReal[i]);
+ out[i].imag = WebRtcSpl_AddSatW16(out[i].imag, uImag[i]);
+ }
+}
static void WindowAndFFT(AecmCore* aecm,
int16_t* fft,
@@ -73,11 +182,11 @@ static void WindowAndFFT(AecmCore* aecm,
for (i = 0; i < PART_LEN; i++) {
// Window time domain signal and insert into real part of
// transformation array |fft|
- int16_t scaled_time_signal = time_signal[i] << time_signal_scaling;
+ int16_t scaled_time_signal = time_signal[i] * (1 << time_signal_scaling);
fft[i] = (int16_t)((scaled_time_signal * WebRtcAecm_kSqrtHanning[i]) >> 14);
- scaled_time_signal = time_signal[i + PART_LEN] << time_signal_scaling;
- fft[PART_LEN + i] = (int16_t)((
- scaled_time_signal * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14);
+ scaled_time_signal = time_signal[i + PART_LEN] * (1 << time_signal_scaling);
+ fft[PART_LEN + i] = (int16_t)(
+ (scaled_time_signal * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14);
}
// Do forward FFT, then take only the first PART_LEN complex samples,
@@ -114,32 +223,27 @@ static void InverseFFTAndWindow(AecmCore* aecm,
outCFFT = WebRtcSpl_RealInverseFFT(aecm->real_fft, fft, ifft_out);
for (i = 0; i < PART_LEN; i++) {
ifft_out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- ifft_out[i], WebRtcAecm_kSqrtHanning[i], 14);
+ ifft_out[i], WebRtcAecm_kSqrtHanning[i], 14);
tmp32no1 = WEBRTC_SPL_SHIFT_W32((int32_t)ifft_out[i],
- outCFFT - aecm->dfaCleanQDomain);
+ outCFFT - aecm->dfaCleanQDomain);
output[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
tmp32no1 + aecm->outBuf[i],
WEBRTC_SPL_WORD16_MIN);
- tmp32no1 = (ifft_out[PART_LEN + i] *
- WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14;
- tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1,
- outCFFT - aecm->dfaCleanQDomain);
- aecm->outBuf[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
- tmp32no1,
- WEBRTC_SPL_WORD16_MIN);
+ tmp32no1 =
+ (ifft_out[PART_LEN + i] * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14;
+ tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, outCFFT - aecm->dfaCleanQDomain);
+ aecm->outBuf[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1,
+ WEBRTC_SPL_WORD16_MIN);
}
// Copy the current block to the old position
// (aecm->outBuf is shifted elsewhere)
memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN);
- memcpy(aecm->dBufNoisy,
- aecm->dBufNoisy + PART_LEN,
+ memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN,
sizeof(int16_t) * PART_LEN);
- if (nearendClean != NULL)
- {
- memcpy(aecm->dBufClean,
- aecm->dBufClean + PART_LEN,
+ if (nearendClean != NULL) {
+ memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN,
sizeof(int16_t) * PART_LEN);
}
}
@@ -170,7 +274,7 @@ static int TimeToFrequencyDomain(AecmCore* aecm,
// In fft_buf, +16 for 32-byte alignment.
int16_t fft_buf[PART_LEN4 + 16];
- int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31);
+ int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31);
int16_t tmp16no1;
#ifndef WEBRTC_ARCH_ARM_V7
@@ -195,23 +299,17 @@ static int TimeToFrequencyDomain(AecmCore* aecm,
freq_signal[0].imag = 0;
freq_signal[PART_LEN].imag = 0;
freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real);
- freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16(
- freq_signal[PART_LEN].real);
- (*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) +
- (uint32_t)(freq_signal_abs[PART_LEN]);
-
- for (i = 1; i < PART_LEN; i++)
- {
- if (freq_signal[i].real == 0)
- {
+ freq_signal_abs[PART_LEN] =
+ (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[PART_LEN].real);
+ (*freq_signal_sum_abs) =
+ (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]);
+
+ for (i = 1; i < PART_LEN; i++) {
+ if (freq_signal[i].real == 0) {
freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
- }
- else if (freq_signal[i].imag == 0)
- {
+ } else if (freq_signal[i].imag == 0) {
freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].real);
- }
- else
- {
+ } else {
// Approximation for magnitude of complex fft output
// magn = sqrt(real^2 + imag^2)
// magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
@@ -222,27 +320,22 @@ static int TimeToFrequencyDomain(AecmCore* aecm,
tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
- if(tmp16no1 > tmp16no2)
- {
+ if (tmp16no1 > tmp16no2) {
max_value = tmp16no1;
min_value = tmp16no2;
- } else
- {
+ } else {
max_value = tmp16no2;
min_value = tmp16no1;
}
// Magnitude in Q(-6)
- if ((max_value >> 2) > min_value)
- {
+ if ((max_value >> 2) > min_value) {
alpha = kAlpha1;
beta = kBeta1;
- } else if ((max_value >> 1) > min_value)
- {
+ } else if ((max_value >> 1) > min_value) {
alpha = kAlpha2;
beta = kBeta2;
- } else
- {
+ } else {
alpha = kAlpha3;
beta = kBeta3;
}
@@ -252,24 +345,21 @@ static int TimeToFrequencyDomain(AecmCore* aecm,
#else
#ifdef WEBRTC_ARCH_ARM_V7
__asm __volatile(
- "smulbb %[tmp32no1], %[real], %[real]\n\t"
- "smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t"
- :[tmp32no1]"+&r"(tmp32no1),
- [tmp32no2]"=r"(tmp32no2)
- :[real]"r"(freq_signal[i].real),
- [imag]"r"(freq_signal[i].imag)
- );
+ "smulbb %[tmp32no1], %[real], %[real]\n\t"
+ "smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t"
+ : [tmp32no1] "+&r"(tmp32no1), [tmp32no2] "=r"(tmp32no2)
+ : [real] "r"(freq_signal[i].real), [imag] "r"(freq_signal[i].imag));
#else
tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
tmp32no1 = tmp16no1 * tmp16no1;
tmp32no2 = tmp16no2 * tmp16no2;
tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2);
-#endif // WEBRTC_ARCH_ARM_V7
+#endif // WEBRTC_ARCH_ARM_V7
tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2);
freq_signal_abs[i] = (uint16_t)tmp32no1;
-#endif // AECM_WITH_ABS_APPROX
+#endif // AECM_WITH_ABS_APPROX
}
(*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i];
}
@@ -277,7 +367,10 @@ static int TimeToFrequencyDomain(AecmCore* aecm,
return time_signal_scaling;
}
-int WebRtcAecm_ProcessBlock(AecmCore* aecm,
+} // namespace
+
+int RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/8200
+ WebRtcAecm_ProcessBlock(AecmCore* aecm,
const int16_t* farend,
const int16_t* nearendNoisy,
const int16_t* nearendClean,
@@ -300,13 +393,13 @@ int WebRtcAecm_ProcessBlock(AecmCore* aecm,
// 32 byte aligned buffers (with +8 or +16).
// TODO(kma): define fft with ComplexInt16.
- int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
+ int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
int32_t echoEst32_buf[PART_LEN1 + 8];
int32_t dfw_buf[PART_LEN2 + 8];
int32_t efw_buf[PART_LEN2 + 8];
- int16_t* fft = (int16_t*) (((uintptr_t) fft_buf + 31) & ~ 31);
- int32_t* echoEst32 = (int32_t*) (((uintptr_t) echoEst32_buf + 31) & ~ 31);
+ int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31);
+ int32_t* echoEst32 = (int32_t*)(((uintptr_t)echoEst32_buf + 31) & ~31);
ComplexInt16* dfw = (ComplexInt16*)(((uintptr_t)dfw_buf + 31) & ~31);
ComplexInt16* efw = (ComplexInt16*)(((uintptr_t)efw_buf + 31) & ~31);
@@ -332,53 +425,37 @@ int WebRtcAecm_ProcessBlock(AecmCore* aecm,
// (1) another CONV_LEN blocks
// (2) the rest
- if (aecm->startupState < 2)
- {
- aecm->startupState = (aecm->totCount >= CONV_LEN) +
- (aecm->totCount >= CONV_LEN2);
+ if (aecm->startupState < 2) {
+ aecm->startupState =
+ (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2);
}
// END: Determine startup state
// Buffer near and far end signals
memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN);
memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN);
- if (nearendClean != NULL)
- {
- memcpy(aecm->dBufClean + PART_LEN,
- nearendClean,
+ if (nearendClean != NULL) {
+ memcpy(aecm->dBufClean + PART_LEN, nearendClean,
sizeof(int16_t) * PART_LEN);
}
// Transform far end signal from time domain to frequency domain.
- far_q = TimeToFrequencyDomain(aecm,
- aecm->xBuf,
- dfw,
- xfa,
- &xfaSum);
+ far_q = TimeToFrequencyDomain(aecm, aecm->xBuf, dfw, xfa, &xfaSum);
// Transform noisy near end signal from time domain to frequency domain.
- zerosDBufNoisy = TimeToFrequencyDomain(aecm,
- aecm->dBufNoisy,
- dfw,
- dfaNoisy,
- &dfaNoisySum);
+ zerosDBufNoisy =
+ TimeToFrequencyDomain(aecm, aecm->dBufNoisy, dfw, dfaNoisy, &dfaNoisySum);
aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy;
-
- if (nearendClean == NULL)
- {
+ if (nearendClean == NULL) {
ptrDfaClean = dfaNoisy;
aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
dfaCleanSum = dfaNoisySum;
- } else
- {
+ } else {
// Transform clean near end signal from time domain to frequency domain.
- zerosDBufClean = TimeToFrequencyDomain(aecm,
- aecm->dBufClean,
- dfw,
- dfaClean,
+ zerosDBufClean = TimeToFrequencyDomain(aecm, aecm->dBufClean, dfw, dfaClean,
&dfaCleanSum);
aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
aecm->dfaCleanQDomain = (int16_t)zerosDBufClean;
@@ -387,46 +464,34 @@ int WebRtcAecm_ProcessBlock(AecmCore* aecm,
// Get the delay
// Save far-end history and estimate delay
WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q);
- if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend,
- xfa,
- PART_LEN1,
+ if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend, xfa, PART_LEN1,
far_q) == -1) {
return -1;
}
- delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator,
- dfaNoisy,
- PART_LEN1,
- zerosDBufNoisy);
- if (delay == -1)
- {
+ delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, dfaNoisy,
+ PART_LEN1, zerosDBufNoisy);
+ if (delay == -1) {
return -1;
- }
- else if (delay == -2)
- {
+ } else if (delay == -2) {
// If the delay is unknown, we assume zero.
// NOTE: this will have to be adjusted if we ever add lookahead.
delay = 0;
}
- if (aecm->fixedDelay >= 0)
- {
+ if (aecm->fixedDelay >= 0) {
// Use fixed delay
delay = aecm->fixedDelay;
}
// Get aligned far end spectrum
far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay);
- zerosXBuf = (int16_t) far_q;
- if (far_spectrum_ptr == NULL)
- {
+ zerosXBuf = (int16_t)far_q;
+ if (far_spectrum_ptr == NULL) {
return -1;
}
// Calculate log(energy) and update energy threshold levels
- WebRtcAecm_CalcEnergies(aecm,
- far_spectrum_ptr,
- zerosXBuf,
- dfaNoisySum,
+ WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum,
echoEst32);
// Calculate stepsize
@@ -438,63 +503,54 @@ int WebRtcAecm_ProcessBlock(AecmCore* aecm,
// This is the channel estimation algorithm.
// It is base on NLMS but has a variable step length,
// which was calculated above.
- WebRtcAecm_UpdateChannel(aecm,
- far_spectrum_ptr,
- zerosXBuf,
- dfaNoisy,
- mu,
+ WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu,
echoEst32);
supGain = WebRtcAecm_CalcSuppressionGain(aecm);
-
// Calculate Wiener filter hnl[]
- for (i = 0; i < PART_LEN1; i++)
- {
+ for (i = 0; i < PART_LEN1; i++) {
// Far end signal through channel estimate in Q8
// How much can we shift right to preserve resolution
tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
- aecm->echoFilt[i] += (tmp32no1 * 50) >> 8;
+ aecm->echoFilt[i] +=
+ rtc::dchecked_cast<int32_t>((int64_t{tmp32no1} * 50) >> 8);
zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
zeros16 = WebRtcSpl_NormW16(supGain) + 1;
- if (zeros32 + zeros16 > 16)
- {
+ if (zeros32 + zeros16 > 16) {
// Multiplication is safe
// Result in
// Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+
// aecm->xfaQDomainBuf[diff])
- echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
- (uint16_t)supGain);
+ echoEst32Gained =
+ WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i], (uint16_t)supGain);
resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
- } else
- {
+ } else {
tmp16no1 = 17 - zeros32 - zeros16;
- resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 -
- RESOLUTION_SUPGAIN;
+ resolutionDiff =
+ 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
- if (zeros32 > tmp16no1)
- {
+ if (zeros32 > tmp16no1) {
echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
supGain >> tmp16no1);
- } else
- {
+ } else {
// Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain;
}
}
zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]);
- assert(zeros16 >= 0); // |zeros16| is a norm, hence non-negative.
+ RTC_DCHECK_GE(zeros16, 0); // |zeros16| is a norm, hence non-negative.
dfa_clean_q_domain_diff = aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld;
if (zeros16 < dfa_clean_q_domain_diff && aecm->nearFilt[i]) {
- tmp16no1 = aecm->nearFilt[i] << zeros16;
+ tmp16no1 = aecm->nearFilt[i] * (1 << zeros16);
qDomainDiff = zeros16 - dfa_clean_q_domain_diff;
tmp16no2 = ptrDfaClean[i] >> -qDomainDiff;
} else {
tmp16no1 = dfa_clean_q_domain_diff < 0
- ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff
- : aecm->nearFilt[i] << dfa_clean_q_domain_diff;
+ ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff
+ : aecm->nearFilt[i] * (1 << dfa_clean_q_domain_diff);
qDomainDiff = 0;
tmp16no2 = ptrDfaClean[i];
}
@@ -505,130 +561,105 @@ int WebRtcAecm_ProcessBlock(AecmCore* aecm,
if ((tmp16no2) & (-qDomainDiff > zeros16)) {
aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
} else {
- aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 << -qDomainDiff
+ aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 * (1 << -qDomainDiff)
: tmp16no2 >> qDomainDiff;
}
// Wiener filter coefficients, resulting hnl in Q14
- if (echoEst32Gained == 0)
- {
+ if (echoEst32Gained == 0) {
hnl[i] = ONE_Q14;
- } else if (aecm->nearFilt[i] == 0)
- {
+ } else if (aecm->nearFilt[i] == 0) {
hnl[i] = 0;
- } else
- {
+ } else {
// Multiply the suppression gain
// Rounding
echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1);
- tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained,
- (uint16_t)aecm->nearFilt[i]);
+ tmpU32 =
+ WebRtcSpl_DivU32U16(echoEst32Gained, (uint16_t)aecm->nearFilt[i]);
// Current resolution is
// Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN- max(0,17-zeros16- zeros32))
// Make sure we are in Q14
tmp32no1 = (int32_t)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
- if (tmp32no1 > ONE_Q14)
- {
+ if (tmp32no1 > ONE_Q14) {
hnl[i] = 0;
- } else if (tmp32no1 < 0)
- {
+ } else if (tmp32no1 < 0) {
hnl[i] = ONE_Q14;
- } else
- {
+ } else {
// 1-echoEst/dfa
hnl[i] = ONE_Q14 - (int16_t)tmp32no1;
- if (hnl[i] < 0)
- {
+ if (hnl[i] < 0) {
hnl[i] = 0;
}
}
}
- if (hnl[i])
- {
+ if (hnl[i]) {
numPosCoef++;
}
}
// Only in wideband. Prevent the gain in upper band from being larger than
// in lower band.
- if (aecm->mult == 2)
- {
+ if (aecm->mult == 2) {
// TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
// speech distortion in double-talk.
- for (i = 0; i < PART_LEN1; i++)
- {
+ for (i = 0; i < PART_LEN1; i++) {
hnl[i] = (int16_t)((hnl[i] * hnl[i]) >> 14);
}
- for (i = kMinPrefBand; i <= kMaxPrefBand; i++)
- {
+ for (i = kMinPrefBand; i <= kMaxPrefBand; i++) {
avgHnl32 += (int32_t)hnl[i];
}
- assert(kMaxPrefBand - kMinPrefBand + 1 > 0);
+ RTC_DCHECK_GT(kMaxPrefBand - kMinPrefBand + 1, 0);
avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1);
- for (i = kMaxPrefBand; i < PART_LEN1; i++)
- {
- if (hnl[i] > (int16_t)avgHnl32)
- {
+ for (i = kMaxPrefBand; i < PART_LEN1; i++) {
+ if (hnl[i] > (int16_t)avgHnl32) {
hnl[i] = (int16_t)avgHnl32;
}
}
}
// Calculate NLP gain, result is in Q14
- if (aecm->nlpFlag)
- {
- for (i = 0; i < PART_LEN1; i++)
- {
+ if (aecm->nlpFlag) {
+ for (i = 0; i < PART_LEN1; i++) {
// Truncate values close to zero and one.
- if (hnl[i] > NLP_COMP_HIGH)
- {
+ if (hnl[i] > NLP_COMP_HIGH) {
hnl[i] = ONE_Q14;
- } else if (hnl[i] < NLP_COMP_LOW)
- {
+ } else if (hnl[i] < NLP_COMP_LOW) {
hnl[i] = 0;
}
// Remove outliers
- if (numPosCoef < 3)
- {
+ if (numPosCoef < 3) {
nlpGain = 0;
- } else
- {
+ } else {
nlpGain = ONE_Q14;
}
// NLP
- if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14))
- {
+ if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14)) {
hnl[i] = ONE_Q14;
- } else
- {
+ } else {
hnl[i] = (int16_t)((hnl[i] * nlpGain) >> 14);
}
// multiply with Wiener coefficients
- efw[i].real = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
- hnl[i], 14));
- efw[i].imag = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
- hnl[i], 14));
+ efw[i].real = (int16_t)(
+ WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14));
+ efw[i].imag = (int16_t)(
+ WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14));
}
- }
- else
- {
+ } else {
// multiply with Wiener coefficients
- for (i = 0; i < PART_LEN1; i++)
- {
- efw[i].real = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
- hnl[i], 14));
- efw[i].imag = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
- hnl[i], 14));
+ for (i = 0; i < PART_LEN1; i++) {
+ efw[i].real = (int16_t)(
+ WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14));
+ efw[i].imag = (int16_t)(
+ WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14));
}
}
- if (aecm->cngMode == AecmTrue)
- {
+ if (aecm->cngMode == AecmTrue) {
ComfortNoise(aecm, ptrDfaClean, efw, hnl);
}
@@ -637,135 +668,4 @@ int WebRtcAecm_ProcessBlock(AecmCore* aecm,
return 0;
}
-static void ComfortNoise(AecmCore* aecm,
- const uint16_t* dfa,
- ComplexInt16* out,
- const int16_t* lambda) {
- int16_t i;
- int16_t tmp16;
- int32_t tmp32;
-
- int16_t randW16[PART_LEN];
- int16_t uReal[PART_LEN1];
- int16_t uImag[PART_LEN1];
- int32_t outLShift32;
- int16_t noiseRShift16[PART_LEN1];
-
- int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
- int16_t minTrackShift;
-
- assert(shiftFromNearToNoise >= 0);
- assert(shiftFromNearToNoise < 16);
-
- if (aecm->noiseEstCtr < 100)
- {
- // Track the minimum more quickly initially.
- aecm->noiseEstCtr++;
- minTrackShift = 6;
- } else
- {
- minTrackShift = 9;
- }
-
- // Estimate noise power.
- for (i = 0; i < PART_LEN1; i++)
- {
- // Shift to the noise domain.
- tmp32 = (int32_t)dfa[i];
- outLShift32 = tmp32 << shiftFromNearToNoise;
-
- if (outLShift32 < aecm->noiseEst[i])
- {
- // Reset "too low" counter
- aecm->noiseEstTooLowCtr[i] = 0;
- // Track the minimum.
- if (aecm->noiseEst[i] < (1 << minTrackShift))
- {
- // For small values, decrease noiseEst[i] every
- // |kNoiseEstIncCount| block. The regular approach below can not
- // go further down due to truncation.
- aecm->noiseEstTooHighCtr[i]++;
- if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount)
- {
- aecm->noiseEst[i]--;
- aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
- }
- }
- else
- {
- aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32)
- >> minTrackShift);
- }
- } else
- {
- // Reset "too high" counter
- aecm->noiseEstTooHighCtr[i] = 0;
- // Ramp slowly upwards until we hit the minimum again.
- if ((aecm->noiseEst[i] >> 19) > 0)
- {
- // Avoid overflow.
- // Multiplication with 2049 will cause wrap around. Scale
- // down first and then multiply
- aecm->noiseEst[i] >>= 11;
- aecm->noiseEst[i] *= 2049;
- }
- else if ((aecm->noiseEst[i] >> 11) > 0)
- {
- // Large enough for relative increase
- aecm->noiseEst[i] *= 2049;
- aecm->noiseEst[i] >>= 11;
- }
- else
- {
- // Make incremental increases based on size every
- // |kNoiseEstIncCount| block
- aecm->noiseEstTooLowCtr[i]++;
- if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount)
- {
- aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1;
- aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
- }
- }
- }
- }
-
- for (i = 0; i < PART_LEN1; i++)
- {
- tmp32 = aecm->noiseEst[i] >> shiftFromNearToNoise;
- if (tmp32 > 32767)
- {
- tmp32 = 32767;
- aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise;
- }
- noiseRShift16[i] = (int16_t)tmp32;
-
- tmp16 = ONE_Q14 - lambda[i];
- noiseRShift16[i] = (int16_t)((tmp16 * noiseRShift16[i]) >> 14);
- }
-
- // Generate a uniform random array on [0 2^15-1].
- WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
-
- // Generate noise according to estimated energy.
- uReal[0] = 0; // Reject LF noise.
- uImag[0] = 0;
- for (i = 1; i < PART_LEN1; i++)
- {
- // Get a random index for the cos and sin tables over [0 359].
- tmp16 = (int16_t)((359 * randW16[i - 1]) >> 15);
-
- // Tables are in Q13.
- uReal[i] = (int16_t)((noiseRShift16[i] * WebRtcAecm_kCosTable[tmp16]) >>
- 13);
- uImag[i] = (int16_t)((-noiseRShift16[i] * WebRtcAecm_kSinTable[tmp16]) >>
- 13);
- }
- uImag[PART_LEN] = 0;
-
- for (i = 0; i < PART_LEN1; i++)
- {
- out[i].real = WebRtcSpl_AddSatW16(out[i].real, uReal[i]);
- out[i].imag = WebRtcSpl_AddSatW16(out[i].imag, uImag[i]);
- }
-}
-
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core_mips.c b/webrtc/modules/audio_processing/aecm/aecm_core_mips.c
deleted file mode 100644
index 3c2343a..0000000
--- a/webrtc/modules/audio_processing/aecm/aecm_core_mips.c
+++ /dev/null
@@ -1,1566 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
-
-#include <assert.h>
-
-#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
-#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
-
-static const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
- 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
- 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224,
- 6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040,
- 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
- 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553,
- 13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079,
- 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034,
- 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384
-};
-
-static const int16_t kNoiseEstQDomain = 15;
-static const int16_t kNoiseEstIncCount = 5;
-
-static int16_t coefTable[] = {
- 0, 4, 256, 260, 128, 132, 384, 388,
- 64, 68, 320, 324, 192, 196, 448, 452,
- 32, 36, 288, 292, 160, 164, 416, 420,
- 96, 100, 352, 356, 224, 228, 480, 484,
- 16, 20, 272, 276, 144, 148, 400, 404,
- 80, 84, 336, 340, 208, 212, 464, 468,
- 48, 52, 304, 308, 176, 180, 432, 436,
- 112, 116, 368, 372, 240, 244, 496, 500,
- 8, 12, 264, 268, 136, 140, 392, 396,
- 72, 76, 328, 332, 200, 204, 456, 460,
- 40, 44, 296, 300, 168, 172, 424, 428,
- 104, 108, 360, 364, 232, 236, 488, 492,
- 24, 28, 280, 284, 152, 156, 408, 412,
- 88, 92, 344, 348, 216, 220, 472, 476,
- 56, 60, 312, 316, 184, 188, 440, 444,
- 120, 124, 376, 380, 248, 252, 504, 508
-};
-
-static int16_t coefTable_ifft[] = {
- 0, 512, 256, 508, 128, 252, 384, 380,
- 64, 124, 320, 444, 192, 188, 448, 316,
- 32, 60, 288, 476, 160, 220, 416, 348,
- 96, 92, 352, 412, 224, 156, 480, 284,
- 16, 28, 272, 492, 144, 236, 400, 364,
- 80, 108, 336, 428, 208, 172, 464, 300,
- 48, 44, 304, 460, 176, 204, 432, 332,
- 112, 76, 368, 396, 240, 140, 496, 268,
- 8, 12, 264, 500, 136, 244, 392, 372,
- 72, 116, 328, 436, 200, 180, 456, 308,
- 40, 52, 296, 468, 168, 212, 424, 340,
- 104, 84, 360, 404, 232, 148, 488, 276,
- 24, 20, 280, 484, 152, 228, 408, 356,
- 88, 100, 344, 420, 216, 164, 472, 292,
- 56, 36, 312, 452, 184, 196, 440, 324,
- 120, 68, 376, 388, 248, 132, 504, 260
-};
-
-static void ComfortNoise(AecmCore* aecm,
- const uint16_t* dfa,
- ComplexInt16* out,
- const int16_t* lambda);
-
-static void WindowAndFFT(AecmCore* aecm,
- int16_t* fft,
- const int16_t* time_signal,
- ComplexInt16* freq_signal,
- int time_signal_scaling) {
- int i, j;
- int32_t tmp1, tmp2, tmp3, tmp4;
- int16_t* pfrfi;
- ComplexInt16* pfreq_signal;
- int16_t f_coef, s_coef;
- int32_t load_ptr, store_ptr1, store_ptr2, shift, shift1;
- int32_t hann, hann1, coefs;
-
- memset(fft, 0, sizeof(int16_t) * PART_LEN4);
-
- // FFT of signal
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[shift], %[time_signal_scaling], -14 \n\t"
- "addiu %[i], $zero, 64 \n\t"
- "addiu %[load_ptr], %[time_signal], 0 \n\t"
- "addiu %[hann], %[hanning], 0 \n\t"
- "addiu %[hann1], %[hanning], 128 \n\t"
- "addiu %[coefs], %[coefTable], 0 \n\t"
- "bltz %[shift], 2f \n\t"
- " negu %[shift1], %[shift] \n\t"
- "1: \n\t"
- "lh %[tmp1], 0(%[load_ptr]) \n\t"
- "lh %[tmp2], 0(%[hann]) \n\t"
- "lh %[tmp3], 128(%[load_ptr]) \n\t"
- "lh %[tmp4], 0(%[hann1]) \n\t"
- "addiu %[i], %[i], -1 \n\t"
- "mul %[tmp1], %[tmp1], %[tmp2] \n\t"
- "mul %[tmp3], %[tmp3], %[tmp4] \n\t"
- "lh %[f_coef], 0(%[coefs]) \n\t"
- "lh %[s_coef], 2(%[coefs]) \n\t"
- "addiu %[load_ptr], %[load_ptr], 2 \n\t"
- "addiu %[hann], %[hann], 2 \n\t"
- "addiu %[hann1], %[hann1], -2 \n\t"
- "addu %[store_ptr1], %[fft], %[f_coef] \n\t"
- "addu %[store_ptr2], %[fft], %[s_coef] \n\t"
- "sllv %[tmp1], %[tmp1], %[shift] \n\t"
- "sllv %[tmp3], %[tmp3], %[shift] \n\t"
- "sh %[tmp1], 0(%[store_ptr1]) \n\t"
- "sh %[tmp3], 0(%[store_ptr2]) \n\t"
- "bgtz %[i], 1b \n\t"
- " addiu %[coefs], %[coefs], 4 \n\t"
- "b 3f \n\t"
- " nop \n\t"
- "2: \n\t"
- "lh %[tmp1], 0(%[load_ptr]) \n\t"
- "lh %[tmp2], 0(%[hann]) \n\t"
- "lh %[tmp3], 128(%[load_ptr]) \n\t"
- "lh %[tmp4], 0(%[hann1]) \n\t"
- "addiu %[i], %[i], -1 \n\t"
- "mul %[tmp1], %[tmp1], %[tmp2] \n\t"
- "mul %[tmp3], %[tmp3], %[tmp4] \n\t"
- "lh %[f_coef], 0(%[coefs]) \n\t"
- "lh %[s_coef], 2(%[coefs]) \n\t"
- "addiu %[load_ptr], %[load_ptr], 2 \n\t"
- "addiu %[hann], %[hann], 2 \n\t"
- "addiu %[hann1], %[hann1], -2 \n\t"
- "addu %[store_ptr1], %[fft], %[f_coef] \n\t"
- "addu %[store_ptr2], %[fft], %[s_coef] \n\t"
- "srav %[tmp1], %[tmp1], %[shift1] \n\t"
- "srav %[tmp3], %[tmp3], %[shift1] \n\t"
- "sh %[tmp1], 0(%[store_ptr1]) \n\t"
- "sh %[tmp3], 0(%[store_ptr2]) \n\t"
- "bgtz %[i], 2b \n\t"
- " addiu %[coefs], %[coefs], 4 \n\t"
- "3: \n\t"
- ".set pop \n\t"
- : [load_ptr] "=&r" (load_ptr), [shift] "=&r" (shift), [hann] "=&r" (hann),
- [hann1] "=&r" (hann1), [shift1] "=&r" (shift1), [coefs] "=&r" (coefs),
- [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
- [tmp4] "=&r" (tmp4), [i] "=&r" (i), [f_coef] "=&r" (f_coef),
- [s_coef] "=&r" (s_coef), [store_ptr1] "=&r" (store_ptr1),
- [store_ptr2] "=&r" (store_ptr2)
- : [time_signal] "r" (time_signal), [coefTable] "r" (coefTable),
- [time_signal_scaling] "r" (time_signal_scaling),
- [hanning] "r" (WebRtcAecm_kSqrtHanning), [fft] "r" (fft)
- : "memory", "hi", "lo"
- );
-
- WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
- pfrfi = fft;
- pfreq_signal = freq_signal;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[j], $zero, 128 \n\t"
- "1: \n\t"
- "lh %[tmp1], 0(%[pfrfi]) \n\t"
- "lh %[tmp2], 2(%[pfrfi]) \n\t"
- "lh %[tmp3], 4(%[pfrfi]) \n\t"
- "lh %[tmp4], 6(%[pfrfi]) \n\t"
- "subu %[tmp2], $zero, %[tmp2] \n\t"
- "sh %[tmp1], 0(%[pfreq_signal]) \n\t"
- "sh %[tmp2], 2(%[pfreq_signal]) \n\t"
- "subu %[tmp4], $zero, %[tmp4] \n\t"
- "sh %[tmp3], 4(%[pfreq_signal]) \n\t"
- "sh %[tmp4], 6(%[pfreq_signal]) \n\t"
- "lh %[tmp1], 8(%[pfrfi]) \n\t"
- "lh %[tmp2], 10(%[pfrfi]) \n\t"
- "lh %[tmp3], 12(%[pfrfi]) \n\t"
- "lh %[tmp4], 14(%[pfrfi]) \n\t"
- "addiu %[j], %[j], -8 \n\t"
- "subu %[tmp2], $zero, %[tmp2] \n\t"
- "sh %[tmp1], 8(%[pfreq_signal]) \n\t"
- "sh %[tmp2], 10(%[pfreq_signal]) \n\t"
- "subu %[tmp4], $zero, %[tmp4] \n\t"
- "sh %[tmp3], 12(%[pfreq_signal]) \n\t"
- "sh %[tmp4], 14(%[pfreq_signal]) \n\t"
- "addiu %[pfreq_signal], %[pfreq_signal], 16 \n\t"
- "bgtz %[j], 1b \n\t"
- " addiu %[pfrfi], %[pfrfi], 16 \n\t"
- ".set pop \n\t"
- : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
- [j] "=&r" (j), [pfrfi] "+r" (pfrfi), [pfreq_signal] "+r" (pfreq_signal),
- [tmp4] "=&r" (tmp4)
- :
- : "memory"
- );
-}
-
-static void InverseFFTAndWindow(AecmCore* aecm,
- int16_t* fft,
- ComplexInt16* efw,
- int16_t* output,
- const int16_t* nearendClean) {
- int i, outCFFT;
- int32_t tmp1, tmp2, tmp3, tmp4, tmp_re, tmp_im;
- int16_t* pcoefTable_ifft = coefTable_ifft;
- int16_t* pfft = fft;
- int16_t* ppfft = fft;
- ComplexInt16* pefw = efw;
- int32_t out_aecm;
- int16_t* paecm_buf = aecm->outBuf;
- const int16_t* p_kSqrtHanning = WebRtcAecm_kSqrtHanning;
- const int16_t* pp_kSqrtHanning = &WebRtcAecm_kSqrtHanning[PART_LEN];
- int16_t* output1 = output;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[i], $zero, 64 \n\t"
- "1: \n\t"
- "lh %[tmp1], 0(%[pcoefTable_ifft]) \n\t"
- "lh %[tmp2], 2(%[pcoefTable_ifft]) \n\t"
- "lh %[tmp_re], 0(%[pefw]) \n\t"
- "lh %[tmp_im], 2(%[pefw]) \n\t"
- "addu %[pfft], %[fft], %[tmp2] \n\t"
- "sh %[tmp_re], 0(%[pfft]) \n\t"
- "sh %[tmp_im], 2(%[pfft]) \n\t"
- "addu %[pfft], %[fft], %[tmp1] \n\t"
- "sh %[tmp_re], 0(%[pfft]) \n\t"
- "subu %[tmp_im], $zero, %[tmp_im] \n\t"
- "sh %[tmp_im], 2(%[pfft]) \n\t"
- "lh %[tmp1], 4(%[pcoefTable_ifft]) \n\t"
- "lh %[tmp2], 6(%[pcoefTable_ifft]) \n\t"
- "lh %[tmp_re], 4(%[pefw]) \n\t"
- "lh %[tmp_im], 6(%[pefw]) \n\t"
- "addu %[pfft], %[fft], %[tmp2] \n\t"
- "sh %[tmp_re], 0(%[pfft]) \n\t"
- "sh %[tmp_im], 2(%[pfft]) \n\t"
- "addu %[pfft], %[fft], %[tmp1] \n\t"
- "sh %[tmp_re], 0(%[pfft]) \n\t"
- "subu %[tmp_im], $zero, %[tmp_im] \n\t"
- "sh %[tmp_im], 2(%[pfft]) \n\t"
- "lh %[tmp1], 8(%[pcoefTable_ifft]) \n\t"
- "lh %[tmp2], 10(%[pcoefTable_ifft]) \n\t"
- "lh %[tmp_re], 8(%[pefw]) \n\t"
- "lh %[tmp_im], 10(%[pefw]) \n\t"
- "addu %[pfft], %[fft], %[tmp2] \n\t"
- "sh %[tmp_re], 0(%[pfft]) \n\t"
- "sh %[tmp_im], 2(%[pfft]) \n\t"
- "addu %[pfft], %[fft], %[tmp1] \n\t"
- "sh %[tmp_re], 0(%[pfft]) \n\t"
- "subu %[tmp_im], $zero, %[tmp_im] \n\t"
- "sh %[tmp_im], 2(%[pfft]) \n\t"
- "lh %[tmp1], 12(%[pcoefTable_ifft]) \n\t"
- "lh %[tmp2], 14(%[pcoefTable_ifft]) \n\t"
- "lh %[tmp_re], 12(%[pefw]) \n\t"
- "lh %[tmp_im], 14(%[pefw]) \n\t"
- "addu %[pfft], %[fft], %[tmp2] \n\t"
- "sh %[tmp_re], 0(%[pfft]) \n\t"
- "sh %[tmp_im], 2(%[pfft]) \n\t"
- "addu %[pfft], %[fft], %[tmp1] \n\t"
- "sh %[tmp_re], 0(%[pfft]) \n\t"
- "subu %[tmp_im], $zero, %[tmp_im] \n\t"
- "sh %[tmp_im], 2(%[pfft]) \n\t"
- "addiu %[pcoefTable_ifft], %[pcoefTable_ifft], 16 \n\t"
- "addiu %[i], %[i], -4 \n\t"
- "bgtz %[i], 1b \n\t"
- " addiu %[pefw], %[pefw], 16 \n\t"
- ".set pop \n\t"
- : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [pfft] "+r" (pfft),
- [i] "=&r" (i), [tmp_re] "=&r" (tmp_re), [tmp_im] "=&r" (tmp_im),
- [pefw] "+r" (pefw), [pcoefTable_ifft] "+r" (pcoefTable_ifft),
- [fft] "+r" (fft)
- :
- : "memory"
- );
-
- fft[2] = efw[PART_LEN].real;
- fft[3] = -efw[PART_LEN].imag;
-
- outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1);
- pfft = fft;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[i], $zero, 128 \n\t"
- "1: \n\t"
- "lh %[tmp1], 0(%[ppfft]) \n\t"
- "lh %[tmp2], 4(%[ppfft]) \n\t"
- "lh %[tmp3], 8(%[ppfft]) \n\t"
- "lh %[tmp4], 12(%[ppfft]) \n\t"
- "addiu %[i], %[i], -4 \n\t"
- "sh %[tmp1], 0(%[pfft]) \n\t"
- "sh %[tmp2], 2(%[pfft]) \n\t"
- "sh %[tmp3], 4(%[pfft]) \n\t"
- "sh %[tmp4], 6(%[pfft]) \n\t"
- "addiu %[ppfft], %[ppfft], 16 \n\t"
- "bgtz %[i], 1b \n\t"
- " addiu %[pfft], %[pfft], 8 \n\t"
- ".set pop \n\t"
- : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [pfft] "+r" (pfft),
- [i] "=&r" (i), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4),
- [ppfft] "+r" (ppfft)
- :
- : "memory"
- );
-
- pfft = fft;
- out_aecm = (int32_t)(outCFFT - aecm->dfaCleanQDomain);
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "addiu %[i], $zero, 64 \n\t"
- "11: \n\t"
- "lh %[tmp1], 0(%[pfft]) \n\t"
- "lh %[tmp2], 0(%[p_kSqrtHanning]) \n\t"
- "addiu %[i], %[i], -2 \n\t"
- "mul %[tmp1], %[tmp1], %[tmp2] \n\t"
- "lh %[tmp3], 2(%[pfft]) \n\t"
- "lh %[tmp4], 2(%[p_kSqrtHanning]) \n\t"
- "mul %[tmp3], %[tmp3], %[tmp4] \n\t"
- "addiu %[tmp1], %[tmp1], 8192 \n\t"
- "sra %[tmp1], %[tmp1], 14 \n\t"
- "addiu %[tmp3], %[tmp3], 8192 \n\t"
- "sra %[tmp3], %[tmp3], 14 \n\t"
- "bgez %[out_aecm], 1f \n\t"
- " negu %[tmp2], %[out_aecm] \n\t"
- "srav %[tmp1], %[tmp1], %[tmp2] \n\t"
- "b 2f \n\t"
- " srav %[tmp3], %[tmp3], %[tmp2] \n\t"
- "1: \n\t"
- "sllv %[tmp1], %[tmp1], %[out_aecm] \n\t"
- "sllv %[tmp3], %[tmp3], %[out_aecm] \n\t"
- "2: \n\t"
- "lh %[tmp4], 0(%[paecm_buf]) \n\t"
- "lh %[tmp2], 2(%[paecm_buf]) \n\t"
- "addu %[tmp3], %[tmp3], %[tmp2] \n\t"
- "addu %[tmp1], %[tmp1], %[tmp4] \n\t"
-#if defined(MIPS_DSP_R1_LE)
- "shll_s.w %[tmp1], %[tmp1], 16 \n\t"
- "sra %[tmp1], %[tmp1], 16 \n\t"
- "shll_s.w %[tmp3], %[tmp3], 16 \n\t"
- "sra %[tmp3], %[tmp3], 16 \n\t"
-#else // #if defined(MIPS_DSP_R1_LE)
- "sra %[tmp4], %[tmp1], 31 \n\t"
- "sra %[tmp2], %[tmp1], 15 \n\t"
- "beq %[tmp4], %[tmp2], 3f \n\t"
- " ori %[tmp2], $zero, 0x7fff \n\t"
- "xor %[tmp1], %[tmp2], %[tmp4] \n\t"
- "3: \n\t"
- "sra %[tmp2], %[tmp3], 31 \n\t"
- "sra %[tmp4], %[tmp3], 15 \n\t"
- "beq %[tmp2], %[tmp4], 4f \n\t"
- " ori %[tmp4], $zero, 0x7fff \n\t"
- "xor %[tmp3], %[tmp4], %[tmp2] \n\t"
- "4: \n\t"
-#endif // #if defined(MIPS_DSP_R1_LE)
- "sh %[tmp1], 0(%[pfft]) \n\t"
- "sh %[tmp1], 0(%[output1]) \n\t"
- "sh %[tmp3], 2(%[pfft]) \n\t"
- "sh %[tmp3], 2(%[output1]) \n\t"
- "lh %[tmp1], 128(%[pfft]) \n\t"
- "lh %[tmp2], 0(%[pp_kSqrtHanning]) \n\t"
- "mul %[tmp1], %[tmp1], %[tmp2] \n\t"
- "lh %[tmp3], 130(%[pfft]) \n\t"
- "lh %[tmp4], -2(%[pp_kSqrtHanning]) \n\t"
- "mul %[tmp3], %[tmp3], %[tmp4] \n\t"
- "sra %[tmp1], %[tmp1], 14 \n\t"
- "sra %[tmp3], %[tmp3], 14 \n\t"
- "bgez %[out_aecm], 5f \n\t"
- " negu %[tmp2], %[out_aecm] \n\t"
- "srav %[tmp3], %[tmp3], %[tmp2] \n\t"
- "b 6f \n\t"
- " srav %[tmp1], %[tmp1], %[tmp2] \n\t"
- "5: \n\t"
- "sllv %[tmp1], %[tmp1], %[out_aecm] \n\t"
- "sllv %[tmp3], %[tmp3], %[out_aecm] \n\t"
- "6: \n\t"
-#if defined(MIPS_DSP_R1_LE)
- "shll_s.w %[tmp1], %[tmp1], 16 \n\t"
- "sra %[tmp1], %[tmp1], 16 \n\t"
- "shll_s.w %[tmp3], %[tmp3], 16 \n\t"
- "sra %[tmp3], %[tmp3], 16 \n\t"
-#else // #if defined(MIPS_DSP_R1_LE)
- "sra %[tmp4], %[tmp1], 31 \n\t"
- "sra %[tmp2], %[tmp1], 15 \n\t"
- "beq %[tmp4], %[tmp2], 7f \n\t"
- " ori %[tmp2], $zero, 0x7fff \n\t"
- "xor %[tmp1], %[tmp2], %[tmp4] \n\t"
- "7: \n\t"
- "sra %[tmp2], %[tmp3], 31 \n\t"
- "sra %[tmp4], %[tmp3], 15 \n\t"
- "beq %[tmp2], %[tmp4], 8f \n\t"
- " ori %[tmp4], $zero, 0x7fff \n\t"
- "xor %[tmp3], %[tmp4], %[tmp2] \n\t"
- "8: \n\t"
-#endif // #if defined(MIPS_DSP_R1_LE)
- "sh %[tmp1], 0(%[paecm_buf]) \n\t"
- "sh %[tmp3], 2(%[paecm_buf]) \n\t"
- "addiu %[output1], %[output1], 4 \n\t"
- "addiu %[paecm_buf], %[paecm_buf], 4 \n\t"
- "addiu %[pfft], %[pfft], 4 \n\t"
- "addiu %[p_kSqrtHanning], %[p_kSqrtHanning], 4 \n\t"
- "bgtz %[i], 11b \n\t"
- " addiu %[pp_kSqrtHanning], %[pp_kSqrtHanning], -4 \n\t"
- ".set pop \n\t"
- : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [pfft] "+r" (pfft),
- [output1] "+r" (output1), [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4),
- [paecm_buf] "+r" (paecm_buf), [i] "=&r" (i),
- [pp_kSqrtHanning] "+r" (pp_kSqrtHanning),
- [p_kSqrtHanning] "+r" (p_kSqrtHanning)
- : [out_aecm] "r" (out_aecm),
- [WebRtcAecm_kSqrtHanning] "r" (WebRtcAecm_kSqrtHanning)
- : "hi", "lo","memory"
- );
-
- // Copy the current block to the old position
- // (aecm->outBuf is shifted elsewhere)
- memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN);
- memcpy(aecm->dBufNoisy,
- aecm->dBufNoisy + PART_LEN,
- sizeof(int16_t) * PART_LEN);
- if (nearendClean != NULL) {
- memcpy(aecm->dBufClean,
- aecm->dBufClean + PART_LEN,
- sizeof(int16_t) * PART_LEN);
- }
-}
-
-void WebRtcAecm_CalcLinearEnergies_mips(AecmCore* aecm,
- const uint16_t* far_spectrum,
- int32_t* echo_est,
- uint32_t* far_energy,
- uint32_t* echo_energy_adapt,
- uint32_t* echo_energy_stored) {
- int i;
- uint32_t par1 = (*far_energy);
- uint32_t par2 = (*echo_energy_adapt);
- uint32_t par3 = (*echo_energy_stored);
- int16_t* ch_stored_p = &(aecm->channelStored[0]);
- int16_t* ch_adapt_p = &(aecm->channelAdapt16[0]);
- uint16_t* spectrum_p = (uint16_t*)(&(far_spectrum[0]));
- int32_t* echo_p = &(echo_est[0]);
- int32_t temp0, stored0, echo0, adept0, spectrum0;
- int32_t stored1, adept1, spectrum1, echo1, temp1;
-
- // Get energy for the delayed far end signal and estimated
- // echo using both stored and adapted channels.
- for (i = 0; i < PART_LEN; i+= 4) {
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "lh %[stored0], 0(%[ch_stored_p]) \n\t"
- "lhu %[adept0], 0(%[ch_adapt_p]) \n\t"
- "lhu %[spectrum0], 0(%[spectrum_p]) \n\t"
- "lh %[stored1], 2(%[ch_stored_p]) \n\t"
- "lhu %[adept1], 2(%[ch_adapt_p]) \n\t"
- "lhu %[spectrum1], 2(%[spectrum_p]) \n\t"
- "mul %[echo0], %[stored0], %[spectrum0] \n\t"
- "mul %[temp0], %[adept0], %[spectrum0] \n\t"
- "mul %[echo1], %[stored1], %[spectrum1] \n\t"
- "mul %[temp1], %[adept1], %[spectrum1] \n\t"
- "addu %[par1], %[par1], %[spectrum0] \n\t"
- "addu %[par1], %[par1], %[spectrum1] \n\t"
- "addiu %[echo_p], %[echo_p], 16 \n\t"
- "addu %[par3], %[par3], %[echo0] \n\t"
- "addu %[par2], %[par2], %[temp0] \n\t"
- "addu %[par3], %[par3], %[echo1] \n\t"
- "addu %[par2], %[par2], %[temp1] \n\t"
- "usw %[echo0], -16(%[echo_p]) \n\t"
- "usw %[echo1], -12(%[echo_p]) \n\t"
- "lh %[stored0], 4(%[ch_stored_p]) \n\t"
- "lhu %[adept0], 4(%[ch_adapt_p]) \n\t"
- "lhu %[spectrum0], 4(%[spectrum_p]) \n\t"
- "lh %[stored1], 6(%[ch_stored_p]) \n\t"
- "lhu %[adept1], 6(%[ch_adapt_p]) \n\t"
- "lhu %[spectrum1], 6(%[spectrum_p]) \n\t"
- "mul %[echo0], %[stored0], %[spectrum0] \n\t"
- "mul %[temp0], %[adept0], %[spectrum0] \n\t"
- "mul %[echo1], %[stored1], %[spectrum1] \n\t"
- "mul %[temp1], %[adept1], %[spectrum1] \n\t"
- "addu %[par1], %[par1], %[spectrum0] \n\t"
- "addu %[par1], %[par1], %[spectrum1] \n\t"
- "addiu %[ch_stored_p], %[ch_stored_p], 8 \n\t"
- "addiu %[ch_adapt_p], %[ch_adapt_p], 8 \n\t"
- "addiu %[spectrum_p], %[spectrum_p], 8 \n\t"
- "addu %[par3], %[par3], %[echo0] \n\t"
- "addu %[par2], %[par2], %[temp0] \n\t"
- "addu %[par3], %[par3], %[echo1] \n\t"
- "addu %[par2], %[par2], %[temp1] \n\t"
- "usw %[echo0], -8(%[echo_p]) \n\t"
- "usw %[echo1], -4(%[echo_p]) \n\t"
- ".set pop \n\t"
- : [temp0] "=&r" (temp0), [stored0] "=&r" (stored0),
- [adept0] "=&r" (adept0), [spectrum0] "=&r" (spectrum0),
- [echo0] "=&r" (echo0), [echo_p] "+r" (echo_p), [par3] "+r" (par3),
- [par1] "+r" (par1), [par2] "+r" (par2), [stored1] "=&r" (stored1),
- [adept1] "=&r" (adept1), [echo1] "=&r" (echo1),
- [spectrum1] "=&r" (spectrum1), [temp1] "=&r" (temp1),
- [ch_stored_p] "+r" (ch_stored_p), [ch_adapt_p] "+r" (ch_adapt_p),
- [spectrum_p] "+r" (spectrum_p)
- :
- : "hi", "lo", "memory"
- );
- }
-
- echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN],
- far_spectrum[PART_LEN]);
- par1 += (uint32_t)(far_spectrum[PART_LEN]);
- par2 += aecm->channelAdapt16[PART_LEN] * far_spectrum[PART_LEN];
- par3 += (uint32_t)echo_est[PART_LEN];
-
- (*far_energy) = par1;
- (*echo_energy_adapt) = par2;
- (*echo_energy_stored) = par3;
-}
-
-#if defined(MIPS_DSP_R1_LE)
-void WebRtcAecm_StoreAdaptiveChannel_mips(AecmCore* aecm,
- const uint16_t* far_spectrum,
- int32_t* echo_est) {
- int i;
- int16_t* temp1;
- uint16_t* temp8;
- int32_t temp0, temp2, temp3, temp4, temp5, temp6;
- int32_t* temp7 = &(echo_est[0]);
- temp1 = &(aecm->channelStored[0]);
- temp8 = (uint16_t*)(&far_spectrum[0]);
-
- // During startup we store the channel every block.
- memcpy(aecm->channelStored, aecm->channelAdapt16,
- sizeof(int16_t) * PART_LEN1);
- // Recalculate echo estimate
- for (i = 0; i < PART_LEN; i += 4) {
- __asm __volatile (
- "ulw %[temp0], 0(%[temp8]) \n\t"
- "ulw %[temp2], 0(%[temp1]) \n\t"
- "ulw %[temp4], 4(%[temp8]) \n\t"
- "ulw %[temp5], 4(%[temp1]) \n\t"
- "muleq_s.w.phl %[temp3], %[temp2], %[temp0] \n\t"
- "muleq_s.w.phr %[temp0], %[temp2], %[temp0] \n\t"
- "muleq_s.w.phl %[temp6], %[temp5], %[temp4] \n\t"
- "muleq_s.w.phr %[temp4], %[temp5], %[temp4] \n\t"
- "addiu %[temp7], %[temp7], 16 \n\t"
- "addiu %[temp1], %[temp1], 8 \n\t"
- "addiu %[temp8], %[temp8], 8 \n\t"
- "sra %[temp3], %[temp3], 1 \n\t"
- "sra %[temp0], %[temp0], 1 \n\t"
- "sra %[temp6], %[temp6], 1 \n\t"
- "sra %[temp4], %[temp4], 1 \n\t"
- "usw %[temp3], -12(%[temp7]) \n\t"
- "usw %[temp0], -16(%[temp7]) \n\t"
- "usw %[temp6], -4(%[temp7]) \n\t"
- "usw %[temp4], -8(%[temp7]) \n\t"
- : [temp0] "=&r" (temp0), [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
- [temp4] "=&r" (temp4), [temp5] "=&r" (temp5), [temp6] "=&r" (temp6),
- [temp1] "+r" (temp1), [temp8] "+r" (temp8), [temp7] "+r" (temp7)
- :
- : "hi", "lo", "memory"
- );
- }
- echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
- far_spectrum[i]);
-}
-
-void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm) {
- int i;
- int32_t* temp3;
- int16_t* temp0;
- int32_t temp1, temp2, temp4, temp5;
-
- temp0 = &(aecm->channelStored[0]);
- temp3 = &(aecm->channelAdapt32[0]);
-
- // The stored channel has a significantly lower MSE than the adaptive one for
- // two consecutive calculations. Reset the adaptive channel.
- memcpy(aecm->channelAdapt16,
- aecm->channelStored,
- sizeof(int16_t) * PART_LEN1);
-
- // Restore the W32 channel
- for (i = 0; i < PART_LEN; i += 4) {
- __asm __volatile (
- "ulw %[temp1], 0(%[temp0]) \n\t"
- "ulw %[temp4], 4(%[temp0]) \n\t"
- "preceq.w.phl %[temp2], %[temp1] \n\t"
- "preceq.w.phr %[temp1], %[temp1] \n\t"
- "preceq.w.phl %[temp5], %[temp4] \n\t"
- "preceq.w.phr %[temp4], %[temp4] \n\t"
- "addiu %[temp0], %[temp0], 8 \n\t"
- "usw %[temp2], 4(%[temp3]) \n\t"
- "usw %[temp1], 0(%[temp3]) \n\t"
- "usw %[temp5], 12(%[temp3]) \n\t"
- "usw %[temp4], 8(%[temp3]) \n\t"
- "addiu %[temp3], %[temp3], 16 \n\t"
- : [temp1] "=&r" (temp1), [temp2] "=&r" (temp2),
- [temp4] "=&r" (temp4), [temp5] "=&r" (temp5),
- [temp3] "+r" (temp3), [temp0] "+r" (temp0)
- :
- : "memory"
- );
- }
-
- aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
-}
-#endif // #if defined(MIPS_DSP_R1_LE)
-
-// Transforms a time domain signal into the frequency domain, outputting the
-// complex valued signal, absolute value and sum of absolute values.
-//
-// time_signal [in] Pointer to time domain signal
-// freq_signal_real [out] Pointer to real part of frequency domain array
-// freq_signal_imag [out] Pointer to imaginary part of frequency domain
-// array
-// freq_signal_abs [out] Pointer to absolute value of frequency domain
-// array
-// freq_signal_sum_abs [out] Pointer to the sum of all absolute values in
-// the frequency domain array
-// return value The Q-domain of current frequency values
-//
-static int TimeToFrequencyDomain(AecmCore* aecm,
- const int16_t* time_signal,
- ComplexInt16* freq_signal,
- uint16_t* freq_signal_abs,
- uint32_t* freq_signal_sum_abs) {
- int i = 0;
- int time_signal_scaling = 0;
-
- // In fft_buf, +16 for 32-byte alignment.
- int16_t fft_buf[PART_LEN4 + 16];
- int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31);
-
- int16_t tmp16no1;
-#if !defined(MIPS_DSP_R2_LE)
- int32_t tmp32no1;
- int32_t tmp32no2;
- int16_t tmp16no2;
-#else
- int32_t tmp32no10, tmp32no11, tmp32no12, tmp32no13;
- int32_t tmp32no20, tmp32no21, tmp32no22, tmp32no23;
- int16_t* freqp;
- uint16_t* freqabsp;
- uint32_t freqt0, freqt1, freqt2, freqt3;
- uint32_t freqs;
-#endif
-
-#ifdef AECM_DYNAMIC_Q
- tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2);
- time_signal_scaling = WebRtcSpl_NormW16(tmp16no1);
-#endif
-
- WindowAndFFT(aecm, fft, time_signal, freq_signal, time_signal_scaling);
-
- // Extract imaginary and real part,
- // calculate the magnitude for all frequency bins
- freq_signal[0].imag = 0;
- freq_signal[PART_LEN].imag = 0;
- freq_signal[PART_LEN].real = fft[PART_LEN2];
- freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real);
- freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16(
- freq_signal[PART_LEN].real);
- (*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) +
- (uint32_t)(freq_signal_abs[PART_LEN]);
-
-#if !defined(MIPS_DSP_R2_LE)
- for (i = 1; i < PART_LEN; i++) {
- if (freq_signal[i].real == 0)
- {
- freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(
- freq_signal[i].imag);
- }
- else if (freq_signal[i].imag == 0)
- {
- freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(
- freq_signal[i].real);
- }
- else
- {
- // Approximation for magnitude of complex fft output
- // magn = sqrt(real^2 + imag^2)
- // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
- //
- // The parameters alpha and beta are stored in Q15
- tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
- tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
- tmp32no1 = tmp16no1 * tmp16no1;
- tmp32no2 = tmp16no2 * tmp16no2;
- tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2);
- tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2);
-
- freq_signal_abs[i] = (uint16_t)tmp32no1;
- }
- (*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i];
- }
-#else // #if !defined(MIPS_DSP_R2_LE)
- freqs = (uint32_t)(freq_signal_abs[0]) +
- (uint32_t)(freq_signal_abs[PART_LEN]);
- freqp = &(freq_signal[1].real);
-
- __asm __volatile (
- "lw %[freqt0], 0(%[freqp]) \n\t"
- "lw %[freqt1], 4(%[freqp]) \n\t"
- "lw %[freqt2], 8(%[freqp]) \n\t"
- "mult $ac0, $zero, $zero \n\t"
- "mult $ac1, $zero, $zero \n\t"
- "mult $ac2, $zero, $zero \n\t"
- "dpaq_s.w.ph $ac0, %[freqt0], %[freqt0] \n\t"
- "dpaq_s.w.ph $ac1, %[freqt1], %[freqt1] \n\t"
- "dpaq_s.w.ph $ac2, %[freqt2], %[freqt2] \n\t"
- "addiu %[freqp], %[freqp], 12 \n\t"
- "extr.w %[tmp32no20], $ac0, 1 \n\t"
- "extr.w %[tmp32no21], $ac1, 1 \n\t"
- "extr.w %[tmp32no22], $ac2, 1 \n\t"
- : [freqt0] "=&r" (freqt0), [freqt1] "=&r" (freqt1),
- [freqt2] "=&r" (freqt2), [freqp] "+r" (freqp),
- [tmp32no20] "=r" (tmp32no20), [tmp32no21] "=r" (tmp32no21),
- [tmp32no22] "=r" (tmp32no22)
- :
- : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo"
- );
-
- tmp32no10 = WebRtcSpl_SqrtFloor(tmp32no20);
- tmp32no11 = WebRtcSpl_SqrtFloor(tmp32no21);
- tmp32no12 = WebRtcSpl_SqrtFloor(tmp32no22);
- freq_signal_abs[1] = (uint16_t)tmp32no10;
- freq_signal_abs[2] = (uint16_t)tmp32no11;
- freq_signal_abs[3] = (uint16_t)tmp32no12;
- freqs += (uint32_t)tmp32no10;
- freqs += (uint32_t)tmp32no11;
- freqs += (uint32_t)tmp32no12;
- freqabsp = &(freq_signal_abs[4]);
- for (i = 4; i < PART_LEN; i+=4)
- {
- __asm __volatile (
- "ulw %[freqt0], 0(%[freqp]) \n\t"
- "ulw %[freqt1], 4(%[freqp]) \n\t"
- "ulw %[freqt2], 8(%[freqp]) \n\t"
- "ulw %[freqt3], 12(%[freqp]) \n\t"
- "mult $ac0, $zero, $zero \n\t"
- "mult $ac1, $zero, $zero \n\t"
- "mult $ac2, $zero, $zero \n\t"
- "mult $ac3, $zero, $zero \n\t"
- "dpaq_s.w.ph $ac0, %[freqt0], %[freqt0] \n\t"
- "dpaq_s.w.ph $ac1, %[freqt1], %[freqt1] \n\t"
- "dpaq_s.w.ph $ac2, %[freqt2], %[freqt2] \n\t"
- "dpaq_s.w.ph $ac3, %[freqt3], %[freqt3] \n\t"
- "addiu %[freqp], %[freqp], 16 \n\t"
- "addiu %[freqabsp], %[freqabsp], 8 \n\t"
- "extr.w %[tmp32no20], $ac0, 1 \n\t"
- "extr.w %[tmp32no21], $ac1, 1 \n\t"
- "extr.w %[tmp32no22], $ac2, 1 \n\t"
- "extr.w %[tmp32no23], $ac3, 1 \n\t"
- : [freqt0] "=&r" (freqt0), [freqt1] "=&r" (freqt1),
- [freqt2] "=&r" (freqt2), [freqt3] "=&r" (freqt3),
- [tmp32no20] "=r" (tmp32no20), [tmp32no21] "=r" (tmp32no21),
- [tmp32no22] "=r" (tmp32no22), [tmp32no23] "=r" (tmp32no23),
- [freqabsp] "+r" (freqabsp), [freqp] "+r" (freqp)
- :
- : "memory", "hi", "lo", "$ac1hi", "$ac1lo",
- "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"
- );
-
- tmp32no10 = WebRtcSpl_SqrtFloor(tmp32no20);
- tmp32no11 = WebRtcSpl_SqrtFloor(tmp32no21);
- tmp32no12 = WebRtcSpl_SqrtFloor(tmp32no22);
- tmp32no13 = WebRtcSpl_SqrtFloor(tmp32no23);
-
- __asm __volatile (
- "sh %[tmp32no10], -8(%[freqabsp]) \n\t"
- "sh %[tmp32no11], -6(%[freqabsp]) \n\t"
- "sh %[tmp32no12], -4(%[freqabsp]) \n\t"
- "sh %[tmp32no13], -2(%[freqabsp]) \n\t"
- "addu %[freqs], %[freqs], %[tmp32no10] \n\t"
- "addu %[freqs], %[freqs], %[tmp32no11] \n\t"
- "addu %[freqs], %[freqs], %[tmp32no12] \n\t"
- "addu %[freqs], %[freqs], %[tmp32no13] \n\t"
- : [freqs] "+r" (freqs)
- : [tmp32no10] "r" (tmp32no10), [tmp32no11] "r" (tmp32no11),
- [tmp32no12] "r" (tmp32no12), [tmp32no13] "r" (tmp32no13),
- [freqabsp] "r" (freqabsp)
- : "memory"
- );
- }
-
- (*freq_signal_sum_abs) = freqs;
-#endif
-
- return time_signal_scaling;
-}
-
-int WebRtcAecm_ProcessBlock(AecmCore* aecm,
- const int16_t* farend,
- const int16_t* nearendNoisy,
- const int16_t* nearendClean,
- int16_t* output) {
- int i;
- uint32_t xfaSum;
- uint32_t dfaNoisySum;
- uint32_t dfaCleanSum;
- uint32_t echoEst32Gained;
- uint32_t tmpU32;
- int32_t tmp32no1;
-
- uint16_t xfa[PART_LEN1];
- uint16_t dfaNoisy[PART_LEN1];
- uint16_t dfaClean[PART_LEN1];
- uint16_t* ptrDfaClean = dfaClean;
- const uint16_t* far_spectrum_ptr = NULL;
-
- // 32 byte aligned buffers (with +8 or +16).
- int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
- int32_t echoEst32_buf[PART_LEN1 + 8];
- int32_t dfw_buf[PART_LEN2 + 8];
- int32_t efw_buf[PART_LEN2 + 8];
-
- int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~ 31);
- int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~ 31);
- ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31);
- ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31);
-
- int16_t hnl[PART_LEN1];
- int16_t numPosCoef = 0;
- int delay;
- int16_t tmp16no1;
- int16_t tmp16no2;
- int16_t mu;
- int16_t supGain;
- int16_t zeros32, zeros16;
- int16_t zerosDBufNoisy, zerosDBufClean, zerosXBuf;
- int far_q;
- int16_t resolutionDiff, qDomainDiff, dfa_clean_q_domain_diff;
-
- const int kMinPrefBand = 4;
- const int kMaxPrefBand = 24;
- int32_t avgHnl32 = 0;
-
- int32_t temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
- int16_t* ptr;
- int16_t* ptr1;
- int16_t* er_ptr;
- int16_t* dr_ptr;
-
- ptr = &hnl[0];
- ptr1 = &hnl[0];
- er_ptr = &efw[0].real;
- dr_ptr = &dfw[0].real;
-
- // Determine startup state. There are three states:
- // (0) the first CONV_LEN blocks
- // (1) another CONV_LEN blocks
- // (2) the rest
-
- if (aecm->startupState < 2) {
- aecm->startupState = (aecm->totCount >= CONV_LEN) +
- (aecm->totCount >= CONV_LEN2);
- }
- // END: Determine startup state
-
- // Buffer near and far end signals
- memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN);
- memcpy(aecm->dBufNoisy + PART_LEN,
- nearendNoisy,
- sizeof(int16_t) * PART_LEN);
- if (nearendClean != NULL) {
- memcpy(aecm->dBufClean + PART_LEN,
- nearendClean,
- sizeof(int16_t) * PART_LEN);
- }
-
- // Transform far end signal from time domain to frequency domain.
- far_q = TimeToFrequencyDomain(aecm,
- aecm->xBuf,
- dfw,
- xfa,
- &xfaSum);
-
- // Transform noisy near end signal from time domain to frequency domain.
- zerosDBufNoisy = TimeToFrequencyDomain(aecm,
- aecm->dBufNoisy,
- dfw,
- dfaNoisy,
- &dfaNoisySum);
- aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
- aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy;
-
- if (nearendClean == NULL) {
- ptrDfaClean = dfaNoisy;
- aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
- aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
- dfaCleanSum = dfaNoisySum;
- } else {
- // Transform clean near end signal from time domain to frequency domain.
- zerosDBufClean = TimeToFrequencyDomain(aecm,
- aecm->dBufClean,
- dfw,
- dfaClean,
- &dfaCleanSum);
- aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
- aecm->dfaCleanQDomain = (int16_t)zerosDBufClean;
- }
-
- // Get the delay
- // Save far-end history and estimate delay
- WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q);
-
- if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend, xfa, PART_LEN1,
- far_q) == -1) {
- return -1;
- }
- delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator,
- dfaNoisy,
- PART_LEN1,
- zerosDBufNoisy);
- if (delay == -1) {
- return -1;
- }
- else if (delay == -2) {
- // If the delay is unknown, we assume zero.
- // NOTE: this will have to be adjusted if we ever add lookahead.
- delay = 0;
- }
-
- if (aecm->fixedDelay >= 0) {
- // Use fixed delay
- delay = aecm->fixedDelay;
- }
-
- // Get aligned far end spectrum
- far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay);
- zerosXBuf = (int16_t) far_q;
-
- if (far_spectrum_ptr == NULL) {
- return -1;
- }
-
- // Calculate log(energy) and update energy threshold levels
- WebRtcAecm_CalcEnergies(aecm,
- far_spectrum_ptr,
- zerosXBuf,
- dfaNoisySum,
- echoEst32);
- // Calculate stepsize
- mu = WebRtcAecm_CalcStepSize(aecm);
-
- // Update counters
- aecm->totCount++;
-
- // This is the channel estimation algorithm.
- // It is base on NLMS but has a variable step length,
- // which was calculated above.
- WebRtcAecm_UpdateChannel(aecm,
- far_spectrum_ptr,
- zerosXBuf,
- dfaNoisy,
- mu,
- echoEst32);
-
- supGain = WebRtcAecm_CalcSuppressionGain(aecm);
-
- // Calculate Wiener filter hnl[]
- for (i = 0; i < PART_LEN1; i++) {
- // Far end signal through channel estimate in Q8
- // How much can we shift right to preserve resolution
- tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
- aecm->echoFilt[i] += (tmp32no1 * 50) >> 8;
-
- zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
- zeros16 = WebRtcSpl_NormW16(supGain) + 1;
- if (zeros32 + zeros16 > 16) {
- // Multiplication is safe
- // Result in
- // Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff])
- echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
- (uint16_t)supGain);
- resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
- resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
- } else {
- tmp16no1 = 17 - zeros32 - zeros16;
- resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 -
- RESOLUTION_SUPGAIN;
- resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
- if (zeros32 > tmp16no1) {
- echoEst32Gained = WEBRTC_SPL_UMUL_32_16(
- (uint32_t)aecm->echoFilt[i],
- supGain >> tmp16no1);
- } else {
- // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
- echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain;
- }
- }
-
- zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]);
- assert(zeros16 >= 0); // |zeros16| is a norm, hence non-negative.
- dfa_clean_q_domain_diff = aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld;
- if (zeros16 < dfa_clean_q_domain_diff && aecm->nearFilt[i]) {
- tmp16no1 = aecm->nearFilt[i] << zeros16;
- qDomainDiff = zeros16 - dfa_clean_q_domain_diff;
- tmp16no2 = ptrDfaClean[i] >> -qDomainDiff;
- } else {
- tmp16no1 = dfa_clean_q_domain_diff < 0
- ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff
- : aecm->nearFilt[i] << dfa_clean_q_domain_diff;
- qDomainDiff = 0;
- tmp16no2 = ptrDfaClean[i];
- }
-
- tmp32no1 = (int32_t)(tmp16no2 - tmp16no1);
- tmp16no2 = (int16_t)(tmp32no1 >> 4);
- tmp16no2 += tmp16no1;
- zeros16 = WebRtcSpl_NormW16(tmp16no2);
- if ((tmp16no2) & (-qDomainDiff > zeros16)) {
- aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
- } else {
- aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 << -qDomainDiff
- : tmp16no2 >> qDomainDiff;
- }
-
- // Wiener filter coefficients, resulting hnl in Q14
- if (echoEst32Gained == 0) {
- hnl[i] = ONE_Q14;
- numPosCoef++;
- } else if (aecm->nearFilt[i] == 0) {
- hnl[i] = 0;
- } else {
- // Multiply the suppression gain
- // Rounding
- echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1);
- tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained,
- (uint16_t)aecm->nearFilt[i]);
-
- // Current resolution is
- // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN
- // - max(0, 17 - zeros16 - zeros32))
- // Make sure we are in Q14
- tmp32no1 = (int32_t)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
- if (tmp32no1 > ONE_Q14) {
- hnl[i] = 0;
- } else if (tmp32no1 < 0) {
- hnl[i] = ONE_Q14;
- numPosCoef++;
- } else {
- // 1-echoEst/dfa
- hnl[i] = ONE_Q14 - (int16_t)tmp32no1;
- if (hnl[i] <= 0) {
- hnl[i] = 0;
- } else {
- numPosCoef++;
- }
- }
- }
- }
-
- // Only in wideband. Prevent the gain in upper band from being larger than
- // in lower band.
- if (aecm->mult == 2) {
- // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
- // speech distortion in double-talk.
- for (i = 0; i < (PART_LEN1 >> 3); i++) {
- __asm __volatile (
- "lh %[temp1], 0(%[ptr1]) \n\t"
- "lh %[temp2], 2(%[ptr1]) \n\t"
- "lh %[temp3], 4(%[ptr1]) \n\t"
- "lh %[temp4], 6(%[ptr1]) \n\t"
- "lh %[temp5], 8(%[ptr1]) \n\t"
- "lh %[temp6], 10(%[ptr1]) \n\t"
- "lh %[temp7], 12(%[ptr1]) \n\t"
- "lh %[temp8], 14(%[ptr1]) \n\t"
- "mul %[temp1], %[temp1], %[temp1] \n\t"
- "mul %[temp2], %[temp2], %[temp2] \n\t"
- "mul %[temp3], %[temp3], %[temp3] \n\t"
- "mul %[temp4], %[temp4], %[temp4] \n\t"
- "mul %[temp5], %[temp5], %[temp5] \n\t"
- "mul %[temp6], %[temp6], %[temp6] \n\t"
- "mul %[temp7], %[temp7], %[temp7] \n\t"
- "mul %[temp8], %[temp8], %[temp8] \n\t"
- "sra %[temp1], %[temp1], 14 \n\t"
- "sra %[temp2], %[temp2], 14 \n\t"
- "sra %[temp3], %[temp3], 14 \n\t"
- "sra %[temp4], %[temp4], 14 \n\t"
- "sra %[temp5], %[temp5], 14 \n\t"
- "sra %[temp6], %[temp6], 14 \n\t"
- "sra %[temp7], %[temp7], 14 \n\t"
- "sra %[temp8], %[temp8], 14 \n\t"
- "sh %[temp1], 0(%[ptr1]) \n\t"
- "sh %[temp2], 2(%[ptr1]) \n\t"
- "sh %[temp3], 4(%[ptr1]) \n\t"
- "sh %[temp4], 6(%[ptr1]) \n\t"
- "sh %[temp5], 8(%[ptr1]) \n\t"
- "sh %[temp6], 10(%[ptr1]) \n\t"
- "sh %[temp7], 12(%[ptr1]) \n\t"
- "sh %[temp8], 14(%[ptr1]) \n\t"
- "addiu %[ptr1], %[ptr1], 16 \n\t"
- : [temp1] "=&r" (temp1), [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
- [temp4] "=&r" (temp4), [temp5] "=&r" (temp5), [temp6] "=&r" (temp6),
- [temp7] "=&r" (temp7), [temp8] "=&r" (temp8), [ptr1] "+r" (ptr1)
- :
- : "memory", "hi", "lo"
- );
- }
- for(i = 0; i < (PART_LEN1 & 7); i++) {
- __asm __volatile (
- "lh %[temp1], 0(%[ptr1]) \n\t"
- "mul %[temp1], %[temp1], %[temp1] \n\t"
- "sra %[temp1], %[temp1], 14 \n\t"
- "sh %[temp1], 0(%[ptr1]) \n\t"
- "addiu %[ptr1], %[ptr1], 2 \n\t"
- : [temp1] "=&r" (temp1), [ptr1] "+r" (ptr1)
- :
- : "memory", "hi", "lo"
- );
- }
-
- for (i = kMinPrefBand; i <= kMaxPrefBand; i++) {
- avgHnl32 += (int32_t)hnl[i];
- }
-
- assert(kMaxPrefBand - kMinPrefBand + 1 > 0);
- avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1);
-
- for (i = kMaxPrefBand; i < PART_LEN1; i++) {
- if (hnl[i] > (int16_t)avgHnl32) {
- hnl[i] = (int16_t)avgHnl32;
- }
- }
- }
-
- // Calculate NLP gain, result is in Q14
- if (aecm->nlpFlag) {
- if (numPosCoef < 3) {
- for (i = 0; i < PART_LEN1; i++) {
- efw[i].real = 0;
- efw[i].imag = 0;
- hnl[i] = 0;
- }
- } else {
- for (i = 0; i < PART_LEN1; i++) {
-#if defined(MIPS_DSP_R1_LE)
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "lh %[temp1], 0(%[ptr]) \n\t"
- "lh %[temp2], 0(%[dr_ptr]) \n\t"
- "slti %[temp4], %[temp1], 0x4001 \n\t"
- "beqz %[temp4], 3f \n\t"
- " lh %[temp3], 2(%[dr_ptr]) \n\t"
- "slti %[temp5], %[temp1], 3277 \n\t"
- "bnez %[temp5], 2f \n\t"
- " addiu %[dr_ptr], %[dr_ptr], 4 \n\t"
- "mul %[temp2], %[temp2], %[temp1] \n\t"
- "mul %[temp3], %[temp3], %[temp1] \n\t"
- "shra_r.w %[temp2], %[temp2], 14 \n\t"
- "shra_r.w %[temp3], %[temp3], 14 \n\t"
- "b 4f \n\t"
- " nop \n\t"
- "2: \n\t"
- "addu %[temp1], $zero, $zero \n\t"
- "addu %[temp2], $zero, $zero \n\t"
- "addu %[temp3], $zero, $zero \n\t"
- "b 1f \n\t"
- " nop \n\t"
- "3: \n\t"
- "addiu %[temp1], $0, 0x4000 \n\t"
- "1: \n\t"
- "sh %[temp1], 0(%[ptr]) \n\t"
- "4: \n\t"
- "sh %[temp2], 0(%[er_ptr]) \n\t"
- "sh %[temp3], 2(%[er_ptr]) \n\t"
- "addiu %[ptr], %[ptr], 2 \n\t"
- "addiu %[er_ptr], %[er_ptr], 4 \n\t"
- ".set pop \n\t"
- : [temp1] "=&r" (temp1), [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
- [temp4] "=&r" (temp4), [temp5] "=&r" (temp5), [ptr] "+r" (ptr),
- [er_ptr] "+r" (er_ptr), [dr_ptr] "+r" (dr_ptr)
- :
- : "memory", "hi", "lo"
- );
-#else
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "lh %[temp1], 0(%[ptr]) \n\t"
- "lh %[temp2], 0(%[dr_ptr]) \n\t"
- "slti %[temp4], %[temp1], 0x4001 \n\t"
- "beqz %[temp4], 3f \n\t"
- " lh %[temp3], 2(%[dr_ptr]) \n\t"
- "slti %[temp5], %[temp1], 3277 \n\t"
- "bnez %[temp5], 2f \n\t"
- " addiu %[dr_ptr], %[dr_ptr], 4 \n\t"
- "mul %[temp2], %[temp2], %[temp1] \n\t"
- "mul %[temp3], %[temp3], %[temp1] \n\t"
- "addiu %[temp2], %[temp2], 0x2000 \n\t"
- "addiu %[temp3], %[temp3], 0x2000 \n\t"
- "sra %[temp2], %[temp2], 14 \n\t"
- "sra %[temp3], %[temp3], 14 \n\t"
- "b 4f \n\t"
- " nop \n\t"
- "2: \n\t"
- "addu %[temp1], $zero, $zero \n\t"
- "addu %[temp2], $zero, $zero \n\t"
- "addu %[temp3], $zero, $zero \n\t"
- "b 1f \n\t"
- " nop \n\t"
- "3: \n\t"
- "addiu %[temp1], $0, 0x4000 \n\t"
- "1: \n\t"
- "sh %[temp1], 0(%[ptr]) \n\t"
- "4: \n\t"
- "sh %[temp2], 0(%[er_ptr]) \n\t"
- "sh %[temp3], 2(%[er_ptr]) \n\t"
- "addiu %[ptr], %[ptr], 2 \n\t"
- "addiu %[er_ptr], %[er_ptr], 4 \n\t"
- ".set pop \n\t"
- : [temp1] "=&r" (temp1), [temp2] "=&r" (temp2), [temp3] "=&r" (temp3),
- [temp4] "=&r" (temp4), [temp5] "=&r" (temp5), [ptr] "+r" (ptr),
- [er_ptr] "+r" (er_ptr), [dr_ptr] "+r" (dr_ptr)
- :
- : "memory", "hi", "lo"
- );
-#endif
- }
- }
- }
- else {
- // multiply with Wiener coefficients
- for (i = 0; i < PART_LEN1; i++) {
- efw[i].real = (int16_t)
- (WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
- hnl[i],
- 14));
- efw[i].imag = (int16_t)
- (WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
- hnl[i],
- 14));
- }
- }
-
- if (aecm->cngMode == AecmTrue) {
- ComfortNoise(aecm, ptrDfaClean, efw, hnl);
- }
-
- InverseFFTAndWindow(aecm, fft, efw, output, nearendClean);
-
- return 0;
-}
-
-// Generate comfort noise and add to output signal.
-static void ComfortNoise(AecmCore* aecm,
- const uint16_t* dfa,
- ComplexInt16* out,
- const int16_t* lambda) {
- int16_t i;
- int16_t tmp16, tmp161, tmp162, tmp163, nrsh1, nrsh2;
- int32_t tmp32, tmp321, tnoise, tnoise1;
- int32_t tmp322, tmp323, *tmp1;
- int16_t* dfap;
- int16_t* lambdap;
- const int32_t c2049 = 2049;
- const int32_t c359 = 359;
- const int32_t c114 = ONE_Q14;
-
- int16_t randW16[PART_LEN];
- int16_t uReal[PART_LEN1];
- int16_t uImag[PART_LEN1];
- int32_t outLShift32;
-
- int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
- int16_t minTrackShift = 9;
-
- assert(shiftFromNearToNoise >= 0);
- assert(shiftFromNearToNoise < 16);
-
- if (aecm->noiseEstCtr < 100) {
- // Track the minimum more quickly initially.
- aecm->noiseEstCtr++;
- minTrackShift = 6;
- }
-
- // Generate a uniform random array on [0 2^15-1].
- WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
- int16_t* randW16p = (int16_t*)randW16;
-#if defined (MIPS_DSP_R1_LE)
- int16_t* kCosTablep = (int16_t*)WebRtcAecm_kCosTable;
- int16_t* kSinTablep = (int16_t*)WebRtcAecm_kSinTable;
-#endif // #if defined(MIPS_DSP_R1_LE)
- tmp1 = (int32_t*)aecm->noiseEst + 1;
- dfap = (int16_t*)dfa + 1;
- lambdap = (int16_t*)lambda + 1;
- // Estimate noise power.
- for (i = 1; i < PART_LEN1; i+=2) {
- // Shift to the noise domain.
- __asm __volatile (
- "lh %[tmp32], 0(%[dfap]) \n\t"
- "lw %[tnoise], 0(%[tmp1]) \n\t"
- "sllv %[outLShift32], %[tmp32], %[shiftFromNearToNoise] \n\t"
- : [tmp32] "=&r" (tmp32), [outLShift32] "=r" (outLShift32),
- [tnoise] "=&r" (tnoise)
- : [tmp1] "r" (tmp1), [dfap] "r" (dfap),
- [shiftFromNearToNoise] "r" (shiftFromNearToNoise)
- : "memory"
- );
-
- if (outLShift32 < tnoise) {
- // Reset "too low" counter
- aecm->noiseEstTooLowCtr[i] = 0;
- // Track the minimum.
- if (tnoise < (1 << minTrackShift)) {
- // For small values, decrease noiseEst[i] every
- // |kNoiseEstIncCount| block. The regular approach below can not
- // go further down due to truncation.
- aecm->noiseEstTooHighCtr[i]++;
- if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) {
- tnoise--;
- aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
- }
- } else {
- __asm __volatile (
- "subu %[tmp32], %[tnoise], %[outLShift32] \n\t"
- "srav %[tmp32], %[tmp32], %[minTrackShift] \n\t"
- "subu %[tnoise], %[tnoise], %[tmp32] \n\t"
- : [tmp32] "=&r" (tmp32), [tnoise] "+r" (tnoise)
- : [outLShift32] "r" (outLShift32), [minTrackShift] "r" (minTrackShift)
- );
- }
- } else {
- // Reset "too high" counter
- aecm->noiseEstTooHighCtr[i] = 0;
- // Ramp slowly upwards until we hit the minimum again.
- if ((tnoise >> 19) <= 0) {
- if ((tnoise >> 11) > 0) {
- // Large enough for relative increase
- __asm __volatile (
- "mul %[tnoise], %[tnoise], %[c2049] \n\t"
- "sra %[tnoise], %[tnoise], 11 \n\t"
- : [tnoise] "+r" (tnoise)
- : [c2049] "r" (c2049)
- : "hi", "lo"
- );
- } else {
- // Make incremental increases based on size every
- // |kNoiseEstIncCount| block
- aecm->noiseEstTooLowCtr[i]++;
- if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) {
- __asm __volatile (
- "sra %[tmp32], %[tnoise], 9 \n\t"
- "addi %[tnoise], %[tnoise], 1 \n\t"
- "addu %[tnoise], %[tnoise], %[tmp32] \n\t"
- : [tnoise] "+r" (tnoise), [tmp32] "=&r" (tmp32)
- :
- );
- aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
- }
- }
- } else {
- // Avoid overflow.
- // Multiplication with 2049 will cause wrap around. Scale
- // down first and then multiply
- __asm __volatile (
- "sra %[tnoise], %[tnoise], 11 \n\t"
- "mul %[tnoise], %[tnoise], %[c2049] \n\t"
- : [tnoise] "+r" (tnoise)
- : [c2049] "r" (c2049)
- : "hi", "lo"
- );
- }
- }
-
- // Shift to the noise domain.
- __asm __volatile (
- "lh %[tmp32], 2(%[dfap]) \n\t"
- "lw %[tnoise1], 4(%[tmp1]) \n\t"
- "addiu %[dfap], %[dfap], 4 \n\t"
- "sllv %[outLShift32], %[tmp32], %[shiftFromNearToNoise] \n\t"
- : [tmp32] "=&r" (tmp32), [dfap] "+r" (dfap),
- [outLShift32] "=r" (outLShift32), [tnoise1] "=&r" (tnoise1)
- : [tmp1] "r" (tmp1), [shiftFromNearToNoise] "r" (shiftFromNearToNoise)
- : "memory"
- );
-
- if (outLShift32 < tnoise1) {
- // Reset "too low" counter
- aecm->noiseEstTooLowCtr[i + 1] = 0;
- // Track the minimum.
- if (tnoise1 < (1 << minTrackShift)) {
- // For small values, decrease noiseEst[i] every
- // |kNoiseEstIncCount| block. The regular approach below can not
- // go further down due to truncation.
- aecm->noiseEstTooHighCtr[i + 1]++;
- if (aecm->noiseEstTooHighCtr[i + 1] >= kNoiseEstIncCount) {
- tnoise1--;
- aecm->noiseEstTooHighCtr[i + 1] = 0; // Reset the counter
- }
- } else {
- __asm __volatile (
- "subu %[tmp32], %[tnoise1], %[outLShift32] \n\t"
- "srav %[tmp32], %[tmp32], %[minTrackShift] \n\t"
- "subu %[tnoise1], %[tnoise1], %[tmp32] \n\t"
- : [tmp32] "=&r" (tmp32), [tnoise1] "+r" (tnoise1)
- : [outLShift32] "r" (outLShift32), [minTrackShift] "r" (minTrackShift)
- );
- }
- } else {
- // Reset "too high" counter
- aecm->noiseEstTooHighCtr[i + 1] = 0;
- // Ramp slowly upwards until we hit the minimum again.
- if ((tnoise1 >> 19) <= 0) {
- if ((tnoise1 >> 11) > 0) {
- // Large enough for relative increase
- __asm __volatile (
- "mul %[tnoise1], %[tnoise1], %[c2049] \n\t"
- "sra %[tnoise1], %[tnoise1], 11 \n\t"
- : [tnoise1] "+r" (tnoise1)
- : [c2049] "r" (c2049)
- : "hi", "lo"
- );
- } else {
- // Make incremental increases based on size every
- // |kNoiseEstIncCount| block
- aecm->noiseEstTooLowCtr[i + 1]++;
- if (aecm->noiseEstTooLowCtr[i + 1] >= kNoiseEstIncCount) {
- __asm __volatile (
- "sra %[tmp32], %[tnoise1], 9 \n\t"
- "addi %[tnoise1], %[tnoise1], 1 \n\t"
- "addu %[tnoise1], %[tnoise1], %[tmp32] \n\t"
- : [tnoise1] "+r" (tnoise1), [tmp32] "=&r" (tmp32)
- :
- );
- aecm->noiseEstTooLowCtr[i + 1] = 0; // Reset counter
- }
- }
- } else {
- // Avoid overflow.
- // Multiplication with 2049 will cause wrap around. Scale
- // down first and then multiply
- __asm __volatile (
- "sra %[tnoise1], %[tnoise1], 11 \n\t"
- "mul %[tnoise1], %[tnoise1], %[c2049] \n\t"
- : [tnoise1] "+r" (tnoise1)
- : [c2049] "r" (c2049)
- : "hi", "lo"
- );
- }
- }
-
- __asm __volatile (
- "lh %[tmp16], 0(%[lambdap]) \n\t"
- "lh %[tmp161], 2(%[lambdap]) \n\t"
- "sw %[tnoise], 0(%[tmp1]) \n\t"
- "sw %[tnoise1], 4(%[tmp1]) \n\t"
- "subu %[tmp16], %[c114], %[tmp16] \n\t"
- "subu %[tmp161], %[c114], %[tmp161] \n\t"
- "srav %[tmp32], %[tnoise], %[shiftFromNearToNoise] \n\t"
- "srav %[tmp321], %[tnoise1], %[shiftFromNearToNoise] \n\t"
- "addiu %[lambdap], %[lambdap], 4 \n\t"
- "addiu %[tmp1], %[tmp1], 8 \n\t"
- : [tmp16] "=&r" (tmp16), [tmp161] "=&r" (tmp161), [tmp1] "+r" (tmp1),
- [tmp32] "=&r" (tmp32), [tmp321] "=&r" (tmp321), [lambdap] "+r" (lambdap)
- : [tnoise] "r" (tnoise), [tnoise1] "r" (tnoise1), [c114] "r" (c114),
- [shiftFromNearToNoise] "r" (shiftFromNearToNoise)
- : "memory"
- );
-
- if (tmp32 > 32767) {
- tmp32 = 32767;
- aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise;
- }
- if (tmp321 > 32767) {
- tmp321 = 32767;
- aecm->noiseEst[i+1] = tmp321 << shiftFromNearToNoise;
- }
-
- __asm __volatile (
- "mul %[tmp32], %[tmp32], %[tmp16] \n\t"
- "mul %[tmp321], %[tmp321], %[tmp161] \n\t"
- "sra %[nrsh1], %[tmp32], 14 \n\t"
- "sra %[nrsh2], %[tmp321], 14 \n\t"
- : [nrsh1] "=&r" (nrsh1), [nrsh2] "=r" (nrsh2)
- : [tmp16] "r" (tmp16), [tmp161] "r" (tmp161), [tmp32] "r" (tmp32),
- [tmp321] "r" (tmp321)
- : "memory", "hi", "lo"
- );
-
- __asm __volatile (
- "lh %[tmp32], 0(%[randW16p]) \n\t"
- "lh %[tmp321], 2(%[randW16p]) \n\t"
- "addiu %[randW16p], %[randW16p], 4 \n\t"
- "mul %[tmp32], %[tmp32], %[c359] \n\t"
- "mul %[tmp321], %[tmp321], %[c359] \n\t"
- "sra %[tmp16], %[tmp32], 15 \n\t"
- "sra %[tmp161], %[tmp321], 15 \n\t"
- : [randW16p] "+r" (randW16p), [tmp32] "=&r" (tmp32),
- [tmp16] "=r" (tmp16), [tmp161] "=r" (tmp161), [tmp321] "=&r" (tmp321)
- : [c359] "r" (c359)
- : "memory", "hi", "lo"
- );
-
-#if !defined(MIPS_DSP_R1_LE)
- tmp32 = WebRtcAecm_kCosTable[tmp16];
- tmp321 = WebRtcAecm_kSinTable[tmp16];
- tmp322 = WebRtcAecm_kCosTable[tmp161];
- tmp323 = WebRtcAecm_kSinTable[tmp161];
-#else
- __asm __volatile (
- "sll %[tmp16], %[tmp16], 1 \n\t"
- "sll %[tmp161], %[tmp161], 1 \n\t"
- "lhx %[tmp32], %[tmp16](%[kCosTablep]) \n\t"
- "lhx %[tmp321], %[tmp16](%[kSinTablep]) \n\t"
- "lhx %[tmp322], %[tmp161](%[kCosTablep]) \n\t"
- "lhx %[tmp323], %[tmp161](%[kSinTablep]) \n\t"
- : [tmp32] "=&r" (tmp32), [tmp321] "=&r" (tmp321),
- [tmp322] "=&r" (tmp322), [tmp323] "=&r" (tmp323)
- : [kCosTablep] "r" (kCosTablep), [tmp16] "r" (tmp16),
- [tmp161] "r" (tmp161), [kSinTablep] "r" (kSinTablep)
- : "memory"
- );
-#endif
- __asm __volatile (
- "mul %[tmp32], %[tmp32], %[nrsh1] \n\t"
- "negu %[tmp162], %[nrsh1] \n\t"
- "mul %[tmp322], %[tmp322], %[nrsh2] \n\t"
- "negu %[tmp163], %[nrsh2] \n\t"
- "sra %[tmp32], %[tmp32], 13 \n\t"
- "mul %[tmp321], %[tmp321], %[tmp162] \n\t"
- "sra %[tmp322], %[tmp322], 13 \n\t"
- "mul %[tmp323], %[tmp323], %[tmp163] \n\t"
- "sra %[tmp321], %[tmp321], 13 \n\t"
- "sra %[tmp323], %[tmp323], 13 \n\t"
- : [tmp32] "+r" (tmp32), [tmp321] "+r" (tmp321), [tmp162] "=&r" (tmp162),
- [tmp322] "+r" (tmp322), [tmp323] "+r" (tmp323), [tmp163] "=&r" (tmp163)
- : [nrsh1] "r" (nrsh1), [nrsh2] "r" (nrsh2)
- : "hi", "lo"
- );
- // Tables are in Q13.
- uReal[i] = (int16_t)tmp32;
- uImag[i] = (int16_t)tmp321;
- uReal[i + 1] = (int16_t)tmp322;
- uImag[i + 1] = (int16_t)tmp323;
- }
-
- int32_t tt, sgn;
- tt = out[0].real;
- sgn = ((int)tt) >> 31;
- out[0].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
- tt = out[0].imag;
- sgn = ((int)tt) >> 31;
- out[0].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
- for (i = 1; i < PART_LEN; i++) {
- tt = out[i].real + uReal[i];
- sgn = ((int)tt) >> 31;
- out[i].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
- tt = out[i].imag + uImag[i];
- sgn = ((int)tt) >> 31;
- out[i].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
- }
- tt = out[PART_LEN].real + uReal[PART_LEN];
- sgn = ((int)tt) >> 31;
- out[PART_LEN].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
- tt = out[PART_LEN].imag;
- sgn = ((int)tt) >> 31;
- out[PART_LEN].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
-}
-
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc b/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc
new file mode 100644
index 0000000..f2f43e1
--- /dev/null
+++ b/webrtc/modules/audio_processing/aecm/aecm_core_mips.cc
@@ -0,0 +1,1656 @@
+/*
+ * 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/audio_processing/aecm/aecm_core.h"
+#include "modules/audio_processing/aecm/echo_control_mobile.h"
+#include "modules/audio_processing/utility/delay_estimator_wrapper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+
+namespace {
+
+static const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
+ 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, 3562, 3951,
+ 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019,
+ 8364, 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
+ 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189,
+ 14384, 14571, 14749, 14918, 15079, 15231, 15373, 15506, 15631, 15746, 15851,
+ 15947, 16034, 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384};
+
+static const int16_t kNoiseEstQDomain = 15;
+static const int16_t kNoiseEstIncCount = 5;
+
+static int16_t coefTable[] = {
+ 0, 4, 256, 260, 128, 132, 384, 388, 64, 68, 320, 324, 192, 196, 448,
+ 452, 32, 36, 288, 292, 160, 164, 416, 420, 96, 100, 352, 356, 224, 228,
+ 480, 484, 16, 20, 272, 276, 144, 148, 400, 404, 80, 84, 336, 340, 208,
+ 212, 464, 468, 48, 52, 304, 308, 176, 180, 432, 436, 112, 116, 368, 372,
+ 240, 244, 496, 500, 8, 12, 264, 268, 136, 140, 392, 396, 72, 76, 328,
+ 332, 200, 204, 456, 460, 40, 44, 296, 300, 168, 172, 424, 428, 104, 108,
+ 360, 364, 232, 236, 488, 492, 24, 28, 280, 284, 152, 156, 408, 412, 88,
+ 92, 344, 348, 216, 220, 472, 476, 56, 60, 312, 316, 184, 188, 440, 444,
+ 120, 124, 376, 380, 248, 252, 504, 508};
+
+static int16_t coefTable_ifft[] = {
+ 0, 512, 256, 508, 128, 252, 384, 380, 64, 124, 320, 444, 192, 188, 448,
+ 316, 32, 60, 288, 476, 160, 220, 416, 348, 96, 92, 352, 412, 224, 156,
+ 480, 284, 16, 28, 272, 492, 144, 236, 400, 364, 80, 108, 336, 428, 208,
+ 172, 464, 300, 48, 44, 304, 460, 176, 204, 432, 332, 112, 76, 368, 396,
+ 240, 140, 496, 268, 8, 12, 264, 500, 136, 244, 392, 372, 72, 116, 328,
+ 436, 200, 180, 456, 308, 40, 52, 296, 468, 168, 212, 424, 340, 104, 84,
+ 360, 404, 232, 148, 488, 276, 24, 20, 280, 484, 152, 228, 408, 356, 88,
+ 100, 344, 420, 216, 164, 472, 292, 56, 36, 312, 452, 184, 196, 440, 324,
+ 120, 68, 376, 388, 248, 132, 504, 260};
+
+} // namespace
+
+static void ComfortNoise(AecmCore* aecm,
+ const uint16_t* dfa,
+ ComplexInt16* out,
+ const int16_t* lambda);
+
+static void WindowAndFFT(AecmCore* aecm,
+ int16_t* fft,
+ const int16_t* time_signal,
+ ComplexInt16* freq_signal,
+ int time_signal_scaling) {
+ int i, j;
+ int32_t tmp1, tmp2, tmp3, tmp4;
+ int16_t* pfrfi;
+ ComplexInt16* pfreq_signal;
+ int16_t f_coef, s_coef;
+ int32_t load_ptr, store_ptr1, store_ptr2, shift, shift1;
+ int32_t hann, hann1, coefs;
+
+ memset(fft, 0, sizeof(int16_t) * PART_LEN4);
+
+ // FFT of signal
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[shift], %[time_signal_scaling], -14 \n\t"
+ "addiu %[i], $zero, 64 \n\t"
+ "addiu %[load_ptr], %[time_signal], 0 \n\t"
+ "addiu %[hann], %[hanning], 0 \n\t"
+ "addiu %[hann1], %[hanning], 128 \n\t"
+ "addiu %[coefs], %[coefTable], 0 \n\t"
+ "bltz %[shift], 2f \n\t"
+ " negu %[shift1], %[shift] \n\t"
+ "1: "
+ "\n\t"
+ "lh %[tmp1], 0(%[load_ptr]) \n\t"
+ "lh %[tmp2], 0(%[hann]) \n\t"
+ "lh %[tmp3], 128(%[load_ptr]) \n\t"
+ "lh %[tmp4], 0(%[hann1]) \n\t"
+ "addiu %[i], %[i], -1 \n\t"
+ "mul %[tmp1], %[tmp1], %[tmp2] \n\t"
+ "mul %[tmp3], %[tmp3], %[tmp4] \n\t"
+ "lh %[f_coef], 0(%[coefs]) \n\t"
+ "lh %[s_coef], 2(%[coefs]) \n\t"
+ "addiu %[load_ptr], %[load_ptr], 2 \n\t"
+ "addiu %[hann], %[hann], 2 \n\t"
+ "addiu %[hann1], %[hann1], -2 \n\t"
+ "addu %[store_ptr1], %[fft], %[f_coef] \n\t"
+ "addu %[store_ptr2], %[fft], %[s_coef] \n\t"
+ "sllv %[tmp1], %[tmp1], %[shift] \n\t"
+ "sllv %[tmp3], %[tmp3], %[shift] \n\t"
+ "sh %[tmp1], 0(%[store_ptr1]) \n\t"
+ "sh %[tmp3], 0(%[store_ptr2]) \n\t"
+ "bgtz %[i], 1b \n\t"
+ " addiu %[coefs], %[coefs], 4 \n\t"
+ "b 3f \n\t"
+ " nop \n\t"
+ "2: "
+ "\n\t"
+ "lh %[tmp1], 0(%[load_ptr]) \n\t"
+ "lh %[tmp2], 0(%[hann]) \n\t"
+ "lh %[tmp3], 128(%[load_ptr]) \n\t"
+ "lh %[tmp4], 0(%[hann1]) \n\t"
+ "addiu %[i], %[i], -1 \n\t"
+ "mul %[tmp1], %[tmp1], %[tmp2] \n\t"
+ "mul %[tmp3], %[tmp3], %[tmp4] \n\t"
+ "lh %[f_coef], 0(%[coefs]) \n\t"
+ "lh %[s_coef], 2(%[coefs]) \n\t"
+ "addiu %[load_ptr], %[load_ptr], 2 \n\t"
+ "addiu %[hann], %[hann], 2 \n\t"
+ "addiu %[hann1], %[hann1], -2 \n\t"
+ "addu %[store_ptr1], %[fft], %[f_coef] \n\t"
+ "addu %[store_ptr2], %[fft], %[s_coef] \n\t"
+ "srav %[tmp1], %[tmp1], %[shift1] \n\t"
+ "srav %[tmp3], %[tmp3], %[shift1] \n\t"
+ "sh %[tmp1], 0(%[store_ptr1]) \n\t"
+ "sh %[tmp3], 0(%[store_ptr2]) \n\t"
+ "bgtz %[i], 2b \n\t"
+ " addiu %[coefs], %[coefs], 4 \n\t"
+ "3: "
+ "\n\t"
+ ".set pop \n\t"
+ : [load_ptr] "=&r"(load_ptr), [shift] "=&r"(shift), [hann] "=&r"(hann),
+ [hann1] "=&r"(hann1), [shift1] "=&r"(shift1), [coefs] "=&r"(coefs),
+ [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [tmp3] "=&r"(tmp3),
+ [tmp4] "=&r"(tmp4), [i] "=&r"(i), [f_coef] "=&r"(f_coef),
+ [s_coef] "=&r"(s_coef), [store_ptr1] "=&r"(store_ptr1),
+ [store_ptr2] "=&r"(store_ptr2)
+ : [time_signal] "r"(time_signal), [coefTable] "r"(coefTable),
+ [time_signal_scaling] "r"(time_signal_scaling),
+ [hanning] "r"(WebRtcAecm_kSqrtHanning), [fft] "r"(fft)
+ : "memory", "hi", "lo");
+
+ WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
+ pfrfi = fft;
+ pfreq_signal = freq_signal;
+
+ __asm __volatile(
+ ".set push "
+ "\n\t"
+ ".set noreorder "
+ "\n\t"
+ "addiu %[j], $zero, 128 "
+ "\n\t"
+ "1: "
+ "\n\t"
+ "lh %[tmp1], 0(%[pfrfi]) "
+ "\n\t"
+ "lh %[tmp2], 2(%[pfrfi]) "
+ "\n\t"
+ "lh %[tmp3], 4(%[pfrfi]) "
+ "\n\t"
+ "lh %[tmp4], 6(%[pfrfi]) "
+ "\n\t"
+ "subu %[tmp2], $zero, %[tmp2] "
+ "\n\t"
+ "sh %[tmp1], 0(%[pfreq_signal]) "
+ "\n\t"
+ "sh %[tmp2], 2(%[pfreq_signal]) "
+ "\n\t"
+ "subu %[tmp4], $zero, %[tmp4] "
+ "\n\t"
+ "sh %[tmp3], 4(%[pfreq_signal]) "
+ "\n\t"
+ "sh %[tmp4], 6(%[pfreq_signal]) "
+ "\n\t"
+ "lh %[tmp1], 8(%[pfrfi]) "
+ "\n\t"
+ "lh %[tmp2], 10(%[pfrfi]) "
+ "\n\t"
+ "lh %[tmp3], 12(%[pfrfi]) "
+ "\n\t"
+ "lh %[tmp4], 14(%[pfrfi]) "
+ "\n\t"
+ "addiu %[j], %[j], -8 "
+ "\n\t"
+ "subu %[tmp2], $zero, %[tmp2] "
+ "\n\t"
+ "sh %[tmp1], 8(%[pfreq_signal]) "
+ "\n\t"
+ "sh %[tmp2], 10(%[pfreq_signal]) "
+ "\n\t"
+ "subu %[tmp4], $zero, %[tmp4] "
+ "\n\t"
+ "sh %[tmp3], 12(%[pfreq_signal]) "
+ "\n\t"
+ "sh %[tmp4], 14(%[pfreq_signal]) "
+ "\n\t"
+ "addiu %[pfreq_signal], %[pfreq_signal], 16 "
+ "\n\t"
+ "bgtz %[j], 1b "
+ "\n\t"
+ " addiu %[pfrfi], %[pfrfi], 16 "
+ "\n\t"
+ ".set pop "
+ "\n\t"
+ : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [tmp3] "=&r"(tmp3),
+ [j] "=&r"(j), [pfrfi] "+r"(pfrfi), [pfreq_signal] "+r"(pfreq_signal),
+ [tmp4] "=&r"(tmp4)
+ :
+ : "memory");
+}
+
+static void InverseFFTAndWindow(AecmCore* aecm,
+ int16_t* fft,
+ ComplexInt16* efw,
+ int16_t* output,
+ const int16_t* nearendClean) {
+ int i, outCFFT;
+ int32_t tmp1, tmp2, tmp3, tmp4, tmp_re, tmp_im;
+ int16_t* pcoefTable_ifft = coefTable_ifft;
+ int16_t* pfft = fft;
+ int16_t* ppfft = fft;
+ ComplexInt16* pefw = efw;
+ int32_t out_aecm;
+ int16_t* paecm_buf = aecm->outBuf;
+ const int16_t* p_kSqrtHanning = WebRtcAecm_kSqrtHanning;
+ const int16_t* pp_kSqrtHanning = &WebRtcAecm_kSqrtHanning[PART_LEN];
+ int16_t* output1 = output;
+
+ __asm __volatile(
+ ".set push "
+ "\n\t"
+ ".set noreorder "
+ "\n\t"
+ "addiu %[i], $zero, 64 "
+ "\n\t"
+ "1: "
+ "\n\t"
+ "lh %[tmp1], 0(%[pcoefTable_ifft]) "
+ "\n\t"
+ "lh %[tmp2], 2(%[pcoefTable_ifft]) "
+ "\n\t"
+ "lh %[tmp_re], 0(%[pefw]) "
+ "\n\t"
+ "lh %[tmp_im], 2(%[pefw]) "
+ "\n\t"
+ "addu %[pfft], %[fft], %[tmp2] "
+ "\n\t"
+ "sh %[tmp_re], 0(%[pfft]) "
+ "\n\t"
+ "sh %[tmp_im], 2(%[pfft]) "
+ "\n\t"
+ "addu %[pfft], %[fft], %[tmp1] "
+ "\n\t"
+ "sh %[tmp_re], 0(%[pfft]) "
+ "\n\t"
+ "subu %[tmp_im], $zero, %[tmp_im] "
+ "\n\t"
+ "sh %[tmp_im], 2(%[pfft]) "
+ "\n\t"
+ "lh %[tmp1], 4(%[pcoefTable_ifft]) "
+ "\n\t"
+ "lh %[tmp2], 6(%[pcoefTable_ifft]) "
+ "\n\t"
+ "lh %[tmp_re], 4(%[pefw]) "
+ "\n\t"
+ "lh %[tmp_im], 6(%[pefw]) "
+ "\n\t"
+ "addu %[pfft], %[fft], %[tmp2] "
+ "\n\t"
+ "sh %[tmp_re], 0(%[pfft]) "
+ "\n\t"
+ "sh %[tmp_im], 2(%[pfft]) "
+ "\n\t"
+ "addu %[pfft], %[fft], %[tmp1] "
+ "\n\t"
+ "sh %[tmp_re], 0(%[pfft]) "
+ "\n\t"
+ "subu %[tmp_im], $zero, %[tmp_im] "
+ "\n\t"
+ "sh %[tmp_im], 2(%[pfft]) "
+ "\n\t"
+ "lh %[tmp1], 8(%[pcoefTable_ifft]) "
+ "\n\t"
+ "lh %[tmp2], 10(%[pcoefTable_ifft]) "
+ "\n\t"
+ "lh %[tmp_re], 8(%[pefw]) "
+ "\n\t"
+ "lh %[tmp_im], 10(%[pefw]) "
+ "\n\t"
+ "addu %[pfft], %[fft], %[tmp2] "
+ "\n\t"
+ "sh %[tmp_re], 0(%[pfft]) "
+ "\n\t"
+ "sh %[tmp_im], 2(%[pfft]) "
+ "\n\t"
+ "addu %[pfft], %[fft], %[tmp1] "
+ "\n\t"
+ "sh %[tmp_re], 0(%[pfft]) "
+ "\n\t"
+ "subu %[tmp_im], $zero, %[tmp_im] "
+ "\n\t"
+ "sh %[tmp_im], 2(%[pfft]) "
+ "\n\t"
+ "lh %[tmp1], 12(%[pcoefTable_ifft]) "
+ "\n\t"
+ "lh %[tmp2], 14(%[pcoefTable_ifft]) "
+ "\n\t"
+ "lh %[tmp_re], 12(%[pefw]) "
+ "\n\t"
+ "lh %[tmp_im], 14(%[pefw]) "
+ "\n\t"
+ "addu %[pfft], %[fft], %[tmp2] "
+ "\n\t"
+ "sh %[tmp_re], 0(%[pfft]) "
+ "\n\t"
+ "sh %[tmp_im], 2(%[pfft]) "
+ "\n\t"
+ "addu %[pfft], %[fft], %[tmp1] "
+ "\n\t"
+ "sh %[tmp_re], 0(%[pfft]) "
+ "\n\t"
+ "subu %[tmp_im], $zero, %[tmp_im] "
+ "\n\t"
+ "sh %[tmp_im], 2(%[pfft]) "
+ "\n\t"
+ "addiu %[pcoefTable_ifft], %[pcoefTable_ifft], 16 "
+ "\n\t"
+ "addiu %[i], %[i], -4 "
+ "\n\t"
+ "bgtz %[i], 1b "
+ "\n\t"
+ " addiu %[pefw], %[pefw], 16 "
+ "\n\t"
+ ".set pop "
+ "\n\t"
+ : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft), [i] "=&r"(i),
+ [tmp_re] "=&r"(tmp_re), [tmp_im] "=&r"(tmp_im), [pefw] "+r"(pefw),
+ [pcoefTable_ifft] "+r"(pcoefTable_ifft), [fft] "+r"(fft)
+ :
+ : "memory");
+
+ fft[2] = efw[PART_LEN].real;
+ fft[3] = -efw[PART_LEN].imag;
+
+ outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1);
+ pfft = fft;
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[i], $zero, 128 \n\t"
+ "1: \n\t"
+ "lh %[tmp1], 0(%[ppfft]) \n\t"
+ "lh %[tmp2], 4(%[ppfft]) \n\t"
+ "lh %[tmp3], 8(%[ppfft]) \n\t"
+ "lh %[tmp4], 12(%[ppfft]) \n\t"
+ "addiu %[i], %[i], -4 \n\t"
+ "sh %[tmp1], 0(%[pfft]) \n\t"
+ "sh %[tmp2], 2(%[pfft]) \n\t"
+ "sh %[tmp3], 4(%[pfft]) \n\t"
+ "sh %[tmp4], 6(%[pfft]) \n\t"
+ "addiu %[ppfft], %[ppfft], 16 \n\t"
+ "bgtz %[i], 1b \n\t"
+ " addiu %[pfft], %[pfft], 8 \n\t"
+ ".set pop \n\t"
+ : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft), [i] "=&r"(i),
+ [tmp3] "=&r"(tmp3), [tmp4] "=&r"(tmp4), [ppfft] "+r"(ppfft)
+ :
+ : "memory");
+
+ pfft = fft;
+ out_aecm = (int32_t)(outCFFT - aecm->dfaCleanQDomain);
+
+ __asm __volatile(
+ ".set push "
+ "\n\t"
+ ".set noreorder "
+ "\n\t"
+ "addiu %[i], $zero, 64 "
+ "\n\t"
+ "11: "
+ "\n\t"
+ "lh %[tmp1], 0(%[pfft]) "
+ "\n\t"
+ "lh %[tmp2], 0(%[p_kSqrtHanning]) "
+ "\n\t"
+ "addiu %[i], %[i], -2 "
+ "\n\t"
+ "mul %[tmp1], %[tmp1], %[tmp2] "
+ "\n\t"
+ "lh %[tmp3], 2(%[pfft]) "
+ "\n\t"
+ "lh %[tmp4], 2(%[p_kSqrtHanning]) "
+ "\n\t"
+ "mul %[tmp3], %[tmp3], %[tmp4] "
+ "\n\t"
+ "addiu %[tmp1], %[tmp1], 8192 "
+ "\n\t"
+ "sra %[tmp1], %[tmp1], 14 "
+ "\n\t"
+ "addiu %[tmp3], %[tmp3], 8192 "
+ "\n\t"
+ "sra %[tmp3], %[tmp3], 14 "
+ "\n\t"
+ "bgez %[out_aecm], 1f "
+ "\n\t"
+ " negu %[tmp2], %[out_aecm] "
+ "\n\t"
+ "srav %[tmp1], %[tmp1], %[tmp2] "
+ "\n\t"
+ "b 2f "
+ "\n\t"
+ " srav %[tmp3], %[tmp3], %[tmp2] "
+ "\n\t"
+ "1: "
+ "\n\t"
+ "sllv %[tmp1], %[tmp1], %[out_aecm] "
+ "\n\t"
+ "sllv %[tmp3], %[tmp3], %[out_aecm] "
+ "\n\t"
+ "2: "
+ "\n\t"
+ "lh %[tmp4], 0(%[paecm_buf]) "
+ "\n\t"
+ "lh %[tmp2], 2(%[paecm_buf]) "
+ "\n\t"
+ "addu %[tmp3], %[tmp3], %[tmp2] "
+ "\n\t"
+ "addu %[tmp1], %[tmp1], %[tmp4] "
+ "\n\t"
+#if defined(MIPS_DSP_R1_LE)
+ "shll_s.w %[tmp1], %[tmp1], 16 "
+ "\n\t"
+ "sra %[tmp1], %[tmp1], 16 "
+ "\n\t"
+ "shll_s.w %[tmp3], %[tmp3], 16 "
+ "\n\t"
+ "sra %[tmp3], %[tmp3], 16 "
+ "\n\t"
+#else // #if defined(MIPS_DSP_R1_LE)
+ "sra %[tmp4], %[tmp1], 31 "
+ "\n\t"
+ "sra %[tmp2], %[tmp1], 15 "
+ "\n\t"
+ "beq %[tmp4], %[tmp2], 3f "
+ "\n\t"
+ " ori %[tmp2], $zero, 0x7fff "
+ "\n\t"
+ "xor %[tmp1], %[tmp2], %[tmp4] "
+ "\n\t"
+ "3: "
+ "\n\t"
+ "sra %[tmp2], %[tmp3], 31 "
+ "\n\t"
+ "sra %[tmp4], %[tmp3], 15 "
+ "\n\t"
+ "beq %[tmp2], %[tmp4], 4f "
+ "\n\t"
+ " ori %[tmp4], $zero, 0x7fff "
+ "\n\t"
+ "xor %[tmp3], %[tmp4], %[tmp2] "
+ "\n\t"
+ "4: "
+ "\n\t"
+#endif // #if defined(MIPS_DSP_R1_LE)
+ "sh %[tmp1], 0(%[pfft]) "
+ "\n\t"
+ "sh %[tmp1], 0(%[output1]) "
+ "\n\t"
+ "sh %[tmp3], 2(%[pfft]) "
+ "\n\t"
+ "sh %[tmp3], 2(%[output1]) "
+ "\n\t"
+ "lh %[tmp1], 128(%[pfft]) "
+ "\n\t"
+ "lh %[tmp2], 0(%[pp_kSqrtHanning]) "
+ "\n\t"
+ "mul %[tmp1], %[tmp1], %[tmp2] "
+ "\n\t"
+ "lh %[tmp3], 130(%[pfft]) "
+ "\n\t"
+ "lh %[tmp4], -2(%[pp_kSqrtHanning]) "
+ "\n\t"
+ "mul %[tmp3], %[tmp3], %[tmp4] "
+ "\n\t"
+ "sra %[tmp1], %[tmp1], 14 "
+ "\n\t"
+ "sra %[tmp3], %[tmp3], 14 "
+ "\n\t"
+ "bgez %[out_aecm], 5f "
+ "\n\t"
+ " negu %[tmp2], %[out_aecm] "
+ "\n\t"
+ "srav %[tmp3], %[tmp3], %[tmp2] "
+ "\n\t"
+ "b 6f "
+ "\n\t"
+ " srav %[tmp1], %[tmp1], %[tmp2] "
+ "\n\t"
+ "5: "
+ "\n\t"
+ "sllv %[tmp1], %[tmp1], %[out_aecm] "
+ "\n\t"
+ "sllv %[tmp3], %[tmp3], %[out_aecm] "
+ "\n\t"
+ "6: "
+ "\n\t"
+#if defined(MIPS_DSP_R1_LE)
+ "shll_s.w %[tmp1], %[tmp1], 16 "
+ "\n\t"
+ "sra %[tmp1], %[tmp1], 16 "
+ "\n\t"
+ "shll_s.w %[tmp3], %[tmp3], 16 "
+ "\n\t"
+ "sra %[tmp3], %[tmp3], 16 "
+ "\n\t"
+#else // #if defined(MIPS_DSP_R1_LE)
+ "sra %[tmp4], %[tmp1], 31 "
+ "\n\t"
+ "sra %[tmp2], %[tmp1], 15 "
+ "\n\t"
+ "beq %[tmp4], %[tmp2], 7f "
+ "\n\t"
+ " ori %[tmp2], $zero, 0x7fff "
+ "\n\t"
+ "xor %[tmp1], %[tmp2], %[tmp4] "
+ "\n\t"
+ "7: "
+ "\n\t"
+ "sra %[tmp2], %[tmp3], 31 "
+ "\n\t"
+ "sra %[tmp4], %[tmp3], 15 "
+ "\n\t"
+ "beq %[tmp2], %[tmp4], 8f "
+ "\n\t"
+ " ori %[tmp4], $zero, 0x7fff "
+ "\n\t"
+ "xor %[tmp3], %[tmp4], %[tmp2] "
+ "\n\t"
+ "8: "
+ "\n\t"
+#endif // #if defined(MIPS_DSP_R1_LE)
+ "sh %[tmp1], 0(%[paecm_buf]) "
+ "\n\t"
+ "sh %[tmp3], 2(%[paecm_buf]) "
+ "\n\t"
+ "addiu %[output1], %[output1], 4 "
+ "\n\t"
+ "addiu %[paecm_buf], %[paecm_buf], 4 "
+ "\n\t"
+ "addiu %[pfft], %[pfft], 4 "
+ "\n\t"
+ "addiu %[p_kSqrtHanning], %[p_kSqrtHanning], 4 "
+ "\n\t"
+ "bgtz %[i], 11b "
+ "\n\t"
+ " addiu %[pp_kSqrtHanning], %[pp_kSqrtHanning], -4 "
+ "\n\t"
+ ".set pop "
+ "\n\t"
+ : [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [pfft] "+r"(pfft),
+ [output1] "+r"(output1), [tmp3] "=&r"(tmp3), [tmp4] "=&r"(tmp4),
+ [paecm_buf] "+r"(paecm_buf), [i] "=&r"(i),
+ [pp_kSqrtHanning] "+r"(pp_kSqrtHanning),
+ [p_kSqrtHanning] "+r"(p_kSqrtHanning)
+ : [out_aecm] "r"(out_aecm),
+ [WebRtcAecm_kSqrtHanning] "r"(WebRtcAecm_kSqrtHanning)
+ : "hi", "lo", "memory");
+
+ // Copy the current block to the old position
+ // (aecm->outBuf is shifted elsewhere)
+ memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN);
+ memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN,
+ sizeof(int16_t) * PART_LEN);
+ if (nearendClean != NULL) {
+ memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN,
+ sizeof(int16_t) * PART_LEN);
+ }
+}
+
+void WebRtcAecm_CalcLinearEnergies_mips(AecmCore* aecm,
+ const uint16_t* far_spectrum,
+ int32_t* echo_est,
+ uint32_t* far_energy,
+ uint32_t* echo_energy_adapt,
+ uint32_t* echo_energy_stored) {
+ int i;
+ uint32_t par1 = (*far_energy);
+ uint32_t par2 = (*echo_energy_adapt);
+ uint32_t par3 = (*echo_energy_stored);
+ int16_t* ch_stored_p = &(aecm->channelStored[0]);
+ int16_t* ch_adapt_p = &(aecm->channelAdapt16[0]);
+ uint16_t* spectrum_p = (uint16_t*)(&(far_spectrum[0]));
+ int32_t* echo_p = &(echo_est[0]);
+ int32_t temp0, stored0, echo0, adept0, spectrum0;
+ int32_t stored1, adept1, spectrum1, echo1, temp1;
+
+ // Get energy for the delayed far end signal and estimated
+ // echo using both stored and adapted channels.
+ for (i = 0; i < PART_LEN; i += 4) {
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "lh %[stored0], 0(%[ch_stored_p]) \n\t"
+ "lhu %[adept0], 0(%[ch_adapt_p]) \n\t"
+ "lhu %[spectrum0], 0(%[spectrum_p]) \n\t"
+ "lh %[stored1], 2(%[ch_stored_p]) \n\t"
+ "lhu %[adept1], 2(%[ch_adapt_p]) \n\t"
+ "lhu %[spectrum1], 2(%[spectrum_p]) \n\t"
+ "mul %[echo0], %[stored0], %[spectrum0] \n\t"
+ "mul %[temp0], %[adept0], %[spectrum0] \n\t"
+ "mul %[echo1], %[stored1], %[spectrum1] \n\t"
+ "mul %[temp1], %[adept1], %[spectrum1] \n\t"
+ "addu %[par1], %[par1], %[spectrum0] \n\t"
+ "addu %[par1], %[par1], %[spectrum1] \n\t"
+ "addiu %[echo_p], %[echo_p], 16 \n\t"
+ "addu %[par3], %[par3], %[echo0] \n\t"
+ "addu %[par2], %[par2], %[temp0] \n\t"
+ "addu %[par3], %[par3], %[echo1] \n\t"
+ "addu %[par2], %[par2], %[temp1] \n\t"
+ "usw %[echo0], -16(%[echo_p]) \n\t"
+ "usw %[echo1], -12(%[echo_p]) \n\t"
+ "lh %[stored0], 4(%[ch_stored_p]) \n\t"
+ "lhu %[adept0], 4(%[ch_adapt_p]) \n\t"
+ "lhu %[spectrum0], 4(%[spectrum_p]) \n\t"
+ "lh %[stored1], 6(%[ch_stored_p]) \n\t"
+ "lhu %[adept1], 6(%[ch_adapt_p]) \n\t"
+ "lhu %[spectrum1], 6(%[spectrum_p]) \n\t"
+ "mul %[echo0], %[stored0], %[spectrum0] \n\t"
+ "mul %[temp0], %[adept0], %[spectrum0] \n\t"
+ "mul %[echo1], %[stored1], %[spectrum1] \n\t"
+ "mul %[temp1], %[adept1], %[spectrum1] \n\t"
+ "addu %[par1], %[par1], %[spectrum0] \n\t"
+ "addu %[par1], %[par1], %[spectrum1] \n\t"
+ "addiu %[ch_stored_p], %[ch_stored_p], 8 \n\t"
+ "addiu %[ch_adapt_p], %[ch_adapt_p], 8 \n\t"
+ "addiu %[spectrum_p], %[spectrum_p], 8 \n\t"
+ "addu %[par3], %[par3], %[echo0] \n\t"
+ "addu %[par2], %[par2], %[temp0] \n\t"
+ "addu %[par3], %[par3], %[echo1] \n\t"
+ "addu %[par2], %[par2], %[temp1] \n\t"
+ "usw %[echo0], -8(%[echo_p]) \n\t"
+ "usw %[echo1], -4(%[echo_p]) \n\t"
+ ".set pop \n\t"
+ : [temp0] "=&r"(temp0), [stored0] "=&r"(stored0),
+ [adept0] "=&r"(adept0), [spectrum0] "=&r"(spectrum0),
+ [echo0] "=&r"(echo0), [echo_p] "+r"(echo_p), [par3] "+r"(par3),
+ [par1] "+r"(par1), [par2] "+r"(par2), [stored1] "=&r"(stored1),
+ [adept1] "=&r"(adept1), [echo1] "=&r"(echo1),
+ [spectrum1] "=&r"(spectrum1), [temp1] "=&r"(temp1),
+ [ch_stored_p] "+r"(ch_stored_p), [ch_adapt_p] "+r"(ch_adapt_p),
+ [spectrum_p] "+r"(spectrum_p)
+ :
+ : "hi", "lo", "memory");
+ }
+
+ echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN],
+ far_spectrum[PART_LEN]);
+ par1 += (uint32_t)(far_spectrum[PART_LEN]);
+ par2 += aecm->channelAdapt16[PART_LEN] * far_spectrum[PART_LEN];
+ par3 += (uint32_t)echo_est[PART_LEN];
+
+ (*far_energy) = par1;
+ (*echo_energy_adapt) = par2;
+ (*echo_energy_stored) = par3;
+}
+
+#if defined(MIPS_DSP_R1_LE)
+void WebRtcAecm_StoreAdaptiveChannel_mips(AecmCore* aecm,
+ const uint16_t* far_spectrum,
+ int32_t* echo_est) {
+ int i;
+ int16_t* temp1;
+ uint16_t* temp8;
+ int32_t temp0, temp2, temp3, temp4, temp5, temp6;
+ int32_t* temp7 = &(echo_est[0]);
+ temp1 = &(aecm->channelStored[0]);
+ temp8 = (uint16_t*)(&far_spectrum[0]);
+
+ // During startup we store the channel every block.
+ memcpy(aecm->channelStored, aecm->channelAdapt16,
+ sizeof(int16_t) * PART_LEN1);
+ // Recalculate echo estimate
+ for (i = 0; i < PART_LEN; i += 4) {
+ __asm __volatile(
+ "ulw %[temp0], 0(%[temp8]) \n\t"
+ "ulw %[temp2], 0(%[temp1]) \n\t"
+ "ulw %[temp4], 4(%[temp8]) \n\t"
+ "ulw %[temp5], 4(%[temp1]) \n\t"
+ "muleq_s.w.phl %[temp3], %[temp2], %[temp0] \n\t"
+ "muleq_s.w.phr %[temp0], %[temp2], %[temp0] \n\t"
+ "muleq_s.w.phl %[temp6], %[temp5], %[temp4] \n\t"
+ "muleq_s.w.phr %[temp4], %[temp5], %[temp4] \n\t"
+ "addiu %[temp7], %[temp7], 16 \n\t"
+ "addiu %[temp1], %[temp1], 8 \n\t"
+ "addiu %[temp8], %[temp8], 8 \n\t"
+ "sra %[temp3], %[temp3], 1 \n\t"
+ "sra %[temp0], %[temp0], 1 \n\t"
+ "sra %[temp6], %[temp6], 1 \n\t"
+ "sra %[temp4], %[temp4], 1 \n\t"
+ "usw %[temp3], -12(%[temp7]) \n\t"
+ "usw %[temp0], -16(%[temp7]) \n\t"
+ "usw %[temp6], -4(%[temp7]) \n\t"
+ "usw %[temp4], -8(%[temp7]) \n\t"
+ : [temp0] "=&r"(temp0), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3),
+ [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [temp6] "=&r"(temp6),
+ [temp1] "+r"(temp1), [temp8] "+r"(temp8), [temp7] "+r"(temp7)
+ :
+ : "hi", "lo", "memory");
+ }
+ echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
+}
+
+void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm) {
+ int i;
+ int32_t* temp3;
+ int16_t* temp0;
+ int32_t temp1, temp2, temp4, temp5;
+
+ temp0 = &(aecm->channelStored[0]);
+ temp3 = &(aecm->channelAdapt32[0]);
+
+ // The stored channel has a significantly lower MSE than the adaptive one for
+ // two consecutive calculations. Reset the adaptive channel.
+ memcpy(aecm->channelAdapt16, aecm->channelStored,
+ sizeof(int16_t) * PART_LEN1);
+
+ // Restore the W32 channel
+ for (i = 0; i < PART_LEN; i += 4) {
+ __asm __volatile(
+ "ulw %[temp1], 0(%[temp0]) \n\t"
+ "ulw %[temp4], 4(%[temp0]) \n\t"
+ "preceq.w.phl %[temp2], %[temp1] \n\t"
+ "preceq.w.phr %[temp1], %[temp1] \n\t"
+ "preceq.w.phl %[temp5], %[temp4] \n\t"
+ "preceq.w.phr %[temp4], %[temp4] \n\t"
+ "addiu %[temp0], %[temp0], 8 \n\t"
+ "usw %[temp2], 4(%[temp3]) \n\t"
+ "usw %[temp1], 0(%[temp3]) \n\t"
+ "usw %[temp5], 12(%[temp3]) \n\t"
+ "usw %[temp4], 8(%[temp3]) \n\t"
+ "addiu %[temp3], %[temp3], 16 \n\t"
+ : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp4] "=&r"(temp4),
+ [temp5] "=&r"(temp5), [temp3] "+r"(temp3), [temp0] "+r"(temp0)
+ :
+ : "memory");
+ }
+
+ aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
+}
+#endif // #if defined(MIPS_DSP_R1_LE)
+
+// Transforms a time domain signal into the frequency domain, outputting the
+// complex valued signal, absolute value and sum of absolute values.
+//
+// time_signal [in] Pointer to time domain signal
+// freq_signal_real [out] Pointer to real part of frequency domain array
+// freq_signal_imag [out] Pointer to imaginary part of frequency domain
+// array
+// freq_signal_abs [out] Pointer to absolute value of frequency domain
+// array
+// freq_signal_sum_abs [out] Pointer to the sum of all absolute values in
+// the frequency domain array
+// return value The Q-domain of current frequency values
+//
+static int TimeToFrequencyDomain(AecmCore* aecm,
+ const int16_t* time_signal,
+ ComplexInt16* freq_signal,
+ uint16_t* freq_signal_abs,
+ uint32_t* freq_signal_sum_abs) {
+ int i = 0;
+ int time_signal_scaling = 0;
+
+ // In fft_buf, +16 for 32-byte alignment.
+ int16_t fft_buf[PART_LEN4 + 16];
+ int16_t* fft = (int16_t*)(((uintptr_t)fft_buf + 31) & ~31);
+
+ int16_t tmp16no1;
+#if !defined(MIPS_DSP_R2_LE)
+ int32_t tmp32no1;
+ int32_t tmp32no2;
+ int16_t tmp16no2;
+#else
+ int32_t tmp32no10, tmp32no11, tmp32no12, tmp32no13;
+ int32_t tmp32no20, tmp32no21, tmp32no22, tmp32no23;
+ int16_t* freqp;
+ uint16_t* freqabsp;
+ uint32_t freqt0, freqt1, freqt2, freqt3;
+ uint32_t freqs;
+#endif
+
+#ifdef AECM_DYNAMIC_Q
+ tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2);
+ time_signal_scaling = WebRtcSpl_NormW16(tmp16no1);
+#endif
+
+ WindowAndFFT(aecm, fft, time_signal, freq_signal, time_signal_scaling);
+
+ // Extract imaginary and real part,
+ // calculate the magnitude for all frequency bins
+ freq_signal[0].imag = 0;
+ freq_signal[PART_LEN].imag = 0;
+ freq_signal[PART_LEN].real = fft[PART_LEN2];
+ freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real);
+ freq_signal_abs[PART_LEN] =
+ (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[PART_LEN].real);
+ (*freq_signal_sum_abs) =
+ (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]);
+
+#if !defined(MIPS_DSP_R2_LE)
+ for (i = 1; i < PART_LEN; i++) {
+ if (freq_signal[i].real == 0) {
+ freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
+ } else if (freq_signal[i].imag == 0) {
+ freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].real);
+ } else {
+ // Approximation for magnitude of complex fft output
+ // magn = sqrt(real^2 + imag^2)
+ // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
+ //
+ // The parameters alpha and beta are stored in Q15
+ tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
+ tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
+ tmp32no1 = tmp16no1 * tmp16no1;
+ tmp32no2 = tmp16no2 * tmp16no2;
+ tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2);
+ tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2);
+
+ freq_signal_abs[i] = (uint16_t)tmp32no1;
+ }
+ (*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i];
+ }
+#else // #if !defined(MIPS_DSP_R2_LE)
+ freqs =
+ (uint32_t)(freq_signal_abs[0]) + (uint32_t)(freq_signal_abs[PART_LEN]);
+ freqp = &(freq_signal[1].real);
+
+ __asm __volatile(
+ "lw %[freqt0], 0(%[freqp]) \n\t"
+ "lw %[freqt1], 4(%[freqp]) \n\t"
+ "lw %[freqt2], 8(%[freqp]) \n\t"
+ "mult $ac0, $zero, $zero \n\t"
+ "mult $ac1, $zero, $zero \n\t"
+ "mult $ac2, $zero, $zero \n\t"
+ "dpaq_s.w.ph $ac0, %[freqt0], %[freqt0] \n\t"
+ "dpaq_s.w.ph $ac1, %[freqt1], %[freqt1] \n\t"
+ "dpaq_s.w.ph $ac2, %[freqt2], %[freqt2] \n\t"
+ "addiu %[freqp], %[freqp], 12 \n\t"
+ "extr.w %[tmp32no20], $ac0, 1 \n\t"
+ "extr.w %[tmp32no21], $ac1, 1 \n\t"
+ "extr.w %[tmp32no22], $ac2, 1 \n\t"
+ : [freqt0] "=&r"(freqt0), [freqt1] "=&r"(freqt1), [freqt2] "=&r"(freqt2),
+ [freqp] "+r"(freqp), [tmp32no20] "=r"(tmp32no20),
+ [tmp32no21] "=r"(tmp32no21), [tmp32no22] "=r"(tmp32no22)
+ :
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo");
+
+ tmp32no10 = WebRtcSpl_SqrtFloor(tmp32no20);
+ tmp32no11 = WebRtcSpl_SqrtFloor(tmp32no21);
+ tmp32no12 = WebRtcSpl_SqrtFloor(tmp32no22);
+ freq_signal_abs[1] = (uint16_t)tmp32no10;
+ freq_signal_abs[2] = (uint16_t)tmp32no11;
+ freq_signal_abs[3] = (uint16_t)tmp32no12;
+ freqs += (uint32_t)tmp32no10;
+ freqs += (uint32_t)tmp32no11;
+ freqs += (uint32_t)tmp32no12;
+ freqabsp = &(freq_signal_abs[4]);
+ for (i = 4; i < PART_LEN; i += 4) {
+ __asm __volatile(
+ "ulw %[freqt0], 0(%[freqp]) \n\t"
+ "ulw %[freqt1], 4(%[freqp]) \n\t"
+ "ulw %[freqt2], 8(%[freqp]) \n\t"
+ "ulw %[freqt3], 12(%[freqp]) \n\t"
+ "mult $ac0, $zero, $zero \n\t"
+ "mult $ac1, $zero, $zero \n\t"
+ "mult $ac2, $zero, $zero \n\t"
+ "mult $ac3, $zero, $zero \n\t"
+ "dpaq_s.w.ph $ac0, %[freqt0], %[freqt0] \n\t"
+ "dpaq_s.w.ph $ac1, %[freqt1], %[freqt1] \n\t"
+ "dpaq_s.w.ph $ac2, %[freqt2], %[freqt2] \n\t"
+ "dpaq_s.w.ph $ac3, %[freqt3], %[freqt3] \n\t"
+ "addiu %[freqp], %[freqp], 16 \n\t"
+ "addiu %[freqabsp], %[freqabsp], 8 \n\t"
+ "extr.w %[tmp32no20], $ac0, 1 \n\t"
+ "extr.w %[tmp32no21], $ac1, 1 \n\t"
+ "extr.w %[tmp32no22], $ac2, 1 \n\t"
+ "extr.w %[tmp32no23], $ac3, 1 \n\t"
+ : [freqt0] "=&r"(freqt0), [freqt1] "=&r"(freqt1),
+ [freqt2] "=&r"(freqt2), [freqt3] "=&r"(freqt3),
+ [tmp32no20] "=r"(tmp32no20), [tmp32no21] "=r"(tmp32no21),
+ [tmp32no22] "=r"(tmp32no22), [tmp32no23] "=r"(tmp32no23),
+ [freqabsp] "+r"(freqabsp), [freqp] "+r"(freqp)
+ :
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo",
+ "$ac3hi", "$ac3lo");
+
+ tmp32no10 = WebRtcSpl_SqrtFloor(tmp32no20);
+ tmp32no11 = WebRtcSpl_SqrtFloor(tmp32no21);
+ tmp32no12 = WebRtcSpl_SqrtFloor(tmp32no22);
+ tmp32no13 = WebRtcSpl_SqrtFloor(tmp32no23);
+
+ __asm __volatile(
+ "sh %[tmp32no10], -8(%[freqabsp]) \n\t"
+ "sh %[tmp32no11], -6(%[freqabsp]) \n\t"
+ "sh %[tmp32no12], -4(%[freqabsp]) \n\t"
+ "sh %[tmp32no13], -2(%[freqabsp]) \n\t"
+ "addu %[freqs], %[freqs], %[tmp32no10] \n\t"
+ "addu %[freqs], %[freqs], %[tmp32no11] \n\t"
+ "addu %[freqs], %[freqs], %[tmp32no12] \n\t"
+ "addu %[freqs], %[freqs], %[tmp32no13] \n\t"
+ : [freqs] "+r"(freqs)
+ : [tmp32no10] "r"(tmp32no10), [tmp32no11] "r"(tmp32no11),
+ [tmp32no12] "r"(tmp32no12), [tmp32no13] "r"(tmp32no13),
+ [freqabsp] "r"(freqabsp)
+ : "memory");
+ }
+
+ (*freq_signal_sum_abs) = freqs;
+#endif
+
+ return time_signal_scaling;
+}
+
+int WebRtcAecm_ProcessBlock(AecmCore* aecm,
+ const int16_t* farend,
+ const int16_t* nearendNoisy,
+ const int16_t* nearendClean,
+ int16_t* output) {
+ int i;
+ uint32_t xfaSum;
+ uint32_t dfaNoisySum;
+ uint32_t dfaCleanSum;
+ uint32_t echoEst32Gained;
+ uint32_t tmpU32;
+ int32_t tmp32no1;
+
+ uint16_t xfa[PART_LEN1];
+ uint16_t dfaNoisy[PART_LEN1];
+ uint16_t dfaClean[PART_LEN1];
+ uint16_t* ptrDfaClean = dfaClean;
+ const uint16_t* far_spectrum_ptr = NULL;
+
+ // 32 byte aligned buffers (with +8 or +16).
+ int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
+ int32_t echoEst32_buf[PART_LEN1 + 8];
+ int32_t dfw_buf[PART_LEN2 + 8];
+ int32_t efw_buf[PART_LEN2 + 8];
+
+ int16_t* fft = (int16_t*)(((uint32_t)fft_buf + 31) & ~31);
+ int32_t* echoEst32 = (int32_t*)(((uint32_t)echoEst32_buf + 31) & ~31);
+ ComplexInt16* dfw = (ComplexInt16*)(((uint32_t)dfw_buf + 31) & ~31);
+ ComplexInt16* efw = (ComplexInt16*)(((uint32_t)efw_buf + 31) & ~31);
+
+ int16_t hnl[PART_LEN1];
+ int16_t numPosCoef = 0;
+ int delay;
+ int16_t tmp16no1;
+ int16_t tmp16no2;
+ int16_t mu;
+ int16_t supGain;
+ int16_t zeros32, zeros16;
+ int16_t zerosDBufNoisy, zerosDBufClean, zerosXBuf;
+ int far_q;
+ int16_t resolutionDiff, qDomainDiff, dfa_clean_q_domain_diff;
+
+ const int kMinPrefBand = 4;
+ const int kMaxPrefBand = 24;
+ int32_t avgHnl32 = 0;
+
+ int32_t temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+ int16_t* ptr;
+ int16_t* ptr1;
+ int16_t* er_ptr;
+ int16_t* dr_ptr;
+
+ ptr = &hnl[0];
+ ptr1 = &hnl[0];
+ er_ptr = &efw[0].real;
+ dr_ptr = &dfw[0].real;
+
+ // Determine startup state. There are three states:
+ // (0) the first CONV_LEN blocks
+ // (1) another CONV_LEN blocks
+ // (2) the rest
+
+ if (aecm->startupState < 2) {
+ aecm->startupState =
+ (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2);
+ }
+ // END: Determine startup state
+
+ // Buffer near and far end signals
+ memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN);
+ memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN);
+ if (nearendClean != NULL) {
+ memcpy(aecm->dBufClean + PART_LEN, nearendClean,
+ sizeof(int16_t) * PART_LEN);
+ }
+
+ // Transform far end signal from time domain to frequency domain.
+ far_q = TimeToFrequencyDomain(aecm, aecm->xBuf, dfw, xfa, &xfaSum);
+
+ // Transform noisy near end signal from time domain to frequency domain.
+ zerosDBufNoisy =
+ TimeToFrequencyDomain(aecm, aecm->dBufNoisy, dfw, dfaNoisy, &dfaNoisySum);
+ aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
+ aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy;
+
+ if (nearendClean == NULL) {
+ ptrDfaClean = dfaNoisy;
+ aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
+ aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
+ dfaCleanSum = dfaNoisySum;
+ } else {
+ // Transform clean near end signal from time domain to frequency domain.
+ zerosDBufClean = TimeToFrequencyDomain(aecm, aecm->dBufClean, dfw, dfaClean,
+ &dfaCleanSum);
+ aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
+ aecm->dfaCleanQDomain = (int16_t)zerosDBufClean;
+ }
+
+ // Get the delay
+ // Save far-end history and estimate delay
+ WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q);
+
+ if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend, xfa, PART_LEN1,
+ far_q) == -1) {
+ return -1;
+ }
+ delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, dfaNoisy,
+ PART_LEN1, zerosDBufNoisy);
+ if (delay == -1) {
+ return -1;
+ } else if (delay == -2) {
+ // If the delay is unknown, we assume zero.
+ // NOTE: this will have to be adjusted if we ever add lookahead.
+ delay = 0;
+ }
+
+ if (aecm->fixedDelay >= 0) {
+ // Use fixed delay
+ delay = aecm->fixedDelay;
+ }
+
+ // Get aligned far end spectrum
+ far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay);
+ zerosXBuf = (int16_t)far_q;
+
+ if (far_spectrum_ptr == NULL) {
+ return -1;
+ }
+
+ // Calculate log(energy) and update energy threshold levels
+ WebRtcAecm_CalcEnergies(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisySum,
+ echoEst32);
+ // Calculate stepsize
+ mu = WebRtcAecm_CalcStepSize(aecm);
+
+ // Update counters
+ aecm->totCount++;
+
+ // This is the channel estimation algorithm.
+ // It is base on NLMS but has a variable step length,
+ // which was calculated above.
+ WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu,
+ echoEst32);
+
+ supGain = WebRtcAecm_CalcSuppressionGain(aecm);
+
+ // Calculate Wiener filter hnl[]
+ for (i = 0; i < PART_LEN1; i++) {
+ // Far end signal through channel estimate in Q8
+ // How much can we shift right to preserve resolution
+ tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
+ aecm->echoFilt[i] +=
+ rtc::dchecked_cast<int32_t>((int64_t{tmp32no1} * 50) >> 8);
+
+ zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
+ zeros16 = WebRtcSpl_NormW16(supGain) + 1;
+ if (zeros32 + zeros16 > 16) {
+ // Multiplication is safe
+ // Result in
+ // Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff])
+ echoEst32Gained =
+ WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i], (uint16_t)supGain);
+ resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
+ resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
+ } else {
+ tmp16no1 = 17 - zeros32 - zeros16;
+ resolutionDiff =
+ 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
+ resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
+ if (zeros32 > tmp16no1) {
+ echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
+ supGain >> tmp16no1);
+ } else {
+ // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
+ echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain;
+ }
+ }
+
+ zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]);
+ RTC_DCHECK_GE(zeros16, 0); // |zeros16| is a norm, hence non-negative.
+ dfa_clean_q_domain_diff = aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld;
+ if (zeros16 < dfa_clean_q_domain_diff && aecm->nearFilt[i]) {
+ tmp16no1 = aecm->nearFilt[i] << zeros16;
+ qDomainDiff = zeros16 - dfa_clean_q_domain_diff;
+ tmp16no2 = ptrDfaClean[i] >> -qDomainDiff;
+ } else {
+ tmp16no1 = dfa_clean_q_domain_diff < 0
+ ? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff
+ : aecm->nearFilt[i] << dfa_clean_q_domain_diff;
+ qDomainDiff = 0;
+ tmp16no2 = ptrDfaClean[i];
+ }
+
+ tmp32no1 = (int32_t)(tmp16no2 - tmp16no1);
+ tmp16no2 = (int16_t)(tmp32no1 >> 4);
+ tmp16no2 += tmp16no1;
+ zeros16 = WebRtcSpl_NormW16(tmp16no2);
+ if ((tmp16no2) & (-qDomainDiff > zeros16)) {
+ aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
+ } else {
+ aecm->nearFilt[i] =
+ qDomainDiff < 0 ? tmp16no2 << -qDomainDiff : tmp16no2 >> qDomainDiff;
+ }
+
+ // Wiener filter coefficients, resulting hnl in Q14
+ if (echoEst32Gained == 0) {
+ hnl[i] = ONE_Q14;
+ numPosCoef++;
+ } else if (aecm->nearFilt[i] == 0) {
+ hnl[i] = 0;
+ } else {
+ // Multiply the suppression gain
+ // Rounding
+ echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1);
+ tmpU32 =
+ WebRtcSpl_DivU32U16(echoEst32Gained, (uint16_t)aecm->nearFilt[i]);
+
+ // Current resolution is
+ // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN
+ // - max(0, 17 - zeros16 - zeros32))
+ // Make sure we are in Q14
+ tmp32no1 = (int32_t)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
+ if (tmp32no1 > ONE_Q14) {
+ hnl[i] = 0;
+ } else if (tmp32no1 < 0) {
+ hnl[i] = ONE_Q14;
+ numPosCoef++;
+ } else {
+ // 1-echoEst/dfa
+ hnl[i] = ONE_Q14 - (int16_t)tmp32no1;
+ if (hnl[i] <= 0) {
+ hnl[i] = 0;
+ } else {
+ numPosCoef++;
+ }
+ }
+ }
+ }
+
+ // Only in wideband. Prevent the gain in upper band from being larger than
+ // in lower band.
+ if (aecm->mult == 2) {
+ // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
+ // speech distortion in double-talk.
+ for (i = 0; i < (PART_LEN1 >> 3); i++) {
+ __asm __volatile(
+ "lh %[temp1], 0(%[ptr1]) \n\t"
+ "lh %[temp2], 2(%[ptr1]) \n\t"
+ "lh %[temp3], 4(%[ptr1]) \n\t"
+ "lh %[temp4], 6(%[ptr1]) \n\t"
+ "lh %[temp5], 8(%[ptr1]) \n\t"
+ "lh %[temp6], 10(%[ptr1]) \n\t"
+ "lh %[temp7], 12(%[ptr1]) \n\t"
+ "lh %[temp8], 14(%[ptr1]) \n\t"
+ "mul %[temp1], %[temp1], %[temp1] \n\t"
+ "mul %[temp2], %[temp2], %[temp2] \n\t"
+ "mul %[temp3], %[temp3], %[temp3] \n\t"
+ "mul %[temp4], %[temp4], %[temp4] \n\t"
+ "mul %[temp5], %[temp5], %[temp5] \n\t"
+ "mul %[temp6], %[temp6], %[temp6] \n\t"
+ "mul %[temp7], %[temp7], %[temp7] \n\t"
+ "mul %[temp8], %[temp8], %[temp8] \n\t"
+ "sra %[temp1], %[temp1], 14 \n\t"
+ "sra %[temp2], %[temp2], 14 \n\t"
+ "sra %[temp3], %[temp3], 14 \n\t"
+ "sra %[temp4], %[temp4], 14 \n\t"
+ "sra %[temp5], %[temp5], 14 \n\t"
+ "sra %[temp6], %[temp6], 14 \n\t"
+ "sra %[temp7], %[temp7], 14 \n\t"
+ "sra %[temp8], %[temp8], 14 \n\t"
+ "sh %[temp1], 0(%[ptr1]) \n\t"
+ "sh %[temp2], 2(%[ptr1]) \n\t"
+ "sh %[temp3], 4(%[ptr1]) \n\t"
+ "sh %[temp4], 6(%[ptr1]) \n\t"
+ "sh %[temp5], 8(%[ptr1]) \n\t"
+ "sh %[temp6], 10(%[ptr1]) \n\t"
+ "sh %[temp7], 12(%[ptr1]) \n\t"
+ "sh %[temp8], 14(%[ptr1]) \n\t"
+ "addiu %[ptr1], %[ptr1], 16 \n\t"
+ : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3),
+ [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [temp6] "=&r"(temp6),
+ [temp7] "=&r"(temp7), [temp8] "=&r"(temp8), [ptr1] "+r"(ptr1)
+ :
+ : "memory", "hi", "lo");
+ }
+ for (i = 0; i < (PART_LEN1 & 7); i++) {
+ __asm __volatile(
+ "lh %[temp1], 0(%[ptr1]) \n\t"
+ "mul %[temp1], %[temp1], %[temp1] \n\t"
+ "sra %[temp1], %[temp1], 14 \n\t"
+ "sh %[temp1], 0(%[ptr1]) \n\t"
+ "addiu %[ptr1], %[ptr1], 2 \n\t"
+ : [temp1] "=&r"(temp1), [ptr1] "+r"(ptr1)
+ :
+ : "memory", "hi", "lo");
+ }
+
+ for (i = kMinPrefBand; i <= kMaxPrefBand; i++) {
+ avgHnl32 += (int32_t)hnl[i];
+ }
+
+ RTC_DCHECK_GT(kMaxPrefBand - kMinPrefBand + 1, 0);
+ avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1);
+
+ for (i = kMaxPrefBand; i < PART_LEN1; i++) {
+ if (hnl[i] > (int16_t)avgHnl32) {
+ hnl[i] = (int16_t)avgHnl32;
+ }
+ }
+ }
+
+ // Calculate NLP gain, result is in Q14
+ if (aecm->nlpFlag) {
+ if (numPosCoef < 3) {
+ for (i = 0; i < PART_LEN1; i++) {
+ efw[i].real = 0;
+ efw[i].imag = 0;
+ hnl[i] = 0;
+ }
+ } else {
+ for (i = 0; i < PART_LEN1; i++) {
+#if defined(MIPS_DSP_R1_LE)
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "lh %[temp1], 0(%[ptr]) \n\t"
+ "lh %[temp2], 0(%[dr_ptr]) \n\t"
+ "slti %[temp4], %[temp1], 0x4001 \n\t"
+ "beqz %[temp4], 3f \n\t"
+ " lh %[temp3], 2(%[dr_ptr]) \n\t"
+ "slti %[temp5], %[temp1], 3277 \n\t"
+ "bnez %[temp5], 2f \n\t"
+ " addiu %[dr_ptr], %[dr_ptr], 4 \n\t"
+ "mul %[temp2], %[temp2], %[temp1] \n\t"
+ "mul %[temp3], %[temp3], %[temp1] \n\t"
+ "shra_r.w %[temp2], %[temp2], 14 \n\t"
+ "shra_r.w %[temp3], %[temp3], 14 \n\t"
+ "b 4f \n\t"
+ " nop \n\t"
+ "2: \n\t"
+ "addu %[temp1], $zero, $zero \n\t"
+ "addu %[temp2], $zero, $zero \n\t"
+ "addu %[temp3], $zero, $zero \n\t"
+ "b 1f \n\t"
+ " nop \n\t"
+ "3: \n\t"
+ "addiu %[temp1], $0, 0x4000 \n\t"
+ "1: \n\t"
+ "sh %[temp1], 0(%[ptr]) \n\t"
+ "4: \n\t"
+ "sh %[temp2], 0(%[er_ptr]) \n\t"
+ "sh %[temp3], 2(%[er_ptr]) \n\t"
+ "addiu %[ptr], %[ptr], 2 \n\t"
+ "addiu %[er_ptr], %[er_ptr], 4 \n\t"
+ ".set pop \n\t"
+ : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3),
+ [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [ptr] "+r"(ptr),
+ [er_ptr] "+r"(er_ptr), [dr_ptr] "+r"(dr_ptr)
+ :
+ : "memory", "hi", "lo");
+#else
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "lh %[temp1], 0(%[ptr]) \n\t"
+ "lh %[temp2], 0(%[dr_ptr]) \n\t"
+ "slti %[temp4], %[temp1], 0x4001 \n\t"
+ "beqz %[temp4], 3f \n\t"
+ " lh %[temp3], 2(%[dr_ptr]) \n\t"
+ "slti %[temp5], %[temp1], 3277 \n\t"
+ "bnez %[temp5], 2f \n\t"
+ " addiu %[dr_ptr], %[dr_ptr], 4 \n\t"
+ "mul %[temp2], %[temp2], %[temp1] \n\t"
+ "mul %[temp3], %[temp3], %[temp1] \n\t"
+ "addiu %[temp2], %[temp2], 0x2000 \n\t"
+ "addiu %[temp3], %[temp3], 0x2000 \n\t"
+ "sra %[temp2], %[temp2], 14 \n\t"
+ "sra %[temp3], %[temp3], 14 \n\t"
+ "b 4f \n\t"
+ " nop \n\t"
+ "2: \n\t"
+ "addu %[temp1], $zero, $zero \n\t"
+ "addu %[temp2], $zero, $zero \n\t"
+ "addu %[temp3], $zero, $zero \n\t"
+ "b 1f \n\t"
+ " nop \n\t"
+ "3: \n\t"
+ "addiu %[temp1], $0, 0x4000 \n\t"
+ "1: \n\t"
+ "sh %[temp1], 0(%[ptr]) \n\t"
+ "4: \n\t"
+ "sh %[temp2], 0(%[er_ptr]) \n\t"
+ "sh %[temp3], 2(%[er_ptr]) \n\t"
+ "addiu %[ptr], %[ptr], 2 \n\t"
+ "addiu %[er_ptr], %[er_ptr], 4 \n\t"
+ ".set pop \n\t"
+ : [temp1] "=&r"(temp1), [temp2] "=&r"(temp2), [temp3] "=&r"(temp3),
+ [temp4] "=&r"(temp4), [temp5] "=&r"(temp5), [ptr] "+r"(ptr),
+ [er_ptr] "+r"(er_ptr), [dr_ptr] "+r"(dr_ptr)
+ :
+ : "memory", "hi", "lo");
+#endif
+ }
+ }
+ } else {
+ // multiply with Wiener coefficients
+ for (i = 0; i < PART_LEN1; i++) {
+ efw[i].real = (int16_t)(
+ WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, hnl[i], 14));
+ efw[i].imag = (int16_t)(
+ WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, hnl[i], 14));
+ }
+ }
+
+ if (aecm->cngMode == AecmTrue) {
+ ComfortNoise(aecm, ptrDfaClean, efw, hnl);
+ }
+
+ InverseFFTAndWindow(aecm, fft, efw, output, nearendClean);
+
+ return 0;
+}
+
+// Generate comfort noise and add to output signal.
+static void ComfortNoise(AecmCore* aecm,
+ const uint16_t* dfa,
+ ComplexInt16* out,
+ const int16_t* lambda) {
+ int16_t i;
+ int16_t tmp16, tmp161, tmp162, tmp163, nrsh1, nrsh2;
+ int32_t tmp32, tmp321, tnoise, tnoise1;
+ int32_t tmp322, tmp323, *tmp1;
+ int16_t* dfap;
+ int16_t* lambdap;
+ const int32_t c2049 = 2049;
+ const int32_t c359 = 359;
+ const int32_t c114 = ONE_Q14;
+
+ int16_t randW16[PART_LEN];
+ int16_t uReal[PART_LEN1];
+ int16_t uImag[PART_LEN1];
+ int32_t outLShift32;
+
+ int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
+ int16_t minTrackShift = 9;
+
+ RTC_DCHECK_GE(shiftFromNearToNoise, 0);
+ RTC_DCHECK_LT(shiftFromNearToNoise, 16);
+
+ if (aecm->noiseEstCtr < 100) {
+ // Track the minimum more quickly initially.
+ aecm->noiseEstCtr++;
+ minTrackShift = 6;
+ }
+
+ // Generate a uniform random array on [0 2^15-1].
+ WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
+ int16_t* randW16p = (int16_t*)randW16;
+#if defined(MIPS_DSP_R1_LE)
+ int16_t* kCosTablep = (int16_t*)WebRtcAecm_kCosTable;
+ int16_t* kSinTablep = (int16_t*)WebRtcAecm_kSinTable;
+#endif // #if defined(MIPS_DSP_R1_LE)
+ tmp1 = (int32_t*)aecm->noiseEst + 1;
+ dfap = (int16_t*)dfa + 1;
+ lambdap = (int16_t*)lambda + 1;
+ // Estimate noise power.
+ for (i = 1; i < PART_LEN1; i += 2) {
+ // Shift to the noise domain.
+ __asm __volatile(
+ "lh %[tmp32], 0(%[dfap]) \n\t"
+ "lw %[tnoise], 0(%[tmp1]) \n\t"
+ "sllv %[outLShift32], %[tmp32], %[shiftFromNearToNoise] \n\t"
+ : [tmp32] "=&r"(tmp32), [outLShift32] "=r"(outLShift32),
+ [tnoise] "=&r"(tnoise)
+ : [tmp1] "r"(tmp1), [dfap] "r"(dfap),
+ [shiftFromNearToNoise] "r"(shiftFromNearToNoise)
+ : "memory");
+
+ if (outLShift32 < tnoise) {
+ // Reset "too low" counter
+ aecm->noiseEstTooLowCtr[i] = 0;
+ // Track the minimum.
+ if (tnoise < (1 << minTrackShift)) {
+ // For small values, decrease noiseEst[i] every
+ // |kNoiseEstIncCount| block. The regular approach below can not
+ // go further down due to truncation.
+ aecm->noiseEstTooHighCtr[i]++;
+ if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) {
+ tnoise--;
+ aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
+ }
+ } else {
+ __asm __volatile(
+ "subu %[tmp32], %[tnoise], %[outLShift32] \n\t"
+ "srav %[tmp32], %[tmp32], %[minTrackShift] \n\t"
+ "subu %[tnoise], %[tnoise], %[tmp32] \n\t"
+ : [tmp32] "=&r"(tmp32), [tnoise] "+r"(tnoise)
+ :
+ [outLShift32] "r"(outLShift32), [minTrackShift] "r"(minTrackShift));
+ }
+ } else {
+ // Reset "too high" counter
+ aecm->noiseEstTooHighCtr[i] = 0;
+ // Ramp slowly upwards until we hit the minimum again.
+ if ((tnoise >> 19) <= 0) {
+ if ((tnoise >> 11) > 0) {
+ // Large enough for relative increase
+ __asm __volatile(
+ "mul %[tnoise], %[tnoise], %[c2049] \n\t"
+ "sra %[tnoise], %[tnoise], 11 \n\t"
+ : [tnoise] "+r"(tnoise)
+ : [c2049] "r"(c2049)
+ : "hi", "lo");
+ } else {
+ // Make incremental increases based on size every
+ // |kNoiseEstIncCount| block
+ aecm->noiseEstTooLowCtr[i]++;
+ if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) {
+ __asm __volatile(
+ "sra %[tmp32], %[tnoise], 9 \n\t"
+ "addi %[tnoise], %[tnoise], 1 \n\t"
+ "addu %[tnoise], %[tnoise], %[tmp32] \n\t"
+ : [tnoise] "+r"(tnoise), [tmp32] "=&r"(tmp32)
+ :);
+ aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
+ }
+ }
+ } else {
+ // Avoid overflow.
+ // Multiplication with 2049 will cause wrap around. Scale
+ // down first and then multiply
+ __asm __volatile(
+ "sra %[tnoise], %[tnoise], 11 \n\t"
+ "mul %[tnoise], %[tnoise], %[c2049] \n\t"
+ : [tnoise] "+r"(tnoise)
+ : [c2049] "r"(c2049)
+ : "hi", "lo");
+ }
+ }
+
+ // Shift to the noise domain.
+ __asm __volatile(
+ "lh %[tmp32], 2(%[dfap]) \n\t"
+ "lw %[tnoise1], 4(%[tmp1]) \n\t"
+ "addiu %[dfap], %[dfap], 4 \n\t"
+ "sllv %[outLShift32], %[tmp32], %[shiftFromNearToNoise] \n\t"
+ : [tmp32] "=&r"(tmp32), [dfap] "+r"(dfap),
+ [outLShift32] "=r"(outLShift32), [tnoise1] "=&r"(tnoise1)
+ : [tmp1] "r"(tmp1), [shiftFromNearToNoise] "r"(shiftFromNearToNoise)
+ : "memory");
+
+ if (outLShift32 < tnoise1) {
+ // Reset "too low" counter
+ aecm->noiseEstTooLowCtr[i + 1] = 0;
+ // Track the minimum.
+ if (tnoise1 < (1 << minTrackShift)) {
+ // For small values, decrease noiseEst[i] every
+ // |kNoiseEstIncCount| block. The regular approach below can not
+ // go further down due to truncation.
+ aecm->noiseEstTooHighCtr[i + 1]++;
+ if (aecm->noiseEstTooHighCtr[i + 1] >= kNoiseEstIncCount) {
+ tnoise1--;
+ aecm->noiseEstTooHighCtr[i + 1] = 0; // Reset the counter
+ }
+ } else {
+ __asm __volatile(
+ "subu %[tmp32], %[tnoise1], %[outLShift32] \n\t"
+ "srav %[tmp32], %[tmp32], %[minTrackShift] \n\t"
+ "subu %[tnoise1], %[tnoise1], %[tmp32] \n\t"
+ : [tmp32] "=&r"(tmp32), [tnoise1] "+r"(tnoise1)
+ :
+ [outLShift32] "r"(outLShift32), [minTrackShift] "r"(minTrackShift));
+ }
+ } else {
+ // Reset "too high" counter
+ aecm->noiseEstTooHighCtr[i + 1] = 0;
+ // Ramp slowly upwards until we hit the minimum again.
+ if ((tnoise1 >> 19) <= 0) {
+ if ((tnoise1 >> 11) > 0) {
+ // Large enough for relative increase
+ __asm __volatile(
+ "mul %[tnoise1], %[tnoise1], %[c2049] \n\t"
+ "sra %[tnoise1], %[tnoise1], 11 \n\t"
+ : [tnoise1] "+r"(tnoise1)
+ : [c2049] "r"(c2049)
+ : "hi", "lo");
+ } else {
+ // Make incremental increases based on size every
+ // |kNoiseEstIncCount| block
+ aecm->noiseEstTooLowCtr[i + 1]++;
+ if (aecm->noiseEstTooLowCtr[i + 1] >= kNoiseEstIncCount) {
+ __asm __volatile(
+ "sra %[tmp32], %[tnoise1], 9 \n\t"
+ "addi %[tnoise1], %[tnoise1], 1 \n\t"
+ "addu %[tnoise1], %[tnoise1], %[tmp32] \n\t"
+ : [tnoise1] "+r"(tnoise1), [tmp32] "=&r"(tmp32)
+ :);
+ aecm->noiseEstTooLowCtr[i + 1] = 0; // Reset counter
+ }
+ }
+ } else {
+ // Avoid overflow.
+ // Multiplication with 2049 will cause wrap around. Scale
+ // down first and then multiply
+ __asm __volatile(
+ "sra %[tnoise1], %[tnoise1], 11 \n\t"
+ "mul %[tnoise1], %[tnoise1], %[c2049] \n\t"
+ : [tnoise1] "+r"(tnoise1)
+ : [c2049] "r"(c2049)
+ : "hi", "lo");
+ }
+ }
+
+ __asm __volatile(
+ "lh %[tmp16], 0(%[lambdap]) \n\t"
+ "lh %[tmp161], 2(%[lambdap]) \n\t"
+ "sw %[tnoise], 0(%[tmp1]) \n\t"
+ "sw %[tnoise1], 4(%[tmp1]) \n\t"
+ "subu %[tmp16], %[c114], %[tmp16] \n\t"
+ "subu %[tmp161], %[c114], %[tmp161] \n\t"
+ "srav %[tmp32], %[tnoise], %[shiftFromNearToNoise] \n\t"
+ "srav %[tmp321], %[tnoise1], %[shiftFromNearToNoise] \n\t"
+ "addiu %[lambdap], %[lambdap], 4 \n\t"
+ "addiu %[tmp1], %[tmp1], 8 \n\t"
+ : [tmp16] "=&r"(tmp16), [tmp161] "=&r"(tmp161), [tmp1] "+r"(tmp1),
+ [tmp32] "=&r"(tmp32), [tmp321] "=&r"(tmp321), [lambdap] "+r"(lambdap)
+ : [tnoise] "r"(tnoise), [tnoise1] "r"(tnoise1), [c114] "r"(c114),
+ [shiftFromNearToNoise] "r"(shiftFromNearToNoise)
+ : "memory");
+
+ if (tmp32 > 32767) {
+ tmp32 = 32767;
+ aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise;
+ }
+ if (tmp321 > 32767) {
+ tmp321 = 32767;
+ aecm->noiseEst[i + 1] = tmp321 << shiftFromNearToNoise;
+ }
+
+ __asm __volatile(
+ "mul %[tmp32], %[tmp32], %[tmp16] \n\t"
+ "mul %[tmp321], %[tmp321], %[tmp161] \n\t"
+ "sra %[nrsh1], %[tmp32], 14 \n\t"
+ "sra %[nrsh2], %[tmp321], 14 \n\t"
+ : [nrsh1] "=&r"(nrsh1), [nrsh2] "=r"(nrsh2)
+ : [tmp16] "r"(tmp16), [tmp161] "r"(tmp161), [tmp32] "r"(tmp32),
+ [tmp321] "r"(tmp321)
+ : "memory", "hi", "lo");
+
+ __asm __volatile(
+ "lh %[tmp32], 0(%[randW16p]) \n\t"
+ "lh %[tmp321], 2(%[randW16p]) \n\t"
+ "addiu %[randW16p], %[randW16p], 4 \n\t"
+ "mul %[tmp32], %[tmp32], %[c359] \n\t"
+ "mul %[tmp321], %[tmp321], %[c359] \n\t"
+ "sra %[tmp16], %[tmp32], 15 \n\t"
+ "sra %[tmp161], %[tmp321], 15 \n\t"
+ : [randW16p] "+r"(randW16p), [tmp32] "=&r"(tmp32), [tmp16] "=r"(tmp16),
+ [tmp161] "=r"(tmp161), [tmp321] "=&r"(tmp321)
+ : [c359] "r"(c359)
+ : "memory", "hi", "lo");
+
+#if !defined(MIPS_DSP_R1_LE)
+ tmp32 = WebRtcAecm_kCosTable[tmp16];
+ tmp321 = WebRtcAecm_kSinTable[tmp16];
+ tmp322 = WebRtcAecm_kCosTable[tmp161];
+ tmp323 = WebRtcAecm_kSinTable[tmp161];
+#else
+ __asm __volatile(
+ "sll %[tmp16], %[tmp16], 1 \n\t"
+ "sll %[tmp161], %[tmp161], 1 \n\t"
+ "lhx %[tmp32], %[tmp16](%[kCosTablep]) \n\t"
+ "lhx %[tmp321], %[tmp16](%[kSinTablep]) \n\t"
+ "lhx %[tmp322], %[tmp161](%[kCosTablep]) \n\t"
+ "lhx %[tmp323], %[tmp161](%[kSinTablep]) \n\t"
+ : [tmp32] "=&r"(tmp32), [tmp321] "=&r"(tmp321), [tmp322] "=&r"(tmp322),
+ [tmp323] "=&r"(tmp323)
+ : [kCosTablep] "r"(kCosTablep), [tmp16] "r"(tmp16),
+ [tmp161] "r"(tmp161), [kSinTablep] "r"(kSinTablep)
+ : "memory");
+#endif
+ __asm __volatile(
+ "mul %[tmp32], %[tmp32], %[nrsh1] \n\t"
+ "negu %[tmp162], %[nrsh1] \n\t"
+ "mul %[tmp322], %[tmp322], %[nrsh2] \n\t"
+ "negu %[tmp163], %[nrsh2] \n\t"
+ "sra %[tmp32], %[tmp32], 13 \n\t"
+ "mul %[tmp321], %[tmp321], %[tmp162] \n\t"
+ "sra %[tmp322], %[tmp322], 13 \n\t"
+ "mul %[tmp323], %[tmp323], %[tmp163] \n\t"
+ "sra %[tmp321], %[tmp321], 13 \n\t"
+ "sra %[tmp323], %[tmp323], 13 \n\t"
+ : [tmp32] "+r"(tmp32), [tmp321] "+r"(tmp321), [tmp162] "=&r"(tmp162),
+ [tmp322] "+r"(tmp322), [tmp323] "+r"(tmp323), [tmp163] "=&r"(tmp163)
+ : [nrsh1] "r"(nrsh1), [nrsh2] "r"(nrsh2)
+ : "hi", "lo");
+ // Tables are in Q13.
+ uReal[i] = (int16_t)tmp32;
+ uImag[i] = (int16_t)tmp321;
+ uReal[i + 1] = (int16_t)tmp322;
+ uImag[i + 1] = (int16_t)tmp323;
+ }
+
+ int32_t tt, sgn;
+ tt = out[0].real;
+ sgn = ((int)tt) >> 31;
+ out[0].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
+ tt = out[0].imag;
+ sgn = ((int)tt) >> 31;
+ out[0].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
+ for (i = 1; i < PART_LEN; i++) {
+ tt = out[i].real + uReal[i];
+ sgn = ((int)tt) >> 31;
+ out[i].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
+ tt = out[i].imag + uImag[i];
+ sgn = ((int)tt) >> 31;
+ out[i].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
+ }
+ tt = out[PART_LEN].real + uReal[PART_LEN];
+ sgn = ((int)tt) >> 31;
+ out[PART_LEN].real = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
+ tt = out[PART_LEN].imag;
+ sgn = ((int)tt) >> 31;
+ out[PART_LEN].imag = sgn == (int16_t)(tt >> 15) ? (int16_t)tt : (16384 ^ sgn);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aecm/aecm_core_neon.c b/webrtc/modules/audio_processing/aecm/aecm_core_neon.cc
index 1751fcf..584110d 100644
--- a/webrtc/modules/audio_processing/aecm/aecm_core_neon.c
+++ b/webrtc/modules/audio_processing/aecm/aecm_core_neon.cc
@@ -8,29 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
-
#include <arm_neon.h>
-#include <assert.h>
-#include "webrtc/common_audio/signal_processing/include/real_fft.h"
+#include "common_audio/signal_processing/include/real_fft.h"
+#include "modules/audio_processing/aecm/aecm_core.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
// TODO(kma): Re-write the corresponding assembly file, the offset
// generating script and makefile, to replace these C functions.
-// Square root of Hanning window in Q14.
-const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
- 0,
- 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
- 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224,
- 6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040,
- 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
- 11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553,
- 13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079,
- 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034,
- 16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384
-};
-
static inline void AddLanes(uint32_t* ptr, uint32x4_t v) {
#if defined(WEBRTC_ARCH_ARM64)
*(ptr) = vaddvq_u32(v);
@@ -42,6 +32,8 @@ static inline void AddLanes(uint32_t* ptr, uint32x4_t v) {
#endif
}
+} // namespace
+
void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm,
const uint16_t* far_spectrum,
int32_t* echo_est,
@@ -90,12 +82,12 @@ void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm,
echo_stored_v = vaddq_u32(echo_est_v_low, echo_stored_v);
echo_stored_v = vaddq_u32(echo_est_v_high, echo_stored_v);
- echo_adapt_v = vmlal_u16(echo_adapt_v,
- vreinterpret_u16_s16(vget_low_s16(adapt_v)),
- vget_low_u16(spectrum_v));
- echo_adapt_v = vmlal_u16(echo_adapt_v,
- vreinterpret_u16_s16(vget_high_s16(adapt_v)),
- vget_high_u16(spectrum_v));
+ echo_adapt_v =
+ vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_low_s16(adapt_v)),
+ vget_low_u16(spectrum_v));
+ echo_adapt_v =
+ vmlal_u16(echo_adapt_v, vreinterpret_u16_s16(vget_high_s16(adapt_v)),
+ vget_high_u16(spectrum_v));
start_stored_p += 8;
start_adapt_p += 8;
@@ -117,9 +109,9 @@ void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm,
void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm,
const uint16_t* far_spectrum,
int32_t* echo_est) {
- assert((uintptr_t)echo_est % 32 == 0);
- assert((uintptr_t)(aecm->channelStored) % 16 == 0);
- assert((uintptr_t)(aecm->channelAdapt16) % 16 == 0);
+ RTC_DCHECK_EQ(0, (uintptr_t)echo_est % 32);
+ RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelStored % 16);
+ RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelAdapt16 % 16);
// This is C code of following optimized code.
// During startup we store the channel every block.
@@ -174,9 +166,9 @@ void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm,
}
void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm) {
- assert((uintptr_t)(aecm->channelStored) % 16 == 0);
- assert((uintptr_t)(aecm->channelAdapt16) % 16 == 0);
- assert((uintptr_t)(aecm->channelAdapt32) % 32 == 0);
+ RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelStored % 16);
+ RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelAdapt16 % 16);
+ RTC_DCHECK_EQ(0, (uintptr_t)aecm->channelAdapt32 % 32);
// The C code of following optimized code.
// for (i = 0; i < PART_LEN1; i++) {
@@ -210,3 +202,5 @@ void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm) {
aecm->channelAdapt16[PART_LEN] = aecm->channelStored[PART_LEN];
aecm->channelAdapt32[PART_LEN] = (int32_t)aecm->channelStored[PART_LEN] << 16;
}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aecm/aecm_defines.h b/webrtc/modules/audio_processing/aecm/aecm_defines.h
index 6d63990..5805549 100644
--- a/webrtc/modules/audio_processing/aecm/aecm_defines.h
+++ b/webrtc/modules/audio_processing/aecm/aecm_defines.h
@@ -8,80 +8,80 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_
+#ifndef MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_
+#define MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_
-#define AECM_DYNAMIC_Q /* Turn on/off dynamic Q-domain. */
+#define AECM_DYNAMIC_Q /* Turn on/off dynamic Q-domain. */
/* Algorithm parameters */
-#define FRAME_LEN 80 /* Total frame length, 10 ms. */
+#define FRAME_LEN 80 /* Total frame length, 10 ms. */
-#define PART_LEN 64 /* Length of partition. */
-#define PART_LEN_SHIFT 7 /* Length of (PART_LEN * 2) in base 2. */
+#define PART_LEN 64 /* Length of partition. */
+#define PART_LEN_SHIFT 7 /* Length of (PART_LEN * 2) in base 2. */
-#define PART_LEN1 (PART_LEN + 1) /* Unique fft coefficients. */
-#define PART_LEN2 (PART_LEN << 1) /* Length of partition * 2. */
-#define PART_LEN4 (PART_LEN << 2) /* Length of partition * 4. */
-#define FAR_BUF_LEN PART_LEN4 /* Length of buffers. */
-#define MAX_DELAY 100
+#define PART_LEN1 (PART_LEN + 1) /* Unique fft coefficients. */
+#define PART_LEN2 (PART_LEN << 1) /* Length of partition * 2. */
+#define PART_LEN4 (PART_LEN << 2) /* Length of partition * 4. */
+#define FAR_BUF_LEN PART_LEN4 /* Length of buffers. */
+#define MAX_DELAY 100
/* Counter parameters */
-#define CONV_LEN 512 /* Convergence length used at startup. */
-#define CONV_LEN2 (CONV_LEN << 1) /* Used at startup. */
+#define CONV_LEN 512 /* Convergence length used at startup. */
+#define CONV_LEN2 (CONV_LEN << 1) /* Used at startup. */
/* Energy parameters */
-#define MAX_BUF_LEN 64 /* History length of energy signals. */
-#define FAR_ENERGY_MIN 1025 /* Lowest Far energy level: At least 2 */
- /* in energy. */
-#define FAR_ENERGY_DIFF 929 /* Allowed difference between max */
- /* and min. */
-#define ENERGY_DEV_OFFSET 0 /* The energy error offset in Q8. */
-#define ENERGY_DEV_TOL 400 /* The energy estimation tolerance (Q8). */
-#define FAR_ENERGY_VAD_REGION 230 /* Far VAD tolerance region. */
+#define MAX_BUF_LEN 64 /* History length of energy signals. */
+#define FAR_ENERGY_MIN 1025 /* Lowest Far energy level: At least 2 */
+ /* in energy. */
+#define FAR_ENERGY_DIFF 929 /* Allowed difference between max */
+ /* and min. */
+#define ENERGY_DEV_OFFSET 0 /* The energy error offset in Q8. */
+#define ENERGY_DEV_TOL 400 /* The energy estimation tolerance (Q8). */
+#define FAR_ENERGY_VAD_REGION 230 /* Far VAD tolerance region. */
/* Stepsize parameters */
-#define MU_MIN 10 /* Min stepsize 2^-MU_MIN (far end energy */
- /* dependent). */
-#define MU_MAX 1 /* Max stepsize 2^-MU_MAX (far end energy */
- /* dependent). */
-#define MU_DIFF 9 /* MU_MIN - MU_MAX */
+#define MU_MIN 10 /* Min stepsize 2^-MU_MIN (far end energy */
+ /* dependent). */
+#define MU_MAX 1 /* Max stepsize 2^-MU_MAX (far end energy */
+ /* dependent). */
+#define MU_DIFF 9 /* MU_MIN - MU_MAX */
/* Channel parameters */
-#define MIN_MSE_COUNT 20 /* Min number of consecutive blocks with enough */
- /* far end energy to compare channel estimates. */
-#define MIN_MSE_DIFF 29 /* The ratio between adapted and stored channel to */
- /* accept a new storage (0.8 in Q-MSE_RESOLUTION). */
-#define MSE_RESOLUTION 5 /* MSE parameter resolution. */
-#define RESOLUTION_CHANNEL16 12 /* W16 Channel in Q-RESOLUTION_CHANNEL16. */
-#define RESOLUTION_CHANNEL32 28 /* W32 Channel in Q-RESOLUTION_CHANNEL. */
-#define CHANNEL_VAD 16 /* Minimum energy in frequency band */
- /* to update channel. */
+#define MIN_MSE_COUNT 20 /* Min number of consecutive blocks with enough */
+ /* far end energy to compare channel estimates. */
+#define MIN_MSE_DIFF 29 /* The ratio between adapted and stored channel to */
+ /* accept a new storage (0.8 in Q-MSE_RESOLUTION). */
+#define MSE_RESOLUTION 5 /* MSE parameter resolution. */
+#define RESOLUTION_CHANNEL16 12 /* W16 Channel in Q-RESOLUTION_CHANNEL16. */
+#define RESOLUTION_CHANNEL32 28 /* W32 Channel in Q-RESOLUTION_CHANNEL. */
+#define CHANNEL_VAD 16 /* Minimum energy in frequency band */
+ /* to update channel. */
/* Suppression gain parameters: SUPGAIN parameters in Q-(RESOLUTION_SUPGAIN). */
-#define RESOLUTION_SUPGAIN 8 /* Channel in Q-(RESOLUTION_SUPGAIN). */
-#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) /* Default. */
-#define SUPGAIN_ERROR_PARAM_A 3072 /* Estimation error parameter */
- /* (Maximum gain) (8 in Q8). */
-#define SUPGAIN_ERROR_PARAM_B 1536 /* Estimation error parameter */
- /* (Gain before going down). */
-#define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT /* Estimation error parameter */
- /* (Should be the same as Default) (1 in Q8). */
-#define SUPGAIN_EPC_DT 200 /* SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL */
+#define RESOLUTION_SUPGAIN 8 /* Channel in Q-(RESOLUTION_SUPGAIN). */
+#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) /* Default. */
+#define SUPGAIN_ERROR_PARAM_A 3072 /* Estimation error parameter */
+ /* (Maximum gain) (8 in Q8). */
+#define SUPGAIN_ERROR_PARAM_B 1536 /* Estimation error parameter */
+ /* (Gain before going down). */
+#define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT /* Estimation error parameter */
+/* (Should be the same as Default) (1 in Q8). */
+#define SUPGAIN_EPC_DT 200 /* SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL */
/* Defines for "check delay estimation" */
-#define CORR_WIDTH 31 /* Number of samples to correlate over. */
-#define CORR_MAX 16 /* Maximum correlation offset. */
-#define CORR_MAX_BUF 63
-#define CORR_DEV 4
-#define CORR_MAX_LEVEL 20
-#define CORR_MAX_LOW 4
-#define CORR_BUF_LEN (CORR_MAX << 1) + 1
+#define CORR_WIDTH 31 /* Number of samples to correlate over. */
+#define CORR_MAX 16 /* Maximum correlation offset. */
+#define CORR_MAX_BUF 63
+#define CORR_DEV 4
+#define CORR_MAX_LEVEL 20
+#define CORR_MAX_LOW 4
+#define CORR_BUF_LEN (CORR_MAX << 1) + 1
/* Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN. */
-#define ONE_Q14 (1 << 14)
+#define ONE_Q14 (1 << 14)
/* NLP defines */
-#define NLP_COMP_LOW 3277 /* 0.2 in Q14 */
-#define NLP_COMP_HIGH ONE_Q14 /* 1 in Q14 */
+#define NLP_COMP_LOW 3277 /* 0.2 in Q14 */
+#define NLP_COMP_HIGH ONE_Q14 /* 1 in Q14 */
#endif
diff --git a/webrtc/modules/audio_processing/aecm/echo_control_mobile.c b/webrtc/modules/audio_processing/aecm/echo_control_mobile.c
deleted file mode 100644
index 83781e9..0000000
--- a/webrtc/modules/audio_processing/aecm/echo_control_mobile.c
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
-
-#ifdef AEC_DEBUG
-#include <stdio.h>
-#endif
-#include <stdlib.h>
-
-#include "webrtc/common_audio/ring_buffer.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
-
-#define BUF_SIZE_FRAMES 50 // buffer size (frames)
-// Maximum length of resampled signal. Must be an integer multiple of frames
-// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
-// The factor of 2 handles wb, and the + 1 is as a safety margin
-#define MAX_RESAMP_LEN (5 * FRAME_LEN)
-
-static const size_t kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
-static const int kSampMsNb = 8; // samples per ms in nb
-// Target suppression levels for nlp modes
-// log{0.001, 0.00001, 0.00000001}
-static const int kInitCheck = 42;
-
-typedef struct
-{
- int sampFreq;
- int scSampFreq;
- short bufSizeStart;
- int knownDelay;
-
- // Stores the last frame added to the farend buffer
- short farendOld[2][FRAME_LEN];
- short initFlag; // indicates if AEC has been initialized
-
- // Variables used for averaging far end buffer size
- short counter;
- short sum;
- short firstVal;
- short checkBufSizeCtr;
-
- // Variables used for delay shifts
- short msInSndCardBuf;
- short filtDelay;
- int timeForDelayChange;
- int ECstartup;
- int checkBuffSize;
- int delayChange;
- short lastDelayDiff;
-
- int16_t echoMode;
-
-#ifdef AEC_DEBUG
- FILE *bufFile;
- FILE *delayFile;
- FILE *preCompFile;
- FILE *postCompFile;
-#endif // AEC_DEBUG
- // Structures
- RingBuffer *farendBuf;
-
- int lastError;
-
- AecmCore* aecmCore;
-} AecMobile;
-
-// Estimates delay to set the position of the farend buffer read pointer
-// (controlled by knownDelay)
-static int WebRtcAecm_EstBufDelay(AecMobile* aecmInst, short msInSndCardBuf);
-
-// Stuffs the farend buffer if the estimated delay is too large
-static int WebRtcAecm_DelayComp(AecMobile* aecmInst);
-
-void* WebRtcAecm_Create() {
- AecMobile* aecm = malloc(sizeof(AecMobile));
-
- WebRtcSpl_Init();
-
- aecm->aecmCore = WebRtcAecm_CreateCore();
- if (!aecm->aecmCore) {
- WebRtcAecm_Free(aecm);
- return NULL;
- }
-
- aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp,
- sizeof(int16_t));
- if (!aecm->farendBuf)
- {
- WebRtcAecm_Free(aecm);
- return NULL;
- }
-
- aecm->initFlag = 0;
- aecm->lastError = 0;
-
-#ifdef AEC_DEBUG
- aecm->aecmCore->farFile = fopen("aecFar.pcm","wb");
- aecm->aecmCore->nearFile = fopen("aecNear.pcm","wb");
- aecm->aecmCore->outFile = fopen("aecOut.pcm","wb");
- //aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
-
- aecm->bufFile = fopen("aecBuf.dat", "wb");
- aecm->delayFile = fopen("aecDelay.dat", "wb");
- aecm->preCompFile = fopen("preComp.pcm", "wb");
- aecm->postCompFile = fopen("postComp.pcm", "wb");
-#endif // AEC_DEBUG
- return aecm;
-}
-
-void WebRtcAecm_Free(void* aecmInst) {
- AecMobile* aecm = aecmInst;
-
- if (aecm == NULL) {
- return;
- }
-
-#ifdef AEC_DEBUG
- fclose(aecm->aecmCore->farFile);
- fclose(aecm->aecmCore->nearFile);
- fclose(aecm->aecmCore->outFile);
- //fclose(aecm->aecmCore->outLpFile);
-
- fclose(aecm->bufFile);
- fclose(aecm->delayFile);
- fclose(aecm->preCompFile);
- fclose(aecm->postCompFile);
-#endif // AEC_DEBUG
- WebRtcAecm_FreeCore(aecm->aecmCore);
- WebRtc_FreeBuffer(aecm->farendBuf);
- free(aecm);
-}
-
-int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
-{
- AecMobile* aecm = aecmInst;
- AecmConfig aecConfig;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (sampFreq != 8000 && sampFreq != 16000)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecm->sampFreq = sampFreq;
-
- // Initialize AECM core
- if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1)
- {
- aecm->lastError = AECM_UNSPECIFIED_ERROR;
- return -1;
- }
-
- // Initialize farend buffer
- WebRtc_InitBuffer(aecm->farendBuf);
-
- aecm->initFlag = kInitCheck; // indicates that initialization has been done
-
- aecm->delayChange = 1;
-
- aecm->sum = 0;
- aecm->counter = 0;
- aecm->checkBuffSize = 1;
- aecm->firstVal = 0;
-
- aecm->ECstartup = 1;
- aecm->bufSizeStart = 0;
- aecm->checkBufSizeCtr = 0;
- aecm->filtDelay = 0;
- aecm->timeForDelayChange = 0;
- aecm->knownDelay = 0;
- aecm->lastDelayDiff = 0;
-
- memset(&aecm->farendOld[0][0], 0, 160);
-
- // Default settings.
- aecConfig.cngMode = AecmTrue;
- aecConfig.echoMode = 3;
-
- if (WebRtcAecm_set_config(aecm, aecConfig) == -1)
- {
- aecm->lastError = AECM_UNSPECIFIED_ERROR;
- return -1;
- }
-
- return 0;
-}
-
-int32_t WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend,
- size_t nrOfSamples)
-{
- AecMobile* aecm = aecmInst;
- int32_t retVal = 0;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (farend == NULL)
- {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- if (nrOfSamples != 80 && nrOfSamples != 160)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- // TODO: Is this really a good idea?
- if (!aecm->ECstartup)
- {
- WebRtcAecm_DelayComp(aecm);
- }
-
- WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
-
- return retVal;
-}
-
-int32_t WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy,
- const int16_t *nearendClean, int16_t *out,
- size_t nrOfSamples, int16_t msInSndCardBuf)
-{
- AecMobile* aecm = aecmInst;
- int32_t retVal = 0;
- size_t i;
- short nmbrOfFilledBuffers;
- size_t nBlocks10ms;
- size_t nFrames;
-#ifdef AEC_DEBUG
- short msInAECBuf;
-#endif
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (nearendNoisy == NULL)
- {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (out == NULL)
- {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- if (nrOfSamples != 80 && nrOfSamples != 160)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
-
- if (msInSndCardBuf < 0)
- {
- msInSndCardBuf = 0;
- aecm->lastError = AECM_BAD_PARAMETER_WARNING;
- retVal = -1;
- } else if (msInSndCardBuf > 500)
- {
- msInSndCardBuf = 500;
- aecm->lastError = AECM_BAD_PARAMETER_WARNING;
- retVal = -1;
- }
- msInSndCardBuf += 10;
- aecm->msInSndCardBuf = msInSndCardBuf;
-
- nFrames = nrOfSamples / FRAME_LEN;
- nBlocks10ms = nFrames / aecm->aecmCore->mult;
-
- if (aecm->ECstartup)
- {
- if (nearendClean == NULL)
- {
- if (out != nearendNoisy)
- {
- memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
- }
- } else if (out != nearendClean)
- {
- memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
- }
-
- nmbrOfFilledBuffers =
- (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
- // The AECM is in the start up mode
- // AECM is disabled until the soundcard buffer and farend buffers are OK
-
- // Mechanism to ensure that the soundcard buffer is reasonably stable.
- if (aecm->checkBuffSize)
- {
- aecm->checkBufSizeCtr++;
- // Before we fill up the far end buffer we require the amount of data on the
- // sound card to be stable (+/-8 ms) compared to the first value. This
- // comparison is made during the following 4 consecutive frames. If it seems
- // to be stable then we start to fill up the far end buffer.
-
- if (aecm->counter == 0)
- {
- aecm->firstVal = aecm->msInSndCardBuf;
- aecm->sum = 0;
- }
-
- if (abs(aecm->firstVal - aecm->msInSndCardBuf)
- < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb))
- {
- aecm->sum += aecm->msInSndCardBuf;
- aecm->counter++;
- } else
- {
- aecm->counter = 0;
- }
-
- if (aecm->counter * nBlocks10ms >= 6)
- {
- // The farend buffer size is determined in blocks of 80 samples
- // Use 75% of the average value of the soundcard buffer
- aecm->bufSizeStart
- = WEBRTC_SPL_MIN((3 * aecm->sum
- * aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES);
- // buffersize has now been determined
- aecm->checkBuffSize = 0;
- }
-
- if (aecm->checkBufSizeCtr * nBlocks10ms > 50)
- {
- // for really bad sound cards, don't disable echocanceller for more than 0.5 sec
- aecm->bufSizeStart = WEBRTC_SPL_MIN((3 * aecm->msInSndCardBuf
- * aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES);
- aecm->checkBuffSize = 0;
- }
- }
-
- // if checkBuffSize changed in the if-statement above
- if (!aecm->checkBuffSize)
- {
- // soundcard buffer is now reasonably stable
- // When the far end buffer is filled with approximately the same amount of
- // data as the amount on the sound card we end the start up phase and start
- // to cancel echoes.
-
- if (nmbrOfFilledBuffers == aecm->bufSizeStart)
- {
- aecm->ECstartup = 0; // Enable the AECM
- } else if (nmbrOfFilledBuffers > aecm->bufSizeStart)
- {
- WebRtc_MoveReadPtr(aecm->farendBuf,
- (int) WebRtc_available_read(aecm->farendBuf)
- - (int) aecm->bufSizeStart * FRAME_LEN);
- aecm->ECstartup = 0;
- }
- }
-
- } else
- {
- // AECM is enabled
-
- // Note only 1 block supported for nb and 2 blocks for wb
- for (i = 0; i < nFrames; i++)
- {
- int16_t farend[FRAME_LEN];
- const int16_t* farend_ptr = NULL;
-
- nmbrOfFilledBuffers =
- (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
-
- // Check that there is data in the far end buffer
- if (nmbrOfFilledBuffers > 0)
- {
- // Get the next 80 samples from the farend buffer
- WebRtc_ReadBuffer(aecm->farendBuf, (void**) &farend_ptr, farend,
- FRAME_LEN);
-
- // Always store the last frame for use when we run out of data
- memcpy(&(aecm->farendOld[i][0]), farend_ptr,
- FRAME_LEN * sizeof(short));
- } else
- {
- // We have no data so we use the last played frame
- memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
- farend_ptr = farend;
- }
-
- // Call buffer delay estimator when all data is extracted,
- // i,e. i = 0 for NB and i = 1 for WB
- if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000))
- {
- WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
- }
-
- // Call the AECM
- /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
- &out[FRAME_LEN * i], aecm->knownDelay);*/
- if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
- farend_ptr,
- &nearendNoisy[FRAME_LEN * i],
- (nearendClean
- ? &nearendClean[FRAME_LEN * i]
- : NULL),
- &out[FRAME_LEN * i]) == -1)
- return -1;
- }
- }
-
-#ifdef AEC_DEBUG
- msInAECBuf = (short) WebRtc_available_read(aecm->farendBuf) /
- (kSampMsNb * aecm->aecmCore->mult);
- fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
- fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
-#endif
-
- return retVal;
-}
-
-int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
-{
- AecMobile* aecm = aecmInst;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- if (config.cngMode != AecmFalse && config.cngMode != AecmTrue)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecm->aecmCore->cngMode = config.cngMode;
-
- if (config.echoMode < 0 || config.echoMode > 4)
- {
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- aecm->echoMode = config.echoMode;
-
- if (aecm->echoMode == 0)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
- aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3)
- - (SUPGAIN_ERROR_PARAM_B >> 3);
- aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3)
- - (SUPGAIN_ERROR_PARAM_D >> 3);
- } else if (aecm->echoMode == 1)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
- aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2)
- - (SUPGAIN_ERROR_PARAM_B >> 2);
- aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2)
- - (SUPGAIN_ERROR_PARAM_D >> 2);
- } else if (aecm->echoMode == 2)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
- aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1)
- - (SUPGAIN_ERROR_PARAM_B >> 1);
- aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1)
- - (SUPGAIN_ERROR_PARAM_D >> 1);
- } else if (aecm->echoMode == 3)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
- aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
- aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
- } else if (aecm->echoMode == 4)
- {
- aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
- aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
- aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
- aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
- aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1)
- - (SUPGAIN_ERROR_PARAM_B << 1);
- aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1)
- - (SUPGAIN_ERROR_PARAM_D << 1);
- }
-
- return 0;
-}
-
-int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config)
-{
- AecMobile* aecm = aecmInst;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- if (config == NULL)
- {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- config->cngMode = aecm->aecmCore->cngMode;
- config->echoMode = aecm->echoMode;
-
- return 0;
-}
-
-int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
- const void* echo_path,
- size_t size_bytes)
-{
- AecMobile* aecm = aecmInst;
- const int16_t* echo_path_ptr = echo_path;
-
- if (aecmInst == NULL) {
- return -1;
- }
- if (echo_path == NULL) {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
- if (size_bytes != WebRtcAecm_echo_path_size_bytes())
- {
- // Input channel size does not match the size of AECM
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
-
- return 0;
-}
-
-int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
- void* echo_path,
- size_t size_bytes)
-{
- AecMobile* aecm = aecmInst;
- int16_t* echo_path_ptr = echo_path;
-
- if (aecmInst == NULL) {
- return -1;
- }
- if (echo_path == NULL) {
- aecm->lastError = AECM_NULL_POINTER_ERROR;
- return -1;
- }
- if (size_bytes != WebRtcAecm_echo_path_size_bytes())
- {
- // Input channel size does not match the size of AECM
- aecm->lastError = AECM_BAD_PARAMETER_ERROR;
- return -1;
- }
- if (aecm->initFlag != kInitCheck)
- {
- aecm->lastError = AECM_UNINITIALIZED_ERROR;
- return -1;
- }
-
- memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
- return 0;
-}
-
-size_t WebRtcAecm_echo_path_size_bytes()
-{
- return (PART_LEN1 * sizeof(int16_t));
-}
-
-int32_t WebRtcAecm_get_error_code(void *aecmInst)
-{
- AecMobile* aecm = aecmInst;
-
- if (aecm == NULL)
- {
- return -1;
- }
-
- return aecm->lastError;
-}
-
-static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
- short delayNew, nSampSndCard;
- short nSampFar = (short) WebRtc_available_read(aecm->farendBuf);
- short diff;
-
- nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
-
- delayNew = nSampSndCard - nSampFar;
-
- if (delayNew < FRAME_LEN)
- {
- WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
- delayNew += FRAME_LEN;
- }
-
- aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
-
- diff = aecm->filtDelay - aecm->knownDelay;
- if (diff > 224)
- {
- if (aecm->lastDelayDiff < 96)
- {
- aecm->timeForDelayChange = 0;
- } else
- {
- aecm->timeForDelayChange++;
- }
- } else if (diff < 96 && aecm->knownDelay > 0)
- {
- if (aecm->lastDelayDiff > 224)
- {
- aecm->timeForDelayChange = 0;
- } else
- {
- aecm->timeForDelayChange++;
- }
- } else
- {
- aecm->timeForDelayChange = 0;
- }
- aecm->lastDelayDiff = diff;
-
- if (aecm->timeForDelayChange > 25)
- {
- aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
- }
- return 0;
-}
-
-static int WebRtcAecm_DelayComp(AecMobile* aecm) {
- int nSampFar = (int) WebRtc_available_read(aecm->farendBuf);
- int nSampSndCard, delayNew, nSampAdd;
- const int maxStuffSamp = 10 * FRAME_LEN;
-
- nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
- delayNew = nSampSndCard - nSampFar;
-
- if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult)
- {
- // The difference of the buffer sizes is larger than the maximum
- // allowed known delay. Compensate by stuffing the buffer.
- nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar),
- FRAME_LEN));
- nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
-
- WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
- aecm->delayChange = 1; // the delay needs to be updated
- }
-
- return 0;
-}
diff --git a/webrtc/modules/audio_processing/aecm/echo_control_mobile.cc b/webrtc/modules/audio_processing/aecm/echo_control_mobile.cc
new file mode 100644
index 0000000..14522c0
--- /dev/null
+++ b/webrtc/modules/audio_processing/aecm/echo_control_mobile.cc
@@ -0,0 +1,599 @@
+/*
+ * 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/audio_processing/aecm/echo_control_mobile.h"
+
+#ifdef AEC_DEBUG
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+#include "common_audio/ring_buffer.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "modules/audio_processing/aecm/aecm_defines.h"
+}
+#include "modules/audio_processing/aecm/aecm_core.h"
+
+namespace webrtc {
+
+namespace {
+
+#define BUF_SIZE_FRAMES 50 // buffer size (frames)
+// Maximum length of resampled signal. Must be an integer multiple of frames
+// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
+// The factor of 2 handles wb, and the + 1 is as a safety margin
+#define MAX_RESAMP_LEN (5 * FRAME_LEN)
+
+static const size_t kBufSizeSamp =
+ BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
+static const int kSampMsNb = 8; // samples per ms in nb
+// Target suppression levels for nlp modes
+// log{0.001, 0.00001, 0.00000001}
+static const int kInitCheck = 42;
+
+typedef struct {
+ int sampFreq;
+ int scSampFreq;
+ short bufSizeStart;
+ int knownDelay;
+
+ // Stores the last frame added to the farend buffer
+ short farendOld[2][FRAME_LEN];
+ short initFlag; // indicates if AEC has been initialized
+
+ // Variables used for averaging far end buffer size
+ short counter;
+ short sum;
+ short firstVal;
+ short checkBufSizeCtr;
+
+ // Variables used for delay shifts
+ short msInSndCardBuf;
+ short filtDelay;
+ int timeForDelayChange;
+ int ECstartup;
+ int checkBuffSize;
+ int delayChange;
+ short lastDelayDiff;
+
+ int16_t echoMode;
+
+#ifdef AEC_DEBUG
+ FILE* bufFile;
+ FILE* delayFile;
+ FILE* preCompFile;
+ FILE* postCompFile;
+#endif // AEC_DEBUG
+ // Structures
+ RingBuffer* farendBuf;
+
+ AecmCore* aecmCore;
+} AecMobile;
+
+} // namespace
+
+// Estimates delay to set the position of the farend buffer read pointer
+// (controlled by knownDelay)
+static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf);
+
+// Stuffs the farend buffer if the estimated delay is too large
+static int WebRtcAecm_DelayComp(AecMobile* aecm);
+
+void* WebRtcAecm_Create() {
+ // Allocate zero-filled memory.
+ AecMobile* aecm = static_cast<AecMobile*>(calloc(1, sizeof(AecMobile)));
+
+ aecm->aecmCore = WebRtcAecm_CreateCore();
+ if (!aecm->aecmCore) {
+ WebRtcAecm_Free(aecm);
+ return NULL;
+ }
+
+ aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp, sizeof(int16_t));
+ if (!aecm->farendBuf) {
+ WebRtcAecm_Free(aecm);
+ return NULL;
+ }
+
+#ifdef AEC_DEBUG
+ aecm->aecmCore->farFile = fopen("aecFar.pcm", "wb");
+ aecm->aecmCore->nearFile = fopen("aecNear.pcm", "wb");
+ aecm->aecmCore->outFile = fopen("aecOut.pcm", "wb");
+ // aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
+
+ aecm->bufFile = fopen("aecBuf.dat", "wb");
+ aecm->delayFile = fopen("aecDelay.dat", "wb");
+ aecm->preCompFile = fopen("preComp.pcm", "wb");
+ aecm->postCompFile = fopen("postComp.pcm", "wb");
+#endif // AEC_DEBUG
+ return aecm;
+}
+
+void WebRtcAecm_Free(void* aecmInst) {
+ AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+
+ if (aecm == NULL) {
+ return;
+ }
+
+#ifdef AEC_DEBUG
+ fclose(aecm->aecmCore->farFile);
+ fclose(aecm->aecmCore->nearFile);
+ fclose(aecm->aecmCore->outFile);
+ // fclose(aecm->aecmCore->outLpFile);
+
+ fclose(aecm->bufFile);
+ fclose(aecm->delayFile);
+ fclose(aecm->preCompFile);
+ fclose(aecm->postCompFile);
+#endif // AEC_DEBUG
+ WebRtcAecm_FreeCore(aecm->aecmCore);
+ WebRtc_FreeBuffer(aecm->farendBuf);
+ free(aecm);
+}
+
+int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq) {
+ AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+ AecmConfig aecConfig;
+
+ if (aecm == NULL) {
+ return -1;
+ }
+
+ if (sampFreq != 8000 && sampFreq != 16000) {
+ return AECM_BAD_PARAMETER_ERROR;
+ }
+ aecm->sampFreq = sampFreq;
+
+ // Initialize AECM core
+ if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1) {
+ return AECM_UNSPECIFIED_ERROR;
+ }
+
+ // Initialize farend buffer
+ WebRtc_InitBuffer(aecm->farendBuf);
+
+ aecm->initFlag = kInitCheck; // indicates that initialization has been done
+
+ aecm->delayChange = 1;
+
+ aecm->sum = 0;
+ aecm->counter = 0;
+ aecm->checkBuffSize = 1;
+ aecm->firstVal = 0;
+
+ aecm->ECstartup = 1;
+ aecm->bufSizeStart = 0;
+ aecm->checkBufSizeCtr = 0;
+ aecm->filtDelay = 0;
+ aecm->timeForDelayChange = 0;
+ aecm->knownDelay = 0;
+ aecm->lastDelayDiff = 0;
+
+ memset(&aecm->farendOld, 0, sizeof(aecm->farendOld));
+
+ // Default settings.
+ aecConfig.cngMode = AecmTrue;
+ aecConfig.echoMode = 3;
+
+ if (WebRtcAecm_set_config(aecm, aecConfig) == -1) {
+ return AECM_UNSPECIFIED_ERROR;
+ }
+
+ return 0;
+}
+
+// Returns any error that is caused when buffering the
+// farend signal.
+int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst,
+ const int16_t* farend,
+ size_t nrOfSamples) {
+ AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+
+ if (aecm == NULL)
+ return -1;
+
+ if (farend == NULL)
+ return AECM_NULL_POINTER_ERROR;
+
+ if (aecm->initFlag != kInitCheck)
+ return AECM_UNINITIALIZED_ERROR;
+
+ if (nrOfSamples != 80 && nrOfSamples != 160)
+ return AECM_BAD_PARAMETER_ERROR;
+
+ return 0;
+}
+
+int32_t WebRtcAecm_BufferFarend(void* aecmInst,
+ const int16_t* farend,
+ size_t nrOfSamples) {
+ AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+
+ const int32_t err =
+ WebRtcAecm_GetBufferFarendError(aecmInst, farend, nrOfSamples);
+
+ if (err != 0)
+ return err;
+
+ // TODO(unknown): Is this really a good idea?
+ if (!aecm->ECstartup) {
+ WebRtcAecm_DelayComp(aecm);
+ }
+
+ WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
+
+ return 0;
+}
+
+int32_t WebRtcAecm_Process(void* aecmInst,
+ const int16_t* nearendNoisy,
+ const int16_t* nearendClean,
+ int16_t* out,
+ size_t nrOfSamples,
+ int16_t msInSndCardBuf) {
+ AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+ int32_t retVal = 0;
+ size_t i;
+ short nmbrOfFilledBuffers;
+ size_t nBlocks10ms;
+ size_t nFrames;
+#ifdef AEC_DEBUG
+ short msInAECBuf;
+#endif
+
+ if (aecm == NULL) {
+ return -1;
+ }
+
+ if (nearendNoisy == NULL) {
+ return AECM_NULL_POINTER_ERROR;
+ }
+
+ if (out == NULL) {
+ return AECM_NULL_POINTER_ERROR;
+ }
+
+ if (aecm->initFlag != kInitCheck) {
+ return AECM_UNINITIALIZED_ERROR;
+ }
+
+ if (nrOfSamples != 80 && nrOfSamples != 160) {
+ return AECM_BAD_PARAMETER_ERROR;
+ }
+
+ if (msInSndCardBuf < 0) {
+ msInSndCardBuf = 0;
+ retVal = AECM_BAD_PARAMETER_WARNING;
+ } else if (msInSndCardBuf > 500) {
+ msInSndCardBuf = 500;
+ retVal = AECM_BAD_PARAMETER_WARNING;
+ }
+ msInSndCardBuf += 10;
+ aecm->msInSndCardBuf = msInSndCardBuf;
+
+ nFrames = nrOfSamples / FRAME_LEN;
+ nBlocks10ms = nFrames / aecm->aecmCore->mult;
+
+ if (aecm->ECstartup) {
+ if (nearendClean == NULL) {
+ if (out != nearendNoisy) {
+ memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
+ }
+ } else if (out != nearendClean) {
+ memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
+ }
+
+ nmbrOfFilledBuffers =
+ (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
+ // The AECM is in the start up mode
+ // AECM is disabled until the soundcard buffer and farend buffers are OK
+
+ // Mechanism to ensure that the soundcard buffer is reasonably stable.
+ if (aecm->checkBuffSize) {
+ aecm->checkBufSizeCtr++;
+ // Before we fill up the far end buffer we require the amount of data on
+ // the sound card to be stable (+/-8 ms) compared to the first value. This
+ // comparison is made during the following 4 consecutive frames. If it
+ // seems to be stable then we start to fill up the far end buffer.
+
+ if (aecm->counter == 0) {
+ aecm->firstVal = aecm->msInSndCardBuf;
+ aecm->sum = 0;
+ }
+
+ if (abs(aecm->firstVal - aecm->msInSndCardBuf) <
+ WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb)) {
+ aecm->sum += aecm->msInSndCardBuf;
+ aecm->counter++;
+ } else {
+ aecm->counter = 0;
+ }
+
+ if (aecm->counter * nBlocks10ms >= 6) {
+ // The farend buffer size is determined in blocks of 80 samples
+ // Use 75% of the average value of the soundcard buffer
+ aecm->bufSizeStart = WEBRTC_SPL_MIN(
+ (3 * aecm->sum * aecm->aecmCore->mult) / (aecm->counter * 40),
+ BUF_SIZE_FRAMES);
+ // buffersize has now been determined
+ aecm->checkBuffSize = 0;
+ }
+
+ if (aecm->checkBufSizeCtr * nBlocks10ms > 50) {
+ // for really bad sound cards, don't disable echocanceller for more than
+ // 0.5 sec
+ aecm->bufSizeStart = WEBRTC_SPL_MIN(
+ (3 * aecm->msInSndCardBuf * aecm->aecmCore->mult) / 40,
+ BUF_SIZE_FRAMES);
+ aecm->checkBuffSize = 0;
+ }
+ }
+
+ // if checkBuffSize changed in the if-statement above
+ if (!aecm->checkBuffSize) {
+ // soundcard buffer is now reasonably stable
+ // When the far end buffer is filled with approximately the same amount of
+ // data as the amount on the sound card we end the start up phase and
+ // start to cancel echoes.
+
+ if (nmbrOfFilledBuffers == aecm->bufSizeStart) {
+ aecm->ECstartup = 0; // Enable the AECM
+ } else if (nmbrOfFilledBuffers > aecm->bufSizeStart) {
+ WebRtc_MoveReadPtr(aecm->farendBuf,
+ (int)WebRtc_available_read(aecm->farendBuf) -
+ (int)aecm->bufSizeStart * FRAME_LEN);
+ aecm->ECstartup = 0;
+ }
+ }
+
+ } else {
+ // AECM is enabled
+
+ // Note only 1 block supported for nb and 2 blocks for wb
+ for (i = 0; i < nFrames; i++) {
+ int16_t farend[FRAME_LEN];
+ const int16_t* farend_ptr = NULL;
+
+ nmbrOfFilledBuffers =
+ (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
+
+ // Check that there is data in the far end buffer
+ if (nmbrOfFilledBuffers > 0) {
+ // Get the next 80 samples from the farend buffer
+ WebRtc_ReadBuffer(aecm->farendBuf, (void**)&farend_ptr, farend,
+ FRAME_LEN);
+
+ // Always store the last frame for use when we run out of data
+ memcpy(&(aecm->farendOld[i][0]), farend_ptr, FRAME_LEN * sizeof(short));
+ } else {
+ // We have no data so we use the last played frame
+ memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
+ farend_ptr = farend;
+ }
+
+ // Call buffer delay estimator when all data is extracted,
+ // i,e. i = 0 for NB and i = 1 for WB
+ if ((i == 0 && aecm->sampFreq == 8000) ||
+ (i == 1 && aecm->sampFreq == 16000)) {
+ WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
+ }
+
+ // Call the AECM
+ /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
+ &out[FRAME_LEN * i], aecm->knownDelay);*/
+ if (WebRtcAecm_ProcessFrame(
+ aecm->aecmCore, farend_ptr, &nearendNoisy[FRAME_LEN * i],
+ (nearendClean ? &nearendClean[FRAME_LEN * i] : NULL),
+ &out[FRAME_LEN * i]) == -1)
+ return -1;
+ }
+ }
+
+#ifdef AEC_DEBUG
+ msInAECBuf = (short)WebRtc_available_read(aecm->farendBuf) /
+ (kSampMsNb * aecm->aecmCore->mult);
+ fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
+ fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
+#endif
+
+ return retVal;
+}
+
+int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config) {
+ AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+
+ if (aecm == NULL) {
+ return -1;
+ }
+
+ if (aecm->initFlag != kInitCheck) {
+ return AECM_UNINITIALIZED_ERROR;
+ }
+
+ if (config.cngMode != AecmFalse && config.cngMode != AecmTrue) {
+ return AECM_BAD_PARAMETER_ERROR;
+ }
+ aecm->aecmCore->cngMode = config.cngMode;
+
+ if (config.echoMode < 0 || config.echoMode > 4) {
+ return AECM_BAD_PARAMETER_ERROR;
+ }
+ aecm->echoMode = config.echoMode;
+
+ if (aecm->echoMode == 0) {
+ aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
+ aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
+ aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
+ aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
+ aecm->aecmCore->supGainErrParamDiffAB =
+ (SUPGAIN_ERROR_PARAM_A >> 3) - (SUPGAIN_ERROR_PARAM_B >> 3);
+ aecm->aecmCore->supGainErrParamDiffBD =
+ (SUPGAIN_ERROR_PARAM_B >> 3) - (SUPGAIN_ERROR_PARAM_D >> 3);
+ } else if (aecm->echoMode == 1) {
+ aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
+ aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
+ aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
+ aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
+ aecm->aecmCore->supGainErrParamDiffAB =
+ (SUPGAIN_ERROR_PARAM_A >> 2) - (SUPGAIN_ERROR_PARAM_B >> 2);
+ aecm->aecmCore->supGainErrParamDiffBD =
+ (SUPGAIN_ERROR_PARAM_B >> 2) - (SUPGAIN_ERROR_PARAM_D >> 2);
+ } else if (aecm->echoMode == 2) {
+ aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
+ aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
+ aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
+ aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
+ aecm->aecmCore->supGainErrParamDiffAB =
+ (SUPGAIN_ERROR_PARAM_A >> 1) - (SUPGAIN_ERROR_PARAM_B >> 1);
+ aecm->aecmCore->supGainErrParamDiffBD =
+ (SUPGAIN_ERROR_PARAM_B >> 1) - (SUPGAIN_ERROR_PARAM_D >> 1);
+ } else if (aecm->echoMode == 3) {
+ aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
+ aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
+ aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
+ aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
+ aecm->aecmCore->supGainErrParamDiffAB =
+ SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
+ aecm->aecmCore->supGainErrParamDiffBD =
+ SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
+ } else if (aecm->echoMode == 4) {
+ aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
+ aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
+ aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
+ aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
+ aecm->aecmCore->supGainErrParamDiffAB =
+ (SUPGAIN_ERROR_PARAM_A << 1) - (SUPGAIN_ERROR_PARAM_B << 1);
+ aecm->aecmCore->supGainErrParamDiffBD =
+ (SUPGAIN_ERROR_PARAM_B << 1) - (SUPGAIN_ERROR_PARAM_D << 1);
+ }
+
+ return 0;
+}
+
+int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
+ const void* echo_path,
+ size_t size_bytes) {
+ AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+ const int16_t* echo_path_ptr = static_cast<const int16_t*>(echo_path);
+
+ if (aecmInst == NULL) {
+ return -1;
+ }
+ if (echo_path == NULL) {
+ return AECM_NULL_POINTER_ERROR;
+ }
+ if (size_bytes != WebRtcAecm_echo_path_size_bytes()) {
+ // Input channel size does not match the size of AECM
+ return AECM_BAD_PARAMETER_ERROR;
+ }
+ if (aecm->initFlag != kInitCheck) {
+ return AECM_UNINITIALIZED_ERROR;
+ }
+
+ WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
+
+ return 0;
+}
+
+int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
+ void* echo_path,
+ size_t size_bytes) {
+ AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
+ int16_t* echo_path_ptr = static_cast<int16_t*>(echo_path);
+
+ if (aecmInst == NULL) {
+ return -1;
+ }
+ if (echo_path == NULL) {
+ return AECM_NULL_POINTER_ERROR;
+ }
+ if (size_bytes != WebRtcAecm_echo_path_size_bytes()) {
+ // Input channel size does not match the size of AECM
+ return AECM_BAD_PARAMETER_ERROR;
+ }
+ if (aecm->initFlag != kInitCheck) {
+ return AECM_UNINITIALIZED_ERROR;
+ }
+
+ memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
+ return 0;
+}
+
+size_t WebRtcAecm_echo_path_size_bytes() {
+ return (PART_LEN1 * sizeof(int16_t));
+}
+
+static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
+ short delayNew, nSampSndCard;
+ short nSampFar = (short)WebRtc_available_read(aecm->farendBuf);
+ short diff;
+
+ nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
+
+ delayNew = nSampSndCard - nSampFar;
+
+ if (delayNew < FRAME_LEN) {
+ WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
+ delayNew += FRAME_LEN;
+ }
+
+ aecm->filtDelay =
+ WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
+
+ diff = aecm->filtDelay - aecm->knownDelay;
+ if (diff > 224) {
+ if (aecm->lastDelayDiff < 96) {
+ aecm->timeForDelayChange = 0;
+ } else {
+ aecm->timeForDelayChange++;
+ }
+ } else if (diff < 96 && aecm->knownDelay > 0) {
+ if (aecm->lastDelayDiff > 224) {
+ aecm->timeForDelayChange = 0;
+ } else {
+ aecm->timeForDelayChange++;
+ }
+ } else {
+ aecm->timeForDelayChange = 0;
+ }
+ aecm->lastDelayDiff = diff;
+
+ if (aecm->timeForDelayChange > 25) {
+ aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
+ }
+ return 0;
+}
+
+static int WebRtcAecm_DelayComp(AecMobile* aecm) {
+ int nSampFar = (int)WebRtc_available_read(aecm->farendBuf);
+ int nSampSndCard, delayNew, nSampAdd;
+ const int maxStuffSamp = 10 * FRAME_LEN;
+
+ nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
+ delayNew = nSampSndCard - nSampFar;
+
+ if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult) {
+ // The difference of the buffer sizes is larger than the maximum
+ // allowed known delay. Compensate by stuffing the buffer.
+ nSampAdd =
+ (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar), FRAME_LEN));
+ nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
+
+ WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
+ aecm->delayChange = 1; // the delay needs to be updated
+ }
+
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h b/webrtc/modules/audio_processing/aecm/echo_control_mobile.h
index 7ae15c2..ee78052 100644
--- a/webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h
+++ b/webrtc/modules/audio_processing/aecm/echo_control_mobile.h
@@ -8,31 +8,29 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_
+#ifndef MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_
+#define MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_
-#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
-#include "webrtc/typedefs.h"
+namespace webrtc {
-enum {
- AecmFalse = 0,
- AecmTrue
-};
+enum { AecmFalse = 0, AecmTrue };
// Errors
-#define AECM_UNSPECIFIED_ERROR 12000
-#define AECM_UNSUPPORTED_FUNCTION_ERROR 12001
-#define AECM_UNINITIALIZED_ERROR 12002
-#define AECM_NULL_POINTER_ERROR 12003
-#define AECM_BAD_PARAMETER_ERROR 12004
+#define AECM_UNSPECIFIED_ERROR 12000
+#define AECM_UNSUPPORTED_FUNCTION_ERROR 12001
+#define AECM_UNINITIALIZED_ERROR 12002
+#define AECM_NULL_POINTER_ERROR 12003
+#define AECM_BAD_PARAMETER_ERROR 12004
// Warnings
-#define AECM_BAD_PARAMETER_WARNING 12100
+#define AECM_BAD_PARAMETER_WARNING 12100
typedef struct {
- int16_t cngMode; // AECM_FALSE, AECM_TRUE (default)
- int16_t echoMode; // 0, 1, 2, 3 (default), 4
+ int16_t cngMode; // AECM_FALSE, AECM_TRUE (default)
+ int16_t echoMode; // 0, 1, 2, 3 (default), 4
} AecmConfig;
#ifdef __cplusplus
@@ -66,7 +64,7 @@ void WebRtcAecm_Free(void* aecmInst);
* Outputs Description
* -------------------------------------------------------------------
* int32_t return 0: OK
- * -1: error
+ * 1200-12004,12100: error/warning
*/
int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq);
@@ -83,13 +81,32 @@ int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq);
* Outputs Description
* -------------------------------------------------------------------
* int32_t return 0: OK
- * -1: error
+ * 1200-12004,12100: error/warning
*/
int32_t WebRtcAecm_BufferFarend(void* aecmInst,
const int16_t* farend,
size_t nrOfSamples);
/*
+ * Reports any errors that would arise when buffering a farend buffer.
+ *
+ * Inputs Description
+ * -------------------------------------------------------------------
+ * void* aecmInst Pointer to the AECM instance
+ * int16_t* farend In buffer containing one frame of
+ * farend signal
+ * int16_t nrOfSamples Number of samples in farend buffer
+ *
+ * Outputs Description
+ * -------------------------------------------------------------------
+ * int32_t return 0: OK
+ * 1200-12004,12100: error/warning
+ */
+int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst,
+ const int16_t* farend,
+ size_t nrOfSamples);
+
+/*
* Runs the AECM on an 80 or 160 sample blocks of data.
*
* Inputs Description
@@ -112,7 +129,7 @@ int32_t WebRtcAecm_BufferFarend(void* aecmInst,
* -------------------------------------------------------------------
* int16_t* out Out buffer, one frame of processed nearend
* int32_t return 0: OK
- * -1: error
+ * 1200-12004,12100: error/warning
*/
int32_t WebRtcAecm_Process(void* aecmInst,
const int16_t* nearendNoisy,
@@ -133,27 +150,11 @@ int32_t WebRtcAecm_Process(void* aecmInst,
* Outputs Description
* -------------------------------------------------------------------
* int32_t return 0: OK
- * -1: error
+ * 1200-12004,12100: error/warning
*/
int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config);
/*
- * This function enables the user to set certain parameters on-the-fly
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecmInst Pointer to the AECM instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * AecmConfig* config Pointer to the config instance that
- * all properties will be written to
- * int32_t return 0: OK
- * -1: error
- */
-int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config);
-
-/*
* This function enables the user to set the echo path on-the-fly.
*
* Inputs Description
@@ -165,7 +166,7 @@ int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config);
* Outputs Description
* -------------------------------------------------------------------
* int32_t return 0: OK
- * -1: error
+ * 1200-12004,12100: error/warning
*/
int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
const void* echo_path,
@@ -184,7 +185,7 @@ int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
* Outputs Description
* -------------------------------------------------------------------
* int32_t return 0: OK
- * -1: error
+ * 1200-12004,12100: error/warning
*/
int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
void* echo_path,
@@ -199,20 +200,10 @@ int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
*/
size_t WebRtcAecm_echo_path_size_bytes();
-/*
- * Gets the last error code.
- *
- * Inputs Description
- * -------------------------------------------------------------------
- * void* aecmInst Pointer to the AECM instance
- *
- * Outputs Description
- * -------------------------------------------------------------------
- * int32_t return 11000-11100: error code
- */
-int32_t WebRtcAecm_get_error_code(void *aecmInst);
-
#ifdef __cplusplus
}
#endif
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AECM_ECHO_CONTROL_MOBILE_H_
diff --git a/webrtc/modules/audio_processing/agc/BUILD.gn b/webrtc/modules/audio_processing/agc/BUILD.gn
new file mode 100644
index 0000000..8235456
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc/BUILD.gn
@@ -0,0 +1,116 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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("gain_control_interface") {
+ sources = [ "gain_control.h" ]
+}
+
+rtc_library("agc") {
+ sources = [
+ "agc_manager_direct.cc",
+ "agc_manager_direct.h",
+ ]
+ configs += [ "..:apm_debug_dump" ]
+ deps = [
+ ":gain_control_interface",
+ ":gain_map",
+ ":level_estimation",
+ "..:apm_logging",
+ "..:audio_buffer",
+ "../../../common_audio",
+ "../../../common_audio:common_audio_c",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gtest_prod",
+ "../../../rtc_base:logging",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:safe_minmax",
+ "../../../system_wrappers:field_trial",
+ "../../../system_wrappers:metrics",
+ "../agc2:level_estimation_agc",
+ "../vad",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_library("level_estimation") {
+ sources = [
+ "agc.cc",
+ "agc.h",
+ "loudness_histogram.cc",
+ "loudness_histogram.h",
+ "utility.cc",
+ "utility.h",
+ ]
+ deps = [
+ "../../../rtc_base:checks",
+ "../vad",
+ ]
+}
+
+rtc_library("legacy_agc") {
+ visibility = [
+ ":*",
+ "..:*",
+ ] # Only targets in this file and in
+ # audio_processing can depend on
+ # this.
+
+ sources = [
+ "legacy/analog_agc.cc",
+ "legacy/analog_agc.h",
+ "legacy/digital_agc.cc",
+ "legacy/digital_agc.h",
+ "legacy/gain_control.h",
+ ]
+
+ deps = [
+ "../../../common_audio",
+ "../../../common_audio:common_audio_c",
+ "../../../common_audio/third_party/ooura:fft_size_256",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../system_wrappers",
+ ]
+
+ if (rtc_build_with_neon) {
+ if (current_cpu != "arm64") {
+ # Enable compilation for the NEON instruction set.
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags = [ "-mfpu=neon" ]
+ }
+ }
+}
+
+rtc_source_set("gain_map") {
+ sources = [ "gain_map_internal.h" ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("agc_unittests") {
+ testonly = true
+ sources = [
+ "agc_manager_direct_unittest.cc",
+ "loudness_histogram_unittest.cc",
+ "mock_agc.h",
+ ]
+ configs += [ "..:apm_debug_dump" ]
+
+ deps = [
+ ":agc",
+ ":gain_control_interface",
+ ":level_estimation",
+ "..:mocks",
+ "../../../test:field_trial",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+}
diff --git a/webrtc/modules/audio_processing/agc/agc.cc b/webrtc/modules/audio_processing/agc/agc.cc
index 706b963..a89ae11 100644
--- a/webrtc/modules/audio_processing/agc/agc.cc
+++ b/webrtc/modules/audio_processing/agc/agc.cc
@@ -8,18 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/agc/agc.h"
+#include "modules/audio_processing/agc/agc.h"
#include <cmath>
#include <cstdlib>
-
-#include <algorithm>
#include <vector>
-#include "webrtc/base/checks.h"
-#include "webrtc/modules/audio_processing/agc/histogram.h"
-#include "webrtc/modules/audio_processing/agc/utility.h"
-#include "webrtc/modules/interface/module_common_types.h"
+#include "modules/audio_processing/agc/loudness_histogram.h"
+#include "modules/audio_processing/agc/utility.h"
+#include "rtc_base/checks.h"
namespace webrtc {
namespace {
@@ -33,23 +30,12 @@ const double kActivityThreshold = 0.3;
Agc::Agc()
: target_level_loudness_(Dbfs2Loudness(kDefaultLevelDbfs)),
target_level_dbfs_(kDefaultLevelDbfs),
- histogram_(Histogram::Create(kNumAnalysisFrames)),
- inactive_histogram_(Histogram::Create()) {
- }
-
-Agc::~Agc() {}
+ histogram_(LoudnessHistogram::Create(kNumAnalysisFrames)),
+ inactive_histogram_(LoudnessHistogram::Create()) {}
-float Agc::AnalyzePreproc(const int16_t* audio, size_t length) {
- assert(length > 0);
- size_t num_clipped = 0;
- for (size_t i = 0; i < length; ++i) {
- if (audio[i] == 32767 || audio[i] == -32768)
- ++num_clipped;
- }
- return 1.0f * num_clipped / length;
-}
+Agc::~Agc() = default;
-int Agc::Process(const int16_t* audio, size_t length, int sample_rate_hz) {
+void Agc::Process(const int16_t* audio, size_t length, int sample_rate_hz) {
vad_.ProcessChunk(audio, length, sample_rate_hz);
const std::vector<double>& rms = vad_.chunkwise_rms();
const std::vector<double>& probabilities =
@@ -58,12 +44,11 @@ int Agc::Process(const int16_t* audio, size_t length, int sample_rate_hz) {
for (size_t i = 0; i < rms.size(); ++i) {
histogram_->Update(rms[i], probabilities[i]);
}
- return 0;
}
bool Agc::GetRmsErrorDb(int* error) {
if (!error) {
- assert(false);
+ RTC_NOTREACHED();
return false;
}
@@ -98,4 +83,12 @@ int Agc::set_target_level_dbfs(int level) {
return 0;
}
+int Agc::target_level_dbfs() const {
+ return target_level_dbfs_;
+}
+
+float Agc::voice_probability() const {
+ return vad_.last_voice_probability();
+}
+
} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc/agc.h b/webrtc/modules/audio_processing/agc/agc.h
index 08c287f..b9bd5ea 100644
--- a/webrtc/modules/audio_processing/agc/agc.h
+++ b/webrtc/modules/audio_processing/agc/agc.h
@@ -8,29 +8,25 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_H_
+#ifndef MODULES_AUDIO_PROCESSING_AGC_AGC_H_
+#define MODULES_AUDIO_PROCESSING_AGC_AGC_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/vad/voice_activity_detector.h"
-#include "webrtc/typedefs.h"
+#include <memory>
+
+#include "modules/audio_processing/vad/voice_activity_detector.h"
namespace webrtc {
-class AudioFrame;
-class Histogram;
+class LoudnessHistogram;
class Agc {
public:
Agc();
virtual ~Agc();
- // Returns the proportion of samples in the buffer which are at full-scale
- // (and presumably clipped).
- virtual float AnalyzePreproc(const int16_t* audio, size_t length);
// |audio| must be mono; in a multi-channel stream, provide the first (usually
// left) channel.
- virtual int Process(const int16_t* audio, size_t length, int sample_rate_hz);
+ virtual void Process(const int16_t* audio, size_t length, int sample_rate_hz);
// Retrieves the difference between the target RMS level and the current
// signal RMS level in dB. Returns true if an update is available and false
@@ -39,20 +35,17 @@ class Agc {
virtual void Reset();
virtual int set_target_level_dbfs(int level);
- virtual int target_level_dbfs() const { return target_level_dbfs_; }
-
- virtual float voice_probability() const {
- return vad_.last_voice_probability();
- }
+ virtual int target_level_dbfs() const;
+ virtual float voice_probability() const;
private:
double target_level_loudness_;
int target_level_dbfs_;
- rtc::scoped_ptr<Histogram> histogram_;
- rtc::scoped_ptr<Histogram> inactive_histogram_;
+ std::unique_ptr<LoudnessHistogram> histogram_;
+ std::unique_ptr<LoudnessHistogram> inactive_histogram_;
VoiceActivityDetector vad_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_H_
+#endif // MODULES_AUDIO_PROCESSING_AGC_AGC_H_
diff --git a/webrtc/modules/audio_processing/agc/agc_manager_direct.cc b/webrtc/modules/audio_processing/agc/agc_manager_direct.cc
index 867022d..1428d2a 100644
--- a/webrtc/modules/audio_processing/agc/agc_manager_direct.cc
+++ b/webrtc/modules/audio_processing/agc/agc_manager_direct.cc
@@ -8,26 +8,26 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/agc/agc_manager_direct.h"
+#include "modules/audio_processing/agc/agc_manager_direct.h"
-#include <cassert>
+#include <algorithm>
#include <cmath>
-#ifdef WEBRTC_AGC_DEBUG_DUMP
-#include <cstdio>
-#endif
-
-#include "webrtc/modules/audio_processing/agc/gain_map_internal.h"
-#include "webrtc/modules/audio_processing/gain_control_impl.h"
-#include "webrtc/modules/interface/module_common_types.h"
-#include "webrtc/system_wrappers/include/logging.h"
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/agc/gain_control.h"
+#include "modules/audio_processing/agc/gain_map_internal.h"
+#include "modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_minmax.h"
+#include "system_wrappers/include/field_trial.h"
+#include "system_wrappers/include/metrics.h"
namespace webrtc {
namespace {
-// Lowest the microphone level can be lowered due to clipping.
-const int kClippedLevelMin = 170;
// Amount the microphone level is lowered with every clipping event.
const int kClippedLevelStep = 15;
// Proportion of clipped samples required to declare a clipping event.
@@ -56,185 +56,123 @@ const int kMaxResidualGainChange = 15;
// restrictions from clipping events.
const int kSurplusCompressionGain = 6;
-int ClampLevel(int mic_level) {
- return std::min(std::max(kMinMicLevel, mic_level), kMaxMicLevel);
+// Returns whether a fall-back solution to choose the maximum level should be
+// chosen.
+bool UseMaxAnalogChannelLevel() {
+ return field_trial::IsEnabled("WebRTC-UseMaxAnalogAgcChannelLevel");
+}
+
+// Returns kMinMicLevel if no field trial exists or if it has been disabled.
+// Returns a value between 0 and 255 depending on the field-trial string.
+// Example: 'WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-80' => returns 80.
+int GetMinMicLevel() {
+ RTC_LOG(LS_INFO) << "[agc] GetMinMicLevel";
+ constexpr char kMinMicLevelFieldTrial[] =
+ "WebRTC-Audio-AgcMinMicLevelExperiment";
+ if (!webrtc::field_trial::IsEnabled(kMinMicLevelFieldTrial)) {
+ RTC_LOG(LS_INFO) << "[agc] Using default min mic level: " << kMinMicLevel;
+ return kMinMicLevel;
+ }
+ const auto field_trial_string =
+ webrtc::field_trial::FindFullName(kMinMicLevelFieldTrial);
+ int min_mic_level = -1;
+ sscanf(field_trial_string.c_str(), "Enabled-%d", &min_mic_level);
+ if (min_mic_level >= 0 && min_mic_level <= 255) {
+ RTC_LOG(LS_INFO) << "[agc] Experimental min mic level: " << min_mic_level;
+ return min_mic_level;
+ } else {
+ RTC_LOG(LS_WARNING) << "[agc] Invalid parameter for "
+ << kMinMicLevelFieldTrial << ", ignored.";
+ return kMinMicLevel;
+ }
}
-int LevelFromGainError(int gain_error, int level) {
- assert(level >= 0 && level <= kMaxMicLevel);
+int ClampLevel(int mic_level, int min_mic_level) {
+ return rtc::SafeClamp(mic_level, min_mic_level, kMaxMicLevel);
+}
+
+int LevelFromGainError(int gain_error, int level, int min_mic_level) {
+ RTC_DCHECK_GE(level, 0);
+ RTC_DCHECK_LE(level, kMaxMicLevel);
if (gain_error == 0) {
return level;
}
- // TODO(ajm): Could be made more efficient with a binary search.
+
int new_level = level;
if (gain_error > 0) {
while (kGainMap[new_level] - kGainMap[level] < gain_error &&
- new_level < kMaxMicLevel) {
+ new_level < kMaxMicLevel) {
++new_level;
}
} else {
while (kGainMap[new_level] - kGainMap[level] > gain_error &&
- new_level > kMinMicLevel) {
+ new_level > min_mic_level) {
--new_level;
}
}
return new_level;
}
-} // namespace
-
-// Facility for dumping debug audio files. All methods are no-ops in the
-// default case where WEBRTC_AGC_DEBUG_DUMP is undefined.
-class DebugFile {
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- public:
- explicit DebugFile(const char* filename)
- : file_(fopen(filename, "wb")) {
- assert(file_);
- }
- ~DebugFile() {
- fclose(file_);
- }
- void Write(const int16_t* data, size_t length_samples) {
- fwrite(data, 1, length_samples * sizeof(int16_t), file_);
- }
- private:
- FILE* file_;
-#else
- public:
- explicit DebugFile(const char* filename) {
- }
- ~DebugFile() {
- }
- void Write(const int16_t* data, size_t length_samples) {
+// Returns the proportion of samples in the buffer which are at full-scale
+// (and presumably clipped).
+float ComputeClippedRatio(const float* const* audio,
+ size_t num_channels,
+ size_t samples_per_channel) {
+ RTC_DCHECK_GT(samples_per_channel, 0);
+ int num_clipped = 0;
+ for (size_t ch = 0; ch < num_channels; ++ch) {
+ int num_clipped_in_ch = 0;
+ for (size_t i = 0; i < samples_per_channel; ++i) {
+ RTC_DCHECK(audio[ch]);
+ if (audio[ch][i] >= 32767.f || audio[ch][i] <= -32768.f) {
+ ++num_clipped_in_ch;
+ }
+ }
+ num_clipped = std::max(num_clipped, num_clipped_in_ch);
}
-#endif // WEBRTC_AGC_DEBUG_DUMP
-};
-
-AgcManagerDirect::AgcManagerDirect(GainControl* gctrl,
- VolumeCallbacks* volume_callbacks,
- int startup_min_level)
- : agc_(new Agc()),
- gctrl_(gctrl),
- volume_callbacks_(volume_callbacks),
- frames_since_clipped_(kClippedWaitFrames),
- level_(0),
- max_level_(kMaxMicLevel),
- max_compression_gain_(kMaxCompressionGain),
- target_compression_(kDefaultCompressionGain),
- compression_(target_compression_),
- compression_accumulator_(compression_),
- capture_muted_(false),
- check_volume_on_next_process_(true), // Check at startup.
- startup_(true),
- startup_min_level_(ClampLevel(startup_min_level)),
- file_preproc_(new DebugFile("agc_preproc.pcm")),
- file_postproc_(new DebugFile("agc_postproc.pcm")) {
+ return static_cast<float>(num_clipped) / (samples_per_channel);
}
-AgcManagerDirect::AgcManagerDirect(Agc* agc,
- GainControl* gctrl,
- VolumeCallbacks* volume_callbacks,
- int startup_min_level)
- : agc_(agc),
- gctrl_(gctrl),
- volume_callbacks_(volume_callbacks),
- frames_since_clipped_(kClippedWaitFrames),
- level_(0),
+} // namespace
+
+MonoAgc::MonoAgc(ApmDataDumper* data_dumper,
+ int startup_min_level,
+ int clipped_level_min,
+ bool use_agc2_level_estimation,
+ bool disable_digital_adaptive,
+ int min_mic_level)
+ : min_mic_level_(min_mic_level),
+ disable_digital_adaptive_(disable_digital_adaptive),
max_level_(kMaxMicLevel),
max_compression_gain_(kMaxCompressionGain),
target_compression_(kDefaultCompressionGain),
compression_(target_compression_),
compression_accumulator_(compression_),
- capture_muted_(false),
- check_volume_on_next_process_(true), // Check at startup.
- startup_(true),
- startup_min_level_(ClampLevel(startup_min_level)),
- file_preproc_(new DebugFile("agc_preproc.pcm")),
- file_postproc_(new DebugFile("agc_postproc.pcm")) {
+ startup_min_level_(ClampLevel(startup_min_level, min_mic_level_)),
+ clipped_level_min_(clipped_level_min) {
+ if (use_agc2_level_estimation) {
+ agc_ = std::make_unique<AdaptiveModeLevelEstimatorAgc>(data_dumper);
+ } else {
+ agc_ = std::make_unique<Agc>();
+ }
}
-AgcManagerDirect::~AgcManagerDirect() {}
+MonoAgc::~MonoAgc() = default;
-int AgcManagerDirect::Initialize() {
+void MonoAgc::Initialize() {
max_level_ = kMaxMicLevel;
max_compression_gain_ = kMaxCompressionGain;
- target_compression_ = kDefaultCompressionGain;
- compression_ = target_compression_;
+ target_compression_ = disable_digital_adaptive_ ? 0 : kDefaultCompressionGain;
+ compression_ = disable_digital_adaptive_ ? 0 : target_compression_;
compression_accumulator_ = compression_;
capture_muted_ = false;
check_volume_on_next_process_ = true;
- // TODO(bjornv): Investigate if we need to reset |startup_| as well. For
- // example, what happens when we change devices.
-
- if (gctrl_->set_mode(GainControl::kFixedDigital) != 0) {
- LOG_FERR1(LS_ERROR, set_mode, GainControl::kFixedDigital);
- return -1;
- }
- if (gctrl_->set_target_level_dbfs(2) != 0) {
- LOG_FERR1(LS_ERROR, set_target_level_dbfs, 2);
- return -1;
- }
- if (gctrl_->set_compression_gain_db(kDefaultCompressionGain) != 0) {
- LOG_FERR1(LS_ERROR, set_compression_gain_db, kDefaultCompressionGain);
- return -1;
- }
- if (gctrl_->enable_limiter(true) != 0) {
- LOG_FERR1(LS_ERROR, enable_limiter, true);
- return -1;
- }
- return 0;
}
-void AgcManagerDirect::AnalyzePreProcess(int16_t* audio,
- int num_channels,
- size_t samples_per_channel) {
- size_t length = num_channels * samples_per_channel;
- if (capture_muted_) {
- return;
- }
-
- file_preproc_->Write(audio, length);
-
- if (frames_since_clipped_ < kClippedWaitFrames) {
- ++frames_since_clipped_;
- return;
- }
-
- // Check for clipped samples, as the AGC has difficulty detecting pitch
- // under clipping distortion. We do this in the preprocessing phase in order
- // to catch clipped echo as well.
- //
- // If we find a sufficiently clipped frame, drop the current microphone level
- // and enforce a new maximum level, dropped the same amount from the current
- // maximum. This harsh treatment is an effort to avoid repeated clipped echo
- // events. As compensation for this restriction, the maximum compression
- // gain is increased, through SetMaxLevel().
- float clipped_ratio = agc_->AnalyzePreproc(audio, length);
- if (clipped_ratio > kClippedRatioThreshold) {
- LOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio="
- << clipped_ratio;
- // Always decrease the maximum level, even if the current level is below
- // threshold.
- SetMaxLevel(std::max(kClippedLevelMin, max_level_ - kClippedLevelStep));
- if (level_ > kClippedLevelMin) {
- // Don't try to adjust the level if we're already below the limit. As
- // a consequence, if the user has brought the level above the limit, we
- // will still not react until the postproc updates the level.
- SetLevel(std::max(kClippedLevelMin, level_ - kClippedLevelStep));
- // Reset the AGC since the level has changed.
- agc_->Reset();
- }
- frames_since_clipped_ = 0;
- }
-}
-
-void AgcManagerDirect::Process(const int16_t* audio,
- size_t length,
- int sample_rate_hz) {
- if (capture_muted_) {
- return;
- }
+void MonoAgc::Process(const int16_t* audio,
+ size_t samples_per_channel,
+ int sample_rate_hz) {
+ new_compression_to_set_ = absl::nullopt;
if (check_volume_on_next_process_) {
check_volume_on_next_process_ = false;
@@ -243,35 +181,50 @@ void AgcManagerDirect::Process(const int16_t* audio,
CheckVolumeAndReset();
}
- if (agc_->Process(audio, length, sample_rate_hz) != 0) {
- LOG_FERR0(LS_ERROR, Agc::Process);
- assert(false);
- }
+ agc_->Process(audio, samples_per_channel, sample_rate_hz);
UpdateGain();
- UpdateCompressor();
-
- file_postproc_->Write(audio, length);
+ if (!disable_digital_adaptive_) {
+ UpdateCompressor();
+ }
}
-void AgcManagerDirect::SetLevel(int new_level) {
- int voe_level = volume_callbacks_->GetMicVolume();
- if (voe_level < 0) {
- return;
+void MonoAgc::HandleClipping() {
+ // Always decrease the maximum level, even if the current level is below
+ // threshold.
+ SetMaxLevel(std::max(clipped_level_min_, max_level_ - kClippedLevelStep));
+ if (log_to_histograms_) {
+ RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed",
+ level_ - kClippedLevelStep >= clipped_level_min_);
+ }
+ if (level_ > clipped_level_min_) {
+ // Don't try to adjust the level if we're already below the limit. As
+ // a consequence, if the user has brought the level above the limit, we
+ // will still not react until the postproc updates the level.
+ SetLevel(std::max(clipped_level_min_, level_ - kClippedLevelStep));
+ // Reset the AGCs for all channels since the level has changed.
+ agc_->Reset();
}
+}
+
+void MonoAgc::SetLevel(int new_level) {
+ int voe_level = stream_analog_level_;
if (voe_level == 0) {
- LOG(LS_INFO) << "[agc] VolumeCallbacks returned level=0, taking no action.";
+ RTC_DLOG(LS_INFO)
+ << "[agc] VolumeCallbacks returned level=0, taking no action.";
return;
}
- if (voe_level > kMaxMicLevel) {
- LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level=" << voe_level;
+ if (voe_level < 0 || voe_level > kMaxMicLevel) {
+ RTC_LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level="
+ << voe_level;
return;
}
if (voe_level > level_ + kLevelQuantizationSlack ||
voe_level < level_ - kLevelQuantizationSlack) {
- LOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating "
- << "stored level from " << level_ << " to " << voe_level;
+ RTC_DLOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating "
+ "stored level from "
+ << level_ << " to " << voe_level;
level_ = voe_level;
// Always allow the user to increase the volume.
if (level_ > max_level_) {
@@ -281,6 +234,7 @@ void AgcManagerDirect::SetLevel(int new_level) {
// was manually adjusted. The compressor will still provide some of the
// desired gain change.
agc_->Reset();
+
return;
}
@@ -289,26 +243,27 @@ void AgcManagerDirect::SetLevel(int new_level) {
return;
}
- volume_callbacks_->SetMicVolume(new_level);
- LOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", "
- << "level_=" << level_ << ", "
- << "new_level=" << new_level;
+ stream_analog_level_ = new_level;
+ RTC_DLOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", level_=" << level_
+ << ", new_level=" << new_level;
level_ = new_level;
}
-void AgcManagerDirect::SetMaxLevel(int level) {
- assert(level >= kClippedLevelMin);
+void MonoAgc::SetMaxLevel(int level) {
+ RTC_DCHECK_GE(level, clipped_level_min_);
max_level_ = level;
// Scale the |kSurplusCompressionGain| linearly across the restricted
// level range.
- max_compression_gain_ = kMaxCompressionGain + std::floor(
- (1.f * kMaxMicLevel - max_level_) / (kMaxMicLevel - kClippedLevelMin) *
- kSurplusCompressionGain + 0.5f);
- LOG(LS_INFO) << "[agc] max_level_=" << max_level_
- << ", max_compression_gain_=" << max_compression_gain_;
+ max_compression_gain_ =
+ kMaxCompressionGain + std::floor((1.f * kMaxMicLevel - max_level_) /
+ (kMaxMicLevel - clipped_level_min_) *
+ kSurplusCompressionGain +
+ 0.5f);
+ RTC_DLOG(LS_INFO) << "[agc] max_level_=" << max_level_
+ << ", max_compression_gain_=" << max_compression_gain_;
}
-void AgcManagerDirect::SetCaptureMuted(bool muted) {
+void MonoAgc::SetCaptureMuted(bool muted) {
if (capture_muted_ == muted) {
return;
}
@@ -320,34 +275,29 @@ void AgcManagerDirect::SetCaptureMuted(bool muted) {
}
}
-float AgcManagerDirect::voice_probability() {
- return agc_->voice_probability();
-}
-
-int AgcManagerDirect::CheckVolumeAndReset() {
- int level = volume_callbacks_->GetMicVolume();
- if (level < 0) {
- return -1;
- }
+int MonoAgc::CheckVolumeAndReset() {
+ int level = stream_analog_level_;
// Reasons for taking action at startup:
// 1) A person starting a call is expected to be heard.
// 2) Independent of interpretation of |level| == 0 we should raise it so the
// AGC can do its job properly.
if (level == 0 && !startup_) {
- LOG(LS_INFO) << "[agc] VolumeCallbacks returned level=0, taking no action.";
+ RTC_DLOG(LS_INFO)
+ << "[agc] VolumeCallbacks returned level=0, taking no action.";
return 0;
}
- if (level > kMaxMicLevel) {
- LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level=" << level;
+ if (level < 0 || level > kMaxMicLevel) {
+ RTC_LOG(LS_ERROR) << "[agc] VolumeCallbacks returned an invalid level="
+ << level;
return -1;
}
- LOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level;
+ RTC_DLOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level;
- int minLevel = startup_ ? startup_min_level_ : kMinMicLevel;
+ int minLevel = startup_ ? startup_min_level_ : min_mic_level_;
if (level < minLevel) {
level = minLevel;
- LOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level;
- volume_callbacks_->SetMicVolume(level);
+ RTC_DLOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level;
+ stream_analog_level_ = level;
}
agc_->Reset();
level_ = level;
@@ -362,7 +312,7 @@ int AgcManagerDirect::CheckVolumeAndReset() {
//
// If the slider needs to be moved, we check first if the user has adjusted
// it, in which case we take no action and cache the updated level.
-void AgcManagerDirect::UpdateGain() {
+void MonoAgc::UpdateGain() {
int rms_error = 0;
if (!agc_->GetRmsErrorDb(&rms_error)) {
// No error update ready.
@@ -374,39 +324,55 @@ void AgcManagerDirect::UpdateGain() {
rms_error += kMinCompressionGain;
// Handle as much error as possible with the compressor first.
- int raw_compression = std::max(std::min(rms_error, max_compression_gain_),
- kMinCompressionGain);
+ int raw_compression =
+ rtc::SafeClamp(rms_error, kMinCompressionGain, max_compression_gain_);
+
// Deemphasize the compression gain error. Move halfway between the current
// target and the newly received target. This serves to soften perceptible
// intra-talkspurt adjustments, at the cost of some adaptation speed.
if ((raw_compression == max_compression_gain_ &&
- target_compression_ == max_compression_gain_ - 1) ||
+ target_compression_ == max_compression_gain_ - 1) ||
(raw_compression == kMinCompressionGain &&
- target_compression_ == kMinCompressionGain + 1)) {
+ target_compression_ == kMinCompressionGain + 1)) {
// Special case to allow the target to reach the endpoints of the
// compression range. The deemphasis would otherwise halt it at 1 dB shy.
target_compression_ = raw_compression;
} else {
- target_compression_ = (raw_compression - target_compression_) / 2
- + target_compression_;
+ target_compression_ =
+ (raw_compression - target_compression_) / 2 + target_compression_;
}
// Residual error will be handled by adjusting the volume slider. Use the
// raw rather than deemphasized compression here as we would otherwise
// shrink the amount of slack the compressor provides.
- int residual_gain = rms_error - raw_compression;
- residual_gain = std::min(std::max(residual_gain, -kMaxResidualGainChange),
- kMaxResidualGainChange);
- LOG(LS_INFO) << "[agc] rms_error=" << rms_error << ", "
- << "target_compression=" << target_compression_ << ", "
- << "residual_gain=" << residual_gain;
+ const int residual_gain =
+ rtc::SafeClamp(rms_error - raw_compression, -kMaxResidualGainChange,
+ kMaxResidualGainChange);
+ RTC_DLOG(LS_INFO) << "[agc] rms_error=" << rms_error
+ << ", target_compression=" << target_compression_
+ << ", residual_gain=" << residual_gain;
if (residual_gain == 0)
return;
- SetLevel(LevelFromGainError(residual_gain, level_));
+ int old_level = level_;
+ SetLevel(LevelFromGainError(residual_gain, level_, min_mic_level_));
+ if (old_level != level_) {
+ // level_ was updated by SetLevel; log the new value.
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.AgcSetLevel", level_, 1,
+ kMaxMicLevel, 50);
+ // Reset the AGC since the level has changed.
+ agc_->Reset();
+ }
}
-void AgcManagerDirect::UpdateCompressor() {
+void MonoAgc::UpdateCompressor() {
+ calls_since_last_gain_log_++;
+ if (calls_since_last_gain_log_ == 100) {
+ calls_since_last_gain_log_ = 0;
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc.DigitalGainApplied",
+ compression_, 0, kMaxCompressionGain,
+ kMaxCompressionGain + 1);
+ }
if (compression_ == target_compression_) {
return;
}
@@ -431,10 +397,209 @@ void AgcManagerDirect::UpdateCompressor() {
// Set the new compression gain.
if (new_compression != compression_) {
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc.DigitalGainUpdated",
+ new_compression, 0, kMaxCompressionGain,
+ kMaxCompressionGain + 1);
compression_ = new_compression;
compression_accumulator_ = new_compression;
- if (gctrl_->set_compression_gain_db(compression_) != 0) {
- LOG_FERR1(LS_ERROR, set_compression_gain_db, compression_);
+ new_compression_to_set_ = compression_;
+ }
+}
+
+int AgcManagerDirect::instance_counter_ = 0;
+
+AgcManagerDirect::AgcManagerDirect(Agc* agc,
+ int startup_min_level,
+ int clipped_level_min,
+ int sample_rate_hz)
+ : AgcManagerDirect(/*num_capture_channels*/ 1,
+ startup_min_level,
+ clipped_level_min,
+ /*use_agc2_level_estimation*/ false,
+ /*disable_digital_adaptive*/ false,
+ sample_rate_hz) {
+ RTC_DCHECK(channel_agcs_[0]);
+ RTC_DCHECK(agc);
+ channel_agcs_[0]->set_agc(agc);
+}
+
+AgcManagerDirect::AgcManagerDirect(int num_capture_channels,
+ int startup_min_level,
+ int clipped_level_min,
+ bool use_agc2_level_estimation,
+ bool disable_digital_adaptive,
+ int sample_rate_hz)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_counter_))),
+ use_min_channel_level_(!UseMaxAnalogChannelLevel()),
+ sample_rate_hz_(sample_rate_hz),
+ num_capture_channels_(num_capture_channels),
+ disable_digital_adaptive_(disable_digital_adaptive),
+ frames_since_clipped_(kClippedWaitFrames),
+ capture_muted_(false),
+ channel_agcs_(num_capture_channels),
+ new_compressions_to_set_(num_capture_channels) {
+ const int min_mic_level = GetMinMicLevel();
+ for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) {
+ ApmDataDumper* data_dumper_ch = ch == 0 ? data_dumper_.get() : nullptr;
+
+ channel_agcs_[ch] = std::make_unique<MonoAgc>(
+ data_dumper_ch, startup_min_level, clipped_level_min,
+ use_agc2_level_estimation, disable_digital_adaptive_, min_mic_level);
+ }
+ RTC_DCHECK_LT(0, channel_agcs_.size());
+ channel_agcs_[0]->ActivateLogging();
+}
+
+AgcManagerDirect::~AgcManagerDirect() {}
+
+void AgcManagerDirect::Initialize() {
+ RTC_DLOG(LS_INFO) << "AgcManagerDirect::Initialize";
+ data_dumper_->InitiateNewSetOfRecordings();
+ for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) {
+ channel_agcs_[ch]->Initialize();
+ }
+ capture_muted_ = false;
+
+ AggregateChannelLevels();
+}
+
+void AgcManagerDirect::SetupDigitalGainControl(
+ GainControl* gain_control) const {
+ RTC_DCHECK(gain_control);
+ if (gain_control->set_mode(GainControl::kFixedDigital) != 0) {
+ RTC_LOG(LS_ERROR) << "set_mode(GainControl::kFixedDigital) failed.";
+ }
+ const int target_level_dbfs = disable_digital_adaptive_ ? 0 : 2;
+ if (gain_control->set_target_level_dbfs(target_level_dbfs) != 0) {
+ RTC_LOG(LS_ERROR) << "set_target_level_dbfs() failed.";
+ }
+ const int compression_gain_db =
+ disable_digital_adaptive_ ? 0 : kDefaultCompressionGain;
+ if (gain_control->set_compression_gain_db(compression_gain_db) != 0) {
+ RTC_LOG(LS_ERROR) << "set_compression_gain_db() failed.";
+ }
+ const bool enable_limiter = !disable_digital_adaptive_;
+ if (gain_control->enable_limiter(enable_limiter) != 0) {
+ RTC_LOG(LS_ERROR) << "enable_limiter() failed.";
+ }
+}
+
+void AgcManagerDirect::AnalyzePreProcess(const AudioBuffer* audio) {
+ RTC_DCHECK(audio);
+ AnalyzePreProcess(audio->channels_const(), audio->num_frames());
+}
+
+void AgcManagerDirect::AnalyzePreProcess(const float* const* audio,
+ size_t samples_per_channel) {
+ RTC_DCHECK(audio);
+ AggregateChannelLevels();
+ if (capture_muted_) {
+ return;
+ }
+
+ if (frames_since_clipped_ < kClippedWaitFrames) {
+ ++frames_since_clipped_;
+ return;
+ }
+
+ // Check for clipped samples, as the AGC has difficulty detecting pitch
+ // under clipping distortion. We do this in the preprocessing phase in order
+ // to catch clipped echo as well.
+ //
+ // If we find a sufficiently clipped frame, drop the current microphone level
+ // and enforce a new maximum level, dropped the same amount from the current
+ // maximum. This harsh treatment is an effort to avoid repeated clipped echo
+ // events. As compensation for this restriction, the maximum compression
+ // gain is increased, through SetMaxLevel().
+ float clipped_ratio =
+ ComputeClippedRatio(audio, num_capture_channels_, samples_per_channel);
+
+ if (clipped_ratio > kClippedRatioThreshold) {
+ RTC_DLOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio="
+ << clipped_ratio;
+ for (auto& state_ch : channel_agcs_) {
+ state_ch->HandleClipping();
+ }
+ frames_since_clipped_ = 0;
+ }
+ AggregateChannelLevels();
+}
+
+void AgcManagerDirect::Process(const AudioBuffer* audio) {
+ AggregateChannelLevels();
+
+ if (capture_muted_) {
+ return;
+ }
+
+ for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) {
+ int16_t* audio_use = nullptr;
+ std::array<int16_t, AudioBuffer::kMaxSampleRate / 100> audio_data;
+ int num_frames_per_band;
+ if (audio) {
+ FloatS16ToS16(audio->split_bands_const_f(ch)[0],
+ audio->num_frames_per_band(), audio_data.data());
+ audio_use = audio_data.data();
+ num_frames_per_band = audio->num_frames_per_band();
+ } else {
+ // Only used for testing.
+ // TODO(peah): Change unittests to only allow on non-null audio input.
+ num_frames_per_band = 320;
+ }
+ channel_agcs_[ch]->Process(audio_use, num_frames_per_band, sample_rate_hz_);
+ new_compressions_to_set_[ch] = channel_agcs_[ch]->new_compression();
+ }
+
+ AggregateChannelLevels();
+}
+
+absl::optional<int> AgcManagerDirect::GetDigitalComressionGain() {
+ return new_compressions_to_set_[channel_controlling_gain_];
+}
+
+void AgcManagerDirect::SetCaptureMuted(bool muted) {
+ for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) {
+ channel_agcs_[ch]->SetCaptureMuted(muted);
+ }
+ capture_muted_ = muted;
+}
+
+float AgcManagerDirect::voice_probability() const {
+ float max_prob = 0.f;
+ for (const auto& state_ch : channel_agcs_) {
+ max_prob = std::max(max_prob, state_ch->voice_probability());
+ }
+
+ return max_prob;
+}
+
+void AgcManagerDirect::set_stream_analog_level(int level) {
+ for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) {
+ channel_agcs_[ch]->set_stream_analog_level(level);
+ }
+
+ AggregateChannelLevels();
+}
+
+void AgcManagerDirect::AggregateChannelLevels() {
+ stream_analog_level_ = channel_agcs_[0]->stream_analog_level();
+ channel_controlling_gain_ = 0;
+ if (use_min_channel_level_) {
+ for (size_t ch = 1; ch < channel_agcs_.size(); ++ch) {
+ int level = channel_agcs_[ch]->stream_analog_level();
+ if (level < stream_analog_level_) {
+ stream_analog_level_ = level;
+ channel_controlling_gain_ = static_cast<int>(ch);
+ }
+ }
+ } else {
+ for (size_t ch = 1; ch < channel_agcs_.size(); ++ch) {
+ int level = channel_agcs_[ch]->stream_analog_level();
+ if (level > stream_analog_level_) {
+ stream_analog_level_ = level;
+ channel_controlling_gain_ = static_cast<int>(ch);
+ }
}
}
}
diff --git a/webrtc/modules/audio_processing/agc/agc_manager_direct.h b/webrtc/modules/audio_processing/agc/agc_manager_direct.h
index 6edb0f7..d3663be 100644
--- a/webrtc/modules/audio_processing/agc/agc_manager_direct.h
+++ b/webrtc/modules/audio_processing/agc/agc_manager_direct.h
@@ -8,29 +8,22 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
+#ifndef MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
+#define MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/agc/agc.h"
+#include <memory>
+
+#include "absl/types/optional.h"
+#include "modules/audio_processing/agc/agc.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/gtest_prod_util.h"
namespace webrtc {
-class AudioFrame;
-class DebugFile;
+class MonoAgc;
class GainControl;
-// Callbacks that need to be injected into AgcManagerDirect to read and control
-// the volume values. This is done to remove the VoiceEngine dependency in
-// AgcManagerDirect.
-// TODO(aluebs): Remove VolumeCallbacks.
-class VolumeCallbacks {
- public:
- virtual ~VolumeCallbacks() {}
- virtual void SetMicVolume(int volume) = 0;
- virtual int GetMicVolume() = 0;
-};
-
// Direct interface to use AGC to set volume and compression values.
// AudioProcessing uses this interface directly to integrate the callback-less
// AGC.
@@ -42,30 +35,105 @@ class AgcManagerDirect final {
// responsible for processing the audio using it after the call to Process.
// The operating range of startup_min_level is [12, 255] and any input value
// outside that range will be clamped.
- AgcManagerDirect(GainControl* gctrl,
- VolumeCallbacks* volume_callbacks,
- int startup_min_level);
- // Dependency injection for testing. Don't delete |agc| as the memory is owned
- // by the manager.
- AgcManagerDirect(Agc* agc,
- GainControl* gctrl,
- VolumeCallbacks* volume_callbacks,
- int startup_min_level);
+ AgcManagerDirect(int num_capture_channels,
+ int startup_min_level,
+ int clipped_level_min,
+ bool use_agc2_level_estimation,
+ bool disable_digital_adaptive,
+ int sample_rate_hz);
+
~AgcManagerDirect();
+ AgcManagerDirect(const AgcManagerDirect&) = delete;
+ AgcManagerDirect& operator=(const AgcManagerDirect&) = delete;
- int Initialize();
- void AnalyzePreProcess(int16_t* audio,
- int num_channels,
- size_t samples_per_channel);
- void Process(const int16_t* audio, size_t length, int sample_rate_hz);
+ void Initialize();
+ void SetupDigitalGainControl(GainControl* gain_control) const;
+
+ void AnalyzePreProcess(const AudioBuffer* audio);
+ void Process(const AudioBuffer* audio);
// Call when the capture stream has been muted/unmuted. This causes the
// manager to disregard all incoming audio; chances are good it's background
// noise to which we'd like to avoid adapting.
void SetCaptureMuted(bool muted);
- bool capture_muted() { return capture_muted_; }
+ float voice_probability() const;
+
+ int stream_analog_level() const { return stream_analog_level_; }
+ void set_stream_analog_level(int level);
+ int num_channels() const { return num_capture_channels_; }
+ int sample_rate_hz() const { return sample_rate_hz_; }
- float voice_probability();
+ // If available, returns a new compression gain for the digital gain control.
+ absl::optional<int> GetDigitalComressionGain();
+
+ private:
+ friend class AgcManagerDirectTest;
+
+ FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest,
+ DisableDigitalDisablesDigital);
+ FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest,
+ AgcMinMicLevelExperiment);
+
+ // Dependency injection for testing. Don't delete |agc| as the memory is owned
+ // by the manager.
+ AgcManagerDirect(Agc* agc,
+ int startup_min_level,
+ int clipped_level_min,
+ int sample_rate_hz);
+
+ void AnalyzePreProcess(const float* const* audio, size_t samples_per_channel);
+
+ void AggregateChannelLevels();
+
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ static int instance_counter_;
+ const bool use_min_channel_level_;
+ const int sample_rate_hz_;
+ const int num_capture_channels_;
+ const bool disable_digital_adaptive_;
+
+ int frames_since_clipped_;
+ int stream_analog_level_ = 0;
+ bool capture_muted_;
+ int channel_controlling_gain_ = 0;
+
+ std::vector<std::unique_ptr<MonoAgc>> channel_agcs_;
+ std::vector<absl::optional<int>> new_compressions_to_set_;
+};
+
+class MonoAgc {
+ public:
+ MonoAgc(ApmDataDumper* data_dumper,
+ int startup_min_level,
+ int clipped_level_min,
+ bool use_agc2_level_estimation,
+ bool disable_digital_adaptive,
+ int min_mic_level);
+ ~MonoAgc();
+ MonoAgc(const MonoAgc&) = delete;
+ MonoAgc& operator=(const MonoAgc&) = delete;
+
+ void Initialize();
+ void SetCaptureMuted(bool muted);
+
+ void HandleClipping();
+
+ void Process(const int16_t* audio,
+ size_t samples_per_channel,
+ int sample_rate_hz);
+
+ void set_stream_analog_level(int level) { stream_analog_level_ = level; }
+ int stream_analog_level() const { return stream_analog_level_; }
+ float voice_probability() const { return agc_->voice_probability(); }
+ void ActivateLogging() { log_to_histograms_ = true; }
+ absl::optional<int> new_compression() const {
+ return new_compression_to_set_;
+ }
+
+ // Only used for testing.
+ void set_agc(Agc* agc) { agc_.reset(agc); }
+ int min_mic_level() const { return min_mic_level_; }
+ int startup_min_level() const { return startup_min_level_; }
private:
// Sets a new microphone level, after first checking that it hasn't been
@@ -81,28 +149,26 @@ class AgcManagerDirect final {
void UpdateGain();
void UpdateCompressor();
- rtc::scoped_ptr<Agc> agc_;
- GainControl* gctrl_;
- VolumeCallbacks* volume_callbacks_;
-
- int frames_since_clipped_;
- int level_;
+ const int min_mic_level_;
+ const bool disable_digital_adaptive_;
+ std::unique_ptr<Agc> agc_;
+ int level_ = 0;
int max_level_;
int max_compression_gain_;
int target_compression_;
int compression_;
float compression_accumulator_;
- bool capture_muted_;
- bool check_volume_on_next_process_;
- bool startup_;
+ bool capture_muted_ = false;
+ bool check_volume_on_next_process_ = true;
+ bool startup_ = true;
int startup_min_level_;
-
- rtc::scoped_ptr<DebugFile> file_preproc_;
- rtc::scoped_ptr<DebugFile> file_postproc_;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(AgcManagerDirect);
+ int calls_since_last_gain_log_ = 0;
+ int stream_analog_level_ = 0;
+ absl::optional<int> new_compression_to_set_;
+ bool log_to_histograms_ = false;
+ const int clipped_level_min_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
+#endif // MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
diff --git a/webrtc/modules/audio_processing/agc/gain_control.h b/webrtc/modules/audio_processing/agc/gain_control.h
new file mode 100644
index 0000000..f8c706b
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc/gain_control.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC_GAIN_CONTROL_H_
+#define MODULES_AUDIO_PROCESSING_AGC_GAIN_CONTROL_H_
+
+namespace webrtc {
+
+// The automatic gain control (AGC) component brings the signal to an
+// appropriate range. This is done by applying a digital gain directly and, in
+// the analog mode, prescribing an analog gain to be applied at the audio HAL.
+//
+// Recommended to be enabled on the client-side.
+class GainControl {
+ public:
+ // When an analog mode is set, this must be called prior to |ProcessStream()|
+ // to pass the current analog level from the audio HAL. Must be within the
+ // range provided to |set_analog_level_limits()|.
+ virtual int set_stream_analog_level(int level) = 0;
+
+ // When an analog mode is set, this should be called after |ProcessStream()|
+ // to obtain the recommended new analog level for the audio HAL. It is the
+ // users responsibility to apply this level.
+ virtual int stream_analog_level() const = 0;
+
+ enum Mode {
+ // Adaptive mode intended for use if an analog volume control is available
+ // on the capture device. It will require the user to provide coupling
+ // between the OS mixer controls and AGC through the |stream_analog_level()|
+ // functions.
+ //
+ // It consists of an analog gain prescription for the audio device and a
+ // digital compression stage.
+ kAdaptiveAnalog,
+
+ // Adaptive mode intended for situations in which an analog volume control
+ // is unavailable. It operates in a similar fashion to the adaptive analog
+ // mode, but with scaling instead applied in the digital domain. As with
+ // the analog mode, it additionally uses a digital compression stage.
+ kAdaptiveDigital,
+
+ // Fixed mode which enables only the digital compression stage also used by
+ // the two adaptive modes.
+ //
+ // It is distinguished from the adaptive modes by considering only a
+ // short time-window of the input signal. It applies a fixed gain through
+ // most of the input level range, and compresses (gradually reduces gain
+ // with increasing level) the input signal at higher levels. This mode is
+ // preferred on embedded devices where the capture signal level is
+ // predictable, so that a known gain can be applied.
+ kFixedDigital
+ };
+
+ virtual int set_mode(Mode mode) = 0;
+ virtual Mode mode() const = 0;
+
+ // Sets the target peak |level| (or envelope) of the AGC in dBFs (decibels
+ // from digital full-scale). The convention is to use positive values. For
+ // instance, passing in a value of 3 corresponds to -3 dBFs, or a target
+ // level 3 dB below full-scale. Limited to [0, 31].
+ //
+ // TODO(ajm): use a negative value here instead, if/when VoE will similarly
+ // update its interface.
+ virtual int set_target_level_dbfs(int level) = 0;
+ virtual int target_level_dbfs() const = 0;
+
+ // Sets the maximum |gain| the digital compression stage may apply, in dB. A
+ // higher number corresponds to greater compression, while a value of 0 will
+ // leave the signal uncompressed. Limited to [0, 90].
+ virtual int set_compression_gain_db(int gain) = 0;
+ virtual int compression_gain_db() const = 0;
+
+ // When enabled, the compression stage will hard limit the signal to the
+ // target level. Otherwise, the signal will be compressed but not limited
+ // above the target level.
+ virtual int enable_limiter(bool enable) = 0;
+ virtual bool is_limiter_enabled() const = 0;
+
+ // Sets the |minimum| and |maximum| analog levels of the audio capture device.
+ // Must be set if and only if an analog mode is used. Limited to [0, 65535].
+ virtual int set_analog_level_limits(int minimum, int maximum) = 0;
+ virtual int analog_level_minimum() const = 0;
+ virtual int analog_level_maximum() const = 0;
+
+ // Returns true if the AGC has detected a saturation event (period where the
+ // signal reaches digital full-scale) in the current frame and the analog
+ // level cannot be reduced.
+ //
+ // This could be used as an indicator to reduce or disable analog mic gain at
+ // the audio HAL.
+ virtual bool stream_is_saturated() const = 0;
+
+ protected:
+ virtual ~GainControl() {}
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC_GAIN_CONTROL_H_
diff --git a/webrtc/modules/audio_processing/agc/gain_map_internal.h b/webrtc/modules/audio_processing/agc/gain_map_internal.h
index 53c71c1..547f0f3 100644
--- a/webrtc/modules/audio_processing/agc/gain_map_internal.h
+++ b/webrtc/modules/audio_processing/agc/gain_map_internal.h
@@ -8,268 +8,33 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
+#ifndef MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
+#define MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
+
+namespace webrtc {
static const int kGainMapSize = 256;
// Uses parameters: si = 2, sf = 0.25, D = 8/256
static const int kGainMap[kGainMapSize] = {
- -56,
- -54,
- -52,
- -50,
- -48,
- -47,
- -45,
- -43,
- -42,
- -40,
- -38,
- -37,
- -35,
- -34,
- -33,
- -31,
- -30,
- -29,
- -27,
- -26,
- -25,
- -24,
- -23,
- -22,
- -20,
- -19,
- -18,
- -17,
- -16,
- -15,
- -14,
- -14,
- -13,
- -12,
- -11,
- -10,
- -9,
- -8,
- -8,
- -7,
- -6,
- -5,
- -5,
- -4,
- -3,
- -2,
- -2,
- -1,
- 0,
- 0,
- 1,
- 1,
- 2,
- 3,
- 3,
- 4,
- 4,
- 5,
- 5,
- 6,
- 6,
- 7,
- 7,
- 8,
- 8,
- 9,
- 9,
- 10,
- 10,
- 11,
- 11,
- 12,
- 12,
- 13,
- 13,
- 13,
- 14,
- 14,
- 15,
- 15,
- 15,
- 16,
- 16,
- 17,
- 17,
- 17,
- 18,
- 18,
- 18,
- 19,
- 19,
- 19,
- 20,
- 20,
- 21,
- 21,
- 21,
- 22,
- 22,
- 22,
- 23,
- 23,
- 23,
- 24,
- 24,
- 24,
- 24,
- 25,
- 25,
- 25,
- 26,
- 26,
- 26,
- 27,
- 27,
- 27,
- 28,
- 28,
- 28,
- 28,
- 29,
- 29,
- 29,
- 30,
- 30,
- 30,
- 30,
- 31,
- 31,
- 31,
- 32,
- 32,
- 32,
- 32,
- 33,
- 33,
- 33,
- 33,
- 34,
- 34,
- 34,
- 35,
- 35,
- 35,
- 35,
- 36,
- 36,
- 36,
- 36,
- 37,
- 37,
- 37,
- 38,
- 38,
- 38,
- 38,
- 39,
- 39,
- 39,
- 39,
- 40,
- 40,
- 40,
- 40,
- 41,
- 41,
- 41,
- 41,
- 42,
- 42,
- 42,
- 42,
- 43,
- 43,
- 43,
- 44,
- 44,
- 44,
- 44,
- 45,
- 45,
- 45,
- 45,
- 46,
- 46,
- 46,
- 46,
- 47,
- 47,
- 47,
- 47,
- 48,
- 48,
- 48,
- 48,
- 49,
- 49,
- 49,
- 49,
- 50,
- 50,
- 50,
- 50,
- 51,
- 51,
- 51,
- 51,
- 52,
- 52,
- 52,
- 52,
- 53,
- 53,
- 53,
- 53,
- 54,
- 54,
- 54,
- 54,
- 55,
- 55,
- 55,
- 55,
- 56,
- 56,
- 56,
- 56,
- 57,
- 57,
- 57,
- 57,
- 58,
- 58,
- 58,
- 58,
- 59,
- 59,
- 59,
- 59,
- 60,
- 60,
- 60,
- 60,
- 61,
- 61,
- 61,
- 61,
- 62,
- 62,
- 62,
- 62,
- 63,
- 63,
- 63,
- 63,
- 64
-};
+ -56, -54, -52, -50, -48, -47, -45, -43, -42, -40, -38, -37, -35, -34, -33,
+ -31, -30, -29, -27, -26, -25, -24, -23, -22, -20, -19, -18, -17, -16, -15,
+ -14, -14, -13, -12, -11, -10, -9, -8, -8, -7, -6, -5, -5, -4, -3,
+ -2, -2, -1, 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6,
+ 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
+ 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, 17, 18, 18, 18, 19,
+ 19, 19, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24,
+ 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28,
+ 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 33,
+ 33, 33, 33, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37,
+ 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41,
+ 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 44, 44, 44, 44, 45,
+ 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48,
+ 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52,
+ 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56,
+ 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60,
+ 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
+ 64};
+
+} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
+#endif // MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
diff --git a/webrtc/modules/audio_processing/agc/legacy/analog_agc.c b/webrtc/modules/audio_processing/agc/legacy/analog_agc.c
deleted file mode 100644
index be644d9..0000000
--- a/webrtc/modules/audio_processing/agc/legacy/analog_agc.c
+++ /dev/null
@@ -1,1519 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-/* analog_agc.c
- *
- * Using a feedback system, determines an appropriate analog volume level
- * given an input signal and current volume level. Targets a conservative
- * signal level and is intended for use with a digital AGC to apply
- * additional gain.
- *
- */
-
-#include "webrtc/modules/audio_processing/agc/legacy/analog_agc.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#ifdef WEBRTC_AGC_DEBUG_DUMP
-#include <stdio.h>
-#endif
-
-/* The slope of in Q13*/
-static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78};
-
-/* The offset in Q14 */
-static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951,
- 17367};
-
-/* The slope of in Q13*/
-static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
-
-/* The offset in Q14 */
-static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670,
- 17286};
-
-static const int16_t kMuteGuardTimeMs = 8000;
-static const int16_t kInitCheck = 42;
-static const size_t kNumSubframes = 10;
-
-/* Default settings if config is not used */
-#define AGC_DEFAULT_TARGET_LEVEL 3
-#define AGC_DEFAULT_COMP_GAIN 9
-/* This is the target level for the analog part in ENV scale. To convert to RMS scale you
- * have to add OFFSET_ENV_TO_RMS.
- */
-#define ANALOG_TARGET_LEVEL 11
-#define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2
-/* Offset between RMS scale (analog part) and ENV scale (digital part). This value actually
- * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future replace it with
- * a table.
- */
-#define OFFSET_ENV_TO_RMS 9
-/* The reference input level at which the digital part gives an output of targetLevelDbfs
- * (desired level) if we have no compression gain. This level should be set high enough not
- * to compress the peaks due to the dynamics.
- */
-#define DIGITAL_REF_AT_0_COMP_GAIN 4
-/* Speed of reference level decrease.
- */
-#define DIFF_REF_TO_ANALOG 5
-
-#ifdef MIC_LEVEL_FEEDBACK
-#define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7
-#endif
-/* Size of analog gain table */
-#define GAIN_TBL_LEN 32
-/* Matlab code:
- * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
- */
-/* Q12 */
-static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = {4096, 4251, 4412, 4579, 4752,
- 4932, 5118, 5312, 5513, 5722, 5938, 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992,
- 8295, 8609, 8934, 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
-
-/* Gain/Suppression tables for virtual Mic (in Q10) */
-static const uint16_t kGainTableVirtualMic[128] = {1052, 1081, 1110, 1141, 1172, 1204,
- 1237, 1271, 1305, 1341, 1378, 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757,
- 1805, 1854, 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495, 2563,
- 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357, 3449, 3543, 3640, 3739,
- 3842, 3947, 4055, 4166, 4280, 4397, 4517, 4640, 4767, 4898, 5032, 5169, 5311, 5456,
- 5605, 5758, 5916, 6078, 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960,
- 8178, 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004, 11305,
- 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807, 15212, 15628,
- 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923, 20468, 21028, 21603,
- 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808, 27541, 28295, 29069, 29864,
- 30681, 31520, 32382};
-static const uint16_t kSuppressionTableVirtualMic[128] = {1024, 1006, 988, 970, 952,
- 935, 918, 902, 886, 870, 854, 839, 824, 809, 794, 780, 766, 752, 739, 726, 713, 700,
- 687, 675, 663, 651, 639, 628, 616, 605, 594, 584, 573, 563, 553, 543, 533, 524, 514,
- 505, 496, 487, 478, 470, 461, 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378,
- 371, 364, 358, 351, 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278,
- 273, 268, 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
- 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155, 153, 150,
- 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118, 116, 114, 112, 110,
- 108, 106, 104, 102};
-
-/* Table for target energy levels. Values in Q(-7)
- * Matlab code
- * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n', round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
-
-static const int32_t kTargetLevelTable[64] = {134209536, 106606424, 84680493, 67264106,
- 53429779, 42440782, 33711911, 26778323, 21270778, 16895980, 13420954, 10660642,
- 8468049, 6726411, 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095,
- 1066064, 846805, 672641, 534298, 424408, 337119, 267783, 212708, 168960, 134210,
- 106606, 84680, 67264, 53430, 42441, 33712, 26778, 21271, 16896, 13421, 10661, 8468,
- 6726, 5343, 4244, 3371, 2678, 2127, 1690, 1342, 1066, 847, 673, 534, 424, 337, 268,
- 213, 169, 134, 107, 85, 67};
-
-int WebRtcAgc_AddMic(void *state, int16_t* const* in_mic, size_t num_bands,
- size_t samples)
-{
- int32_t nrg, max_nrg, sample, tmp32;
- int32_t *ptr;
- uint16_t targetGainIdx, gain;
- size_t i;
- int16_t n, L, tmp16, tmp_speech[16];
- LegacyAgc* stt;
- stt = (LegacyAgc*)state;
-
- if (stt->fs == 8000) {
- L = 8;
- if (samples != 80) {
- return -1;
- }
- } else {
- L = 16;
- if (samples != 160) {
- return -1;
- }
- }
-
- /* apply slowly varying digital gain */
- if (stt->micVol > stt->maxAnalog)
- {
- /* |maxLevel| is strictly >= |micVol|, so this condition should be
- * satisfied here, ensuring there is no divide-by-zero. */
- assert(stt->maxLevel > stt->maxAnalog);
-
- /* Q1 */
- tmp16 = (int16_t)(stt->micVol - stt->maxAnalog);
- tmp32 = (GAIN_TBL_LEN - 1) * tmp16;
- tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog);
- targetGainIdx = tmp32 / tmp16;
- assert(targetGainIdx < GAIN_TBL_LEN);
-
- /* Increment through the table towards the target gain.
- * If micVol drops below maxAnalog, we allow the gain
- * to be dropped immediately. */
- if (stt->gainTableIdx < targetGainIdx)
- {
- stt->gainTableIdx++;
- } else if (stt->gainTableIdx > targetGainIdx)
- {
- stt->gainTableIdx--;
- }
-
- /* Q12 */
- gain = kGainTableAnalog[stt->gainTableIdx];
-
- for (i = 0; i < samples; i++)
- {
- size_t j;
- for (j = 0; j < num_bands; ++j)
- {
- sample = (in_mic[j][i] * gain) >> 12;
- if (sample > 32767)
- {
- in_mic[j][i] = 32767;
- } else if (sample < -32768)
- {
- in_mic[j][i] = -32768;
- } else
- {
- in_mic[j][i] = (int16_t)sample;
- }
- }
- }
- } else
- {
- stt->gainTableIdx = 0;
- }
-
- /* compute envelope */
- if (stt->inQueue > 0)
- {
- ptr = stt->env[1];
- } else
- {
- ptr = stt->env[0];
- }
-
- for (i = 0; i < kNumSubframes; i++)
- {
- /* iterate over samples */
- max_nrg = 0;
- for (n = 0; n < L; n++)
- {
- nrg = in_mic[0][i * L + n] * in_mic[0][i * L + n];
- if (nrg > max_nrg)
- {
- max_nrg = nrg;
- }
- }
- ptr[i] = max_nrg;
- }
-
- /* compute energy */
- if (stt->inQueue > 0)
- {
- ptr = stt->Rxx16w32_array[1];
- } else
- {
- ptr = stt->Rxx16w32_array[0];
- }
-
- for (i = 0; i < kNumSubframes / 2; i++)
- {
- if (stt->fs == 16000)
- {
- WebRtcSpl_DownsampleBy2(&in_mic[0][i * 32],
- 32,
- tmp_speech,
- stt->filterState);
- } else
- {
- memcpy(tmp_speech, &in_mic[0][i * 16], 16 * sizeof(short));
- }
- /* Compute energy in blocks of 16 samples */
- ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
- }
-
- /* update queue information */
- if (stt->inQueue == 0)
- {
- stt->inQueue = 1;
- } else
- {
- stt->inQueue = 2;
- }
-
- /* call VAD (use low band only) */
- WebRtcAgc_ProcessVad(&stt->vadMic, in_mic[0], samples);
-
- return 0;
-}
-
-int WebRtcAgc_AddFarend(void *state, const int16_t *in_far, size_t samples)
-{
- LegacyAgc* stt;
- stt = (LegacyAgc*)state;
-
- if (stt == NULL)
- {
- return -1;
- }
-
- if (stt->fs == 8000)
- {
- if (samples != 80)
- {
- return -1;
- }
- } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000)
- {
- if (samples != 160)
- {
- return -1;
- }
- } else
- {
- return -1;
- }
-
- return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
-}
-
-int WebRtcAgc_VirtualMic(void *agcInst, int16_t* const* in_near,
- size_t num_bands, size_t samples, int32_t micLevelIn,
- int32_t *micLevelOut)
-{
- int32_t tmpFlt, micLevelTmp, gainIdx;
- uint16_t gain;
- size_t ii, j;
- LegacyAgc* stt;
-
- uint32_t nrg;
- size_t sampleCntr;
- uint32_t frameNrg = 0;
- uint32_t frameNrgLimit = 5500;
- int16_t numZeroCrossing = 0;
- const int16_t kZeroCrossingLowLim = 15;
- const int16_t kZeroCrossingHighLim = 20;
-
- stt = (LegacyAgc*)agcInst;
-
- /*
- * Before applying gain decide if this is a low-level signal.
- * The idea is that digital AGC will not adapt to low-level
- * signals.
- */
- if (stt->fs != 8000)
- {
- frameNrgLimit = frameNrgLimit << 1;
- }
-
- frameNrg = (uint32_t)(in_near[0][0] * in_near[0][0]);
- for (sampleCntr = 1; sampleCntr < samples; sampleCntr++)
- {
-
- // increment frame energy if it is less than the limit
- // the correct value of the energy is not important
- if (frameNrg < frameNrgLimit)
- {
- nrg = (uint32_t)(in_near[0][sampleCntr] * in_near[0][sampleCntr]);
- frameNrg += nrg;
- }
-
- // Count the zero crossings
- numZeroCrossing +=
- ((in_near[0][sampleCntr] ^ in_near[0][sampleCntr - 1]) < 0);
- }
-
- if ((frameNrg < 500) || (numZeroCrossing <= 5))
- {
- stt->lowLevelSignal = 1;
- } else if (numZeroCrossing <= kZeroCrossingLowLim)
- {
- stt->lowLevelSignal = 0;
- } else if (frameNrg <= frameNrgLimit)
- {
- stt->lowLevelSignal = 1;
- } else if (numZeroCrossing >= kZeroCrossingHighLim)
- {
- stt->lowLevelSignal = 1;
- } else
- {
- stt->lowLevelSignal = 0;
- }
-
- micLevelTmp = micLevelIn << stt->scale;
- /* Set desired level */
- gainIdx = stt->micVol;
- if (stt->micVol > stt->maxAnalog)
- {
- gainIdx = stt->maxAnalog;
- }
- if (micLevelTmp != stt->micRef)
- {
- /* Something has happened with the physical level, restart. */
- stt->micRef = micLevelTmp;
- stt->micVol = 127;
- *micLevelOut = 127;
- stt->micGainIdx = 127;
- gainIdx = 127;
- }
- /* Pre-process the signal to emulate the microphone level. */
- /* Take one step at a time in the gain table. */
- if (gainIdx > 127)
- {
- gain = kGainTableVirtualMic[gainIdx - 128];
- } else
- {
- gain = kSuppressionTableVirtualMic[127 - gainIdx];
- }
- for (ii = 0; ii < samples; ii++)
- {
- tmpFlt = (in_near[0][ii] * gain) >> 10;
- if (tmpFlt > 32767)
- {
- tmpFlt = 32767;
- gainIdx--;
- if (gainIdx >= 127)
- {
- gain = kGainTableVirtualMic[gainIdx - 127];
- } else
- {
- gain = kSuppressionTableVirtualMic[127 - gainIdx];
- }
- }
- if (tmpFlt < -32768)
- {
- tmpFlt = -32768;
- gainIdx--;
- if (gainIdx >= 127)
- {
- gain = kGainTableVirtualMic[gainIdx - 127];
- } else
- {
- gain = kSuppressionTableVirtualMic[127 - gainIdx];
- }
- }
- in_near[0][ii] = (int16_t)tmpFlt;
- for (j = 1; j < num_bands; ++j)
- {
- tmpFlt = (in_near[j][ii] * gain) >> 10;
- if (tmpFlt > 32767)
- {
- tmpFlt = 32767;
- }
- if (tmpFlt < -32768)
- {
- tmpFlt = -32768;
- }
- in_near[j][ii] = (int16_t)tmpFlt;
- }
- }
- /* Set the level we (finally) used */
- stt->micGainIdx = gainIdx;
-// *micLevelOut = stt->micGainIdx;
- *micLevelOut = stt->micGainIdx >> stt->scale;
- /* Add to Mic as if it was the output from a true microphone */
- if (WebRtcAgc_AddMic(agcInst, in_near, num_bands, samples) != 0)
- {
- return -1;
- }
- return 0;
-}
-
-void WebRtcAgc_UpdateAgcThresholds(LegacyAgc* stt) {
- int16_t tmp16;
-#ifdef MIC_LEVEL_FEEDBACK
- int zeros;
-
- if (stt->micLvlSat)
- {
- /* Lower the analog target level since we have reached its maximum */
- zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
- stt->targetIdxOffset = (3 * zeros - stt->targetIdx - 2) / 4;
- }
-#endif
-
- /* Set analog target level in envelope dBOv scale */
- tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
- tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
- stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
- if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN)
- {
- stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
- }
- if (stt->agcMode == kAgcModeFixedDigital)
- {
- /* Adjust for different parameter interpretation in FixedDigital mode */
- stt->analogTarget = stt->compressionGaindB;
- }
-#ifdef MIC_LEVEL_FEEDBACK
- stt->analogTarget += stt->targetIdxOffset;
-#endif
- /* Since the offset between RMS and ENV is not constant, we should make this into a
- * table, but for now, we'll stick with a constant, tuned for the chosen analog
- * target level.
- */
- stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
-#ifdef MIC_LEVEL_FEEDBACK
- stt->targetIdx += stt->targetIdxOffset;
-#endif
- /* Analog adaptation limits */
- /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
- stt->analogTargetLevel = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
- stt->startUpperLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1];/* -19 dBov */
- stt->startLowerLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1];/* -21 dBov */
- stt->upperPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2];/* -18 dBov */
- stt->lowerPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2];/* -22 dBov */
- stt->upperSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5];/* -15 dBov */
- stt->lowerSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5];/* -25 dBov */
- stt->upperLimit = stt->startUpperLimit;
- stt->lowerLimit = stt->startLowerLimit;
-}
-
-void WebRtcAgc_SaturationCtrl(LegacyAgc* stt,
- uint8_t* saturated,
- int32_t* env) {
- int16_t i, tmpW16;
-
- /* Check if the signal is saturated */
- for (i = 0; i < 10; i++)
- {
- tmpW16 = (int16_t)(env[i] >> 20);
- if (tmpW16 > 875)
- {
- stt->envSum += tmpW16;
- }
- }
-
- if (stt->envSum > 25000)
- {
- *saturated = 1;
- stt->envSum = 0;
- }
-
- /* stt->envSum *= 0.99; */
- stt->envSum = (int16_t)((stt->envSum * 32440) >> 15);
-}
-
-void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) {
- int16_t i;
- int32_t tmp32 = 0;
- int32_t midVal;
-
- /* Is the input signal zero? */
- for (i = 0; i < 10; i++)
- {
- tmp32 += env[i];
- }
-
- /* Each block is allowed to have a few non-zero
- * samples.
- */
- if (tmp32 < 500)
- {
- stt->msZero += 10;
- } else
- {
- stt->msZero = 0;
- }
-
- if (stt->muteGuardMs > 0)
- {
- stt->muteGuardMs -= 10;
- }
-
- if (stt->msZero > 500)
- {
- stt->msZero = 0;
-
- /* Increase microphone level only if it's less than 50% */
- midVal = (stt->maxAnalog + stt->minLevel + 1) / 2;
- if (*inMicLevel < midVal)
- {
- /* *inMicLevel *= 1.1; */
- *inMicLevel = (1126 * *inMicLevel) >> 10;
- /* Reduces risk of a muted mic repeatedly triggering excessive levels due
- * to zero signal detection. */
- *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
- stt->micVol = *inMicLevel;
- }
-
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold,"
- " micVol: %d\n",
- stt->fcount,
- stt->micVol);
-#endif
-
- stt->activeSpeech = 0;
- stt->Rxx16_LPw32Max = 0;
-
- /* The AGC has a tendency (due to problems with the VAD parameters), to
- * vastly increase the volume after a muting event. This timer prevents
- * upwards adaptation for a short period. */
- stt->muteGuardMs = kMuteGuardTimeMs;
- }
-}
-
-void WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc* stt) {
- /* Check if the near end speaker is inactive.
- * If that is the case the VAD threshold is
- * increased since the VAD speech model gets
- * more sensitive to any sound after a long
- * silence.
- */
-
- int32_t tmp32;
- int16_t vadThresh;
-
- if (stt->vadMic.stdLongTerm < 2500)
- {
- stt->vadThreshold = 1500;
- } else
- {
- vadThresh = kNormalVadThreshold;
- if (stt->vadMic.stdLongTerm < 4500)
- {
- /* Scale between min and max threshold */
- vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2;
- }
-
- /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
- tmp32 = vadThresh + 31 * stt->vadThreshold;
- stt->vadThreshold = (int16_t)(tmp32 >> 5);
- }
-}
-
-void WebRtcAgc_ExpCurve(int16_t volume, int16_t *index)
-{
- // volume in Q14
- // index in [0-7]
- /* 8 different curves */
- if (volume > 5243)
- {
- if (volume > 7864)
- {
- if (volume > 12124)
- {
- *index = 7;
- } else
- {
- *index = 6;
- }
- } else
- {
- if (volume > 6554)
- {
- *index = 5;
- } else
- {
- *index = 4;
- }
- }
- } else
- {
- if (volume > 2621)
- {
- if (volume > 3932)
- {
- *index = 3;
- } else
- {
- *index = 2;
- }
- } else
- {
- if (volume > 1311)
- {
- *index = 1;
- } else
- {
- *index = 0;
- }
- }
- }
-}
-
-int32_t WebRtcAgc_ProcessAnalog(void *state, int32_t inMicLevel,
- int32_t *outMicLevel,
- int16_t vadLogRatio,
- int16_t echo, uint8_t *saturationWarning)
-{
- uint32_t tmpU32;
- int32_t Rxx16w32, tmp32;
- int32_t inMicLevelTmp, lastMicVol;
- int16_t i;
- uint8_t saturated = 0;
- LegacyAgc* stt;
-
- stt = (LegacyAgc*)state;
- inMicLevelTmp = inMicLevel << stt->scale;
-
- if (inMicLevelTmp > stt->maxAnalog)
- {
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n",
- stt->fcount);
-#endif
- return -1;
- } else if (inMicLevelTmp < stt->minLevel)
- {
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n",
- stt->fcount);
-#endif
- return -1;
- }
-
- if (stt->firstCall == 0)
- {
- int32_t tmpVol;
- stt->firstCall = 1;
- tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
- tmpVol = (stt->minLevel + tmp32);
-
- /* If the mic level is very low at start, increase it! */
- if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog))
- {
- inMicLevelTmp = tmpVol;
- }
- stt->micVol = inMicLevelTmp;
- }
-
- /* Set the mic level to the previous output value if there is digital input gain */
- if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog))
- {
- inMicLevelTmp = stt->micVol;
- }
-
- /* If the mic level was manually changed to a very low value raise it! */
- if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput))
- {
- tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
- inMicLevelTmp = (stt->minLevel + tmp32);
- stt->micVol = inMicLevelTmp;
-#ifdef MIC_LEVEL_FEEDBACK
- //stt->numBlocksMicLvlSat = 0;
-#endif
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual"
- " decrease, raise vol\n",
- stt->fcount);
-#endif
- }
-
- if (inMicLevelTmp != stt->micVol)
- {
- if (inMicLevel == stt->lastInMicLevel) {
- // We requested a volume adjustment, but it didn't occur. This is
- // probably due to a coarse quantization of the volume slider.
- // Restore the requested value to prevent getting stuck.
- inMicLevelTmp = stt->micVol;
- }
- else {
- // As long as the value changed, update to match.
- stt->micVol = inMicLevelTmp;
- }
- }
-
- if (inMicLevelTmp > stt->maxLevel)
- {
- // Always allow the user to raise the volume above the maxLevel.
- stt->maxLevel = inMicLevelTmp;
- }
-
- // Store last value here, after we've taken care of manual updates etc.
- stt->lastInMicLevel = inMicLevel;
- lastMicVol = stt->micVol;
-
- /* Checks if the signal is saturated. Also a check if individual samples
- * are larger than 12000 is done. If they are the counter for increasing
- * the volume level is set to -100ms
- */
- WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
-
- /* The AGC is always allowed to lower the level if the signal is saturated */
- if (saturated == 1)
- {
- /* Lower the recording level
- * Rxx160_LP is adjusted down because it is so slow it could
- * cause the AGC to make wrong decisions. */
- /* stt->Rxx160_LPw32 *= 0.875; */
- stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7;
-
- stt->zeroCtrlMax = stt->micVol;
-
- /* stt->micVol *= 0.903; */
- tmp32 = inMicLevelTmp - stt->minLevel;
- tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
- stt->micVol = (tmpU32 >> 15) + stt->minLevel;
- if (stt->micVol > lastMicVol - 2)
- {
- stt->micVol = lastMicVol - 2;
- }
- inMicLevelTmp = stt->micVol;
-
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
- stt->fcount,
- stt->micVol);
-#endif
-
- if (stt->micVol < stt->minOutput)
- {
- *saturationWarning = 1;
- }
-
- /* Reset counter for decrease of volume level to avoid
- * decreasing too much. The saturation control can still
- * lower the level if needed. */
- stt->msTooHigh = -100;
-
- /* Enable the control mechanism to ensure that our measure,
- * Rxx160_LP, is in the correct range. This must be done since
- * the measure is very slow. */
- stt->activeSpeech = 0;
- stt->Rxx16_LPw32Max = 0;
-
- /* Reset to initial values */
- stt->msecSpeechInnerChange = kMsecSpeechInner;
- stt->msecSpeechOuterChange = kMsecSpeechOuter;
- stt->changeToSlowMode = 0;
-
- stt->muteGuardMs = 0;
-
- stt->upperLimit = stt->startUpperLimit;
- stt->lowerLimit = stt->startLowerLimit;
-#ifdef MIC_LEVEL_FEEDBACK
- //stt->numBlocksMicLvlSat = 0;
-#endif
- }
-
- /* Check if the input speech is zero. If so the mic volume
- * is increased. On some computers the input is zero up as high
- * level as 17% */
- WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
-
- /* Check if the near end speaker is inactive.
- * If that is the case the VAD threshold is
- * increased since the VAD speech model gets
- * more sensitive to any sound after a long
- * silence.
- */
- WebRtcAgc_SpeakerInactiveCtrl(stt);
-
- for (i = 0; i < 5; i++)
- {
- /* Computed on blocks of 16 samples */
-
- Rxx16w32 = stt->Rxx16w32_array[0][i];
-
- /* Rxx160w32 in Q(-7) */
- tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3;
- stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
- stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
-
- /* Circular buffer */
- stt->Rxx16pos++;
- if (stt->Rxx16pos == RXX_BUFFER_LEN)
- {
- stt->Rxx16pos = 0;
- }
-
- /* Rxx16_LPw32 in Q(-4) */
- tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm;
- stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
-
- if (vadLogRatio > stt->vadThreshold)
- {
- /* Speech detected! */
-
- /* Check if Rxx160_LP is in the correct range. If
- * it is too high/low then we set it to the maximum of
- * Rxx16_LPw32 during the first 200ms of speech.
- */
- if (stt->activeSpeech < 250)
- {
- stt->activeSpeech += 2;
-
- if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max)
- {
- stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
- }
- } else if (stt->activeSpeech == 250)
- {
- stt->activeSpeech += 2;
- tmp32 = stt->Rxx16_LPw32Max >> 3;
- stt->Rxx160_LPw32 = tmp32 * RXX_BUFFER_LEN;
- }
-
- tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm;
- stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
-
- if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit)
- {
- stt->msTooHigh += 2;
- stt->msTooLow = 0;
- stt->changeToSlowMode = 0;
-
- if (stt->msTooHigh > stt->msecSpeechOuterChange)
- {
- stt->msTooHigh = 0;
-
- /* Lower the recording level */
- /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
- tmp32 = stt->Rxx160_LPw32 >> 6;
- stt->Rxx160_LPw32 = tmp32 * 53;
-
- /* Reduce the max gain to avoid excessive oscillation
- * (but never drop below the maximum analog level).
- */
- stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
- stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
-
- stt->zeroCtrlMax = stt->micVol;
-
- /* 0.95 in Q15 */
- tmp32 = inMicLevelTmp - stt->minLevel;
- tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
- stt->micVol = (tmpU32 >> 15) + stt->minLevel;
- if (stt->micVol > lastMicVol - 1)
- {
- stt->micVol = lastMicVol - 1;
- }
- inMicLevelTmp = stt->micVol;
-
- /* Enable the control mechanism to ensure that our measure,
- * Rxx160_LP, is in the correct range.
- */
- stt->activeSpeech = 0;
- stt->Rxx16_LPw32Max = 0;
-#ifdef MIC_LEVEL_FEEDBACK
- //stt->numBlocksMicLvlSat = 0;
-#endif
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\tAGC->ProcessAnalog, frame %d: measure >"
- " 2ndUpperLim, micVol = %d, maxLevel = %d\n",
- stt->fcount,
- stt->micVol,
- stt->maxLevel);
-#endif
- }
- } else if (stt->Rxx160_LPw32 > stt->upperLimit)
- {
- stt->msTooHigh += 2;
- stt->msTooLow = 0;
- stt->changeToSlowMode = 0;
-
- if (stt->msTooHigh > stt->msecSpeechInnerChange)
- {
- /* Lower the recording level */
- stt->msTooHigh = 0;
- /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
- stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53;
-
- /* Reduce the max gain to avoid excessive oscillation
- * (but never drop below the maximum analog level).
- */
- stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
- stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
-
- stt->zeroCtrlMax = stt->micVol;
-
- /* 0.965 in Q15 */
- tmp32 = inMicLevelTmp - stt->minLevel;
- tmpU32 = WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
- stt->micVol = (tmpU32 >> 15) + stt->minLevel;
- if (stt->micVol > lastMicVol - 1)
- {
- stt->micVol = lastMicVol - 1;
- }
- inMicLevelTmp = stt->micVol;
-
-#ifdef MIC_LEVEL_FEEDBACK
- //stt->numBlocksMicLvlSat = 0;
-#endif
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\tAGC->ProcessAnalog, frame %d: measure >"
- " UpperLim, micVol = %d, maxLevel = %d\n",
- stt->fcount,
- stt->micVol,
- stt->maxLevel);
-#endif
- }
- } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit)
- {
- stt->msTooHigh = 0;
- stt->changeToSlowMode = 0;
- stt->msTooLow += 2;
-
- if (stt->msTooLow > stt->msecSpeechOuterChange)
- {
- /* Raise the recording level */
- int16_t index, weightFIX;
- int16_t volNormFIX = 16384; // =1 in Q14.
-
- stt->msTooLow = 0;
-
- /* Normalize the volume level */
- tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
- if (stt->maxInit != stt->minLevel)
- {
- volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
- }
-
- /* Find correct curve */
- WebRtcAgc_ExpCurve(volNormFIX, &index);
-
- /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */
- weightFIX = kOffset1[index] -
- (int16_t)((kSlope1[index] * volNormFIX) >> 13);
-
- /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
- stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
-
- tmp32 = inMicLevelTmp - stt->minLevel;
- tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
- stt->micVol = (tmpU32 >> 14) + stt->minLevel;
- if (stt->micVol < lastMicVol + 2)
- {
- stt->micVol = lastMicVol + 2;
- }
-
- inMicLevelTmp = stt->micVol;
-
-#ifdef MIC_LEVEL_FEEDBACK
- /* Count ms in level saturation */
- //if (stt->micVol > stt->maxAnalog) {
- if (stt->micVol > 150)
- {
- /* mic level is saturated */
- stt->numBlocksMicLvlSat++;
- fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
- }
-#endif
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\tAGC->ProcessAnalog, frame %d: measure <"
- " 2ndLowerLim, micVol = %d\n",
- stt->fcount,
- stt->micVol);
-#endif
- }
- } else if (stt->Rxx160_LPw32 < stt->lowerLimit)
- {
- stt->msTooHigh = 0;
- stt->changeToSlowMode = 0;
- stt->msTooLow += 2;
-
- if (stt->msTooLow > stt->msecSpeechInnerChange)
- {
- /* Raise the recording level */
- int16_t index, weightFIX;
- int16_t volNormFIX = 16384; // =1 in Q14.
-
- stt->msTooLow = 0;
-
- /* Normalize the volume level */
- tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
- if (stt->maxInit != stt->minLevel)
- {
- volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
- }
-
- /* Find correct curve */
- WebRtcAgc_ExpCurve(volNormFIX, &index);
-
- /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */
- weightFIX = kOffset2[index] -
- (int16_t)((kSlope2[index] * volNormFIX) >> 13);
-
- /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
- stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
-
- tmp32 = inMicLevelTmp - stt->minLevel;
- tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
- stt->micVol = (tmpU32 >> 14) + stt->minLevel;
- if (stt->micVol < lastMicVol + 1)
- {
- stt->micVol = lastMicVol + 1;
- }
-
- inMicLevelTmp = stt->micVol;
-
-#ifdef MIC_LEVEL_FEEDBACK
- /* Count ms in level saturation */
- //if (stt->micVol > stt->maxAnalog) {
- if (stt->micVol > 150)
- {
- /* mic level is saturated */
- stt->numBlocksMicLvlSat++;
- fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
- }
-#endif
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n",
- stt->fcount,
- stt->micVol);
-#endif
-
- }
- } else
- {
- /* The signal is inside the desired range which is:
- * lowerLimit < Rxx160_LP/640 < upperLimit
- */
- if (stt->changeToSlowMode > 4000)
- {
- stt->msecSpeechInnerChange = 1000;
- stt->msecSpeechOuterChange = 500;
- stt->upperLimit = stt->upperPrimaryLimit;
- stt->lowerLimit = stt->lowerPrimaryLimit;
- } else
- {
- stt->changeToSlowMode += 2; // in milliseconds
- }
- stt->msTooLow = 0;
- stt->msTooHigh = 0;
-
- stt->micVol = inMicLevelTmp;
-
- }
-#ifdef MIC_LEVEL_FEEDBACK
- if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET)
- {
- stt->micLvlSat = 1;
- fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
- WebRtcAgc_UpdateAgcThresholds(stt);
- WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]),
- stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable,
- stt->analogTarget);
- stt->numBlocksMicLvlSat = 0;
- stt->micLvlSat = 0;
- fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
- fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
- }
-#endif
- }
- }
-
- /* Ensure gain is not increased in presence of echo or after a mute event
- * (but allow the zeroCtrl() increase on the frame of a mute detection).
- */
- if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs))
- {
- if (stt->micVol > lastMicVol)
- {
- stt->micVol = lastMicVol;
- }
- }
-
- /* limit the gain */
- if (stt->micVol > stt->maxLevel)
- {
- stt->micVol = stt->maxLevel;
- } else if (stt->micVol < stt->minOutput)
- {
- stt->micVol = stt->minOutput;
- }
-
- *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale;
-
- return 0;
-}
-
-int WebRtcAgc_Process(void *agcInst, const int16_t* const* in_near,
- size_t num_bands, size_t samples,
- int16_t* const* out, int32_t inMicLevel,
- int32_t *outMicLevel, int16_t echo,
- uint8_t *saturationWarning)
-{
- LegacyAgc* stt;
-
- stt = (LegacyAgc*)agcInst;
-
- //
- if (stt == NULL)
- {
- return -1;
- }
- //
-
-
- if (stt->fs == 8000)
- {
- if (samples != 80)
- {
- return -1;
- }
- } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000)
- {
- if (samples != 160)
- {
- return -1;
- }
- } else
- {
- return -1;
- }
-
- *saturationWarning = 0;
- //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS
- *outMicLevel = inMicLevel;
-
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- stt->fcount++;
-#endif
-
- if (WebRtcAgc_ProcessDigital(&stt->digitalAgc,
- in_near,
- num_bands,
- out,
- stt->fs,
- stt->lowLevelSignal) == -1)
- {
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "AGC->Process, frame %d: Error from DigAGC\n\n",
- stt->fcount);
-#endif
- return -1;
- }
- if (stt->agcMode < kAgcModeFixedDigital &&
- (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital))
- {
- if (WebRtcAgc_ProcessAnalog(agcInst,
- inMicLevel,
- outMicLevel,
- stt->vadMic.logRatio,
- echo,
- saturationWarning) == -1)
- {
- return -1;
- }
- }
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->agcLog,
- "%5d\t%d\t%d\t%d\t%d\n",
- stt->fcount,
- inMicLevel,
- *outMicLevel,
- stt->maxLevel,
- stt->micVol);
-#endif
-
- /* update queue */
- if (stt->inQueue > 1)
- {
- memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
- memcpy(stt->Rxx16w32_array[0],
- stt->Rxx16w32_array[1],
- 5 * sizeof(int32_t));
- }
-
- if (stt->inQueue > 0)
- {
- stt->inQueue--;
- }
-
- return 0;
-}
-
-int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
- LegacyAgc* stt;
- stt = (LegacyAgc*)agcInst;
-
- if (stt == NULL)
- {
- return -1;
- }
-
- if (stt->initFlag != kInitCheck)
- {
- stt->lastError = AGC_UNINITIALIZED_ERROR;
- return -1;
- }
-
- if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue)
- {
- stt->lastError = AGC_BAD_PARAMETER_ERROR;
- return -1;
- }
- stt->limiterEnable = agcConfig.limiterEnable;
- stt->compressionGaindB = agcConfig.compressionGaindB;
- if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31))
- {
- stt->lastError = AGC_BAD_PARAMETER_ERROR;
- return -1;
- }
- stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
-
- if (stt->agcMode == kAgcModeFixedDigital)
- {
- /* Adjust for different parameter interpretation in FixedDigital mode */
- stt->compressionGaindB += agcConfig.targetLevelDbfs;
- }
-
- /* Update threshold levels for analog adaptation */
- WebRtcAgc_UpdateAgcThresholds(stt);
-
- /* Recalculate gain table */
- if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
- stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1)
- {
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "AGC->set_config, frame %d: Error from calcGainTable\n\n",
- stt->fcount);
-#endif
- return -1;
- }
- /* Store the config in a WebRtcAgcConfig */
- stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
- stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
- stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
-
- return 0;
-}
-
-int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) {
- LegacyAgc* stt;
- stt = (LegacyAgc*)agcInst;
-
- if (stt == NULL)
- {
- return -1;
- }
-
- if (config == NULL)
- {
- stt->lastError = AGC_NULL_POINTER_ERROR;
- return -1;
- }
-
- if (stt->initFlag != kInitCheck)
- {
- stt->lastError = AGC_UNINITIALIZED_ERROR;
- return -1;
- }
-
- config->limiterEnable = stt->usedConfig.limiterEnable;
- config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
- config->compressionGaindB = stt->usedConfig.compressionGaindB;
-
- return 0;
-}
-
-void* WebRtcAgc_Create() {
- LegacyAgc* stt = malloc(sizeof(LegacyAgc));
-
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- stt->fpt = fopen("./agc_test_log.txt", "wt");
- stt->agcLog = fopen("./agc_debug_log.txt", "wt");
- stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
-#endif
-
- stt->initFlag = 0;
- stt->lastError = 0;
-
- return stt;
-}
-
-void WebRtcAgc_Free(void *state) {
- LegacyAgc* stt;
-
- stt = (LegacyAgc*)state;
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fclose(stt->fpt);
- fclose(stt->agcLog);
- fclose(stt->digitalAgc.logFile);
-#endif
- free(stt);
-}
-
-/* minLevel - Minimum volume level
- * maxLevel - Maximum volume level
- */
-int WebRtcAgc_Init(void *agcInst, int32_t minLevel, int32_t maxLevel,
- int16_t agcMode, uint32_t fs)
-{
- int32_t max_add, tmp32;
- int16_t i;
- int tmpNorm;
- LegacyAgc* stt;
-
- /* typecast state pointer */
- stt = (LegacyAgc*)agcInst;
-
- if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0)
- {
- stt->lastError = AGC_UNINITIALIZED_ERROR;
- return -1;
- }
-
- /* Analog AGC variables */
- stt->envSum = 0;
-
- /* mode = 0 - Only saturation protection
- * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
- * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
- * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
- */
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- stt->fcount = 0;
- fprintf(stt->fpt, "AGC->Init\n");
-#endif
- if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital)
- {
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
-#endif
- return -1;
- }
- stt->agcMode = agcMode;
- stt->fs = fs;
-
- /* initialize input VAD */
- WebRtcAgc_InitVad(&stt->vadMic);
-
- /* If the volume range is smaller than 0-256 then
- * the levels are shifted up to Q8-domain */
- tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
- stt->scale = tmpNorm - 23;
- if (stt->scale < 0)
- {
- stt->scale = 0;
- }
- // TODO(bjornv): Investigate if we really need to scale up a small range now when we have
- // a guard against zero-increments. For now, we do not support scale up (scale = 0).
- stt->scale = 0;
- maxLevel <<= stt->scale;
- minLevel <<= stt->scale;
-
- /* Make minLevel and maxLevel static in AdaptiveDigital */
- if (stt->agcMode == kAgcModeAdaptiveDigital)
- {
- minLevel = 0;
- maxLevel = 255;
- stt->scale = 0;
- }
- /* The maximum supplemental volume range is based on a vague idea
- * of how much lower the gain will be than the real analog gain. */
- max_add = (maxLevel - minLevel) / 4;
-
- /* Minimum/maximum volume level that can be set */
- stt->minLevel = minLevel;
- stt->maxAnalog = maxLevel;
- stt->maxLevel = maxLevel + max_add;
- stt->maxInit = stt->maxLevel;
-
- stt->zeroCtrlMax = stt->maxAnalog;
- stt->lastInMicLevel = 0;
-
- /* Initialize micVol parameter */
- stt->micVol = stt->maxAnalog;
- if (stt->agcMode == kAgcModeAdaptiveDigital)
- {
- stt->micVol = 127; /* Mid-point of mic level */
- }
- stt->micRef = stt->micVol;
- stt->micGainIdx = 127;
-#ifdef MIC_LEVEL_FEEDBACK
- stt->numBlocksMicLvlSat = 0;
- stt->micLvlSat = 0;
-#endif
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt,
- "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
- stt->minLevel,
- stt->maxAnalog,
- stt->maxLevel);
-#endif
-
- /* Minimum output volume is 4% higher than the available lowest volume level */
- tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
- stt->minOutput = (stt->minLevel + tmp32);
-
- stt->msTooLow = 0;
- stt->msTooHigh = 0;
- stt->changeToSlowMode = 0;
- stt->firstCall = 0;
- stt->msZero = 0;
- stt->muteGuardMs = 0;
- stt->gainTableIdx = 0;
-
- stt->msecSpeechInnerChange = kMsecSpeechInner;
- stt->msecSpeechOuterChange = kMsecSpeechOuter;
-
- stt->activeSpeech = 0;
- stt->Rxx16_LPw32Max = 0;
-
- stt->vadThreshold = kNormalVadThreshold;
- stt->inActive = 0;
-
- for (i = 0; i < RXX_BUFFER_LEN; i++)
- {
- stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
- }
- stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
-
- stt->Rxx16pos = 0;
- stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
-
- for (i = 0; i < 5; i++)
- {
- stt->Rxx16w32_array[0][i] = 0;
- }
- for (i = 0; i < 10; i++)
- {
- stt->env[0][i] = 0;
- stt->env[1][i] = 0;
- }
- stt->inQueue = 0;
-
-#ifdef MIC_LEVEL_FEEDBACK
- stt->targetIdxOffset = 0;
-#endif
-
- WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
-
- stt->initFlag = kInitCheck;
- // Default config settings.
- stt->defaultConfig.limiterEnable = kAgcTrue;
- stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
- stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
-
- if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1)
- {
- stt->lastError = AGC_UNSPECIFIED_ERROR;
- return -1;
- }
- stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
-
- stt->lowLevelSignal = 0;
-
- /* Only positive values are allowed that are not too large */
- if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000))
- {
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
-#endif
- return -1;
- } else
- {
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- fprintf(stt->fpt, "\n");
-#endif
- return 0;
- }
-}
diff --git a/webrtc/modules/audio_processing/agc/legacy/analog_agc.cc b/webrtc/modules/audio_processing/agc/legacy/analog_agc.cc
new file mode 100644
index 0000000..b53e3f9
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc/legacy/analog_agc.cc
@@ -0,0 +1,1238 @@
+/*
+ * 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.
+ */
+
+/*
+ *
+ * Using a feedback system, determines an appropriate analog volume level
+ * given an input signal and current volume level. Targets a conservative
+ * signal level and is intended for use with a digital AGC to apply
+ * additional gain.
+ *
+ */
+
+#include "modules/audio_processing/agc/legacy/analog_agc.h"
+
+#include <stdlib.h>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Errors
+#define AGC_UNSPECIFIED_ERROR 18000
+#define AGC_UNINITIALIZED_ERROR 18002
+#define AGC_NULL_POINTER_ERROR 18003
+#define AGC_BAD_PARAMETER_ERROR 18004
+
+/* The slope of in Q13*/
+static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129,
+ 2372, 1362, 472, 78};
+
+/* The offset in Q14 */
+static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737,
+ 19612, 18805, 17951, 17367};
+
+/* The slope of in Q13*/
+static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
+
+/* The offset in Q14 */
+static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177,
+ 18052, 17920, 17670, 17286};
+
+static const int16_t kMuteGuardTimeMs = 8000;
+static const int16_t kInitCheck = 42;
+static const size_t kNumSubframes = 10;
+
+/* Default settings if config is not used */
+#define AGC_DEFAULT_TARGET_LEVEL 3
+#define AGC_DEFAULT_COMP_GAIN 9
+/* This is the target level for the analog part in ENV scale. To convert to RMS
+ * scale you
+ * have to add OFFSET_ENV_TO_RMS.
+ */
+#define ANALOG_TARGET_LEVEL 11
+#define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2
+/* Offset between RMS scale (analog part) and ENV scale (digital part). This
+ * value actually
+ * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future
+ * replace it with
+ * a table.
+ */
+#define OFFSET_ENV_TO_RMS 9
+/* The reference input level at which the digital part gives an output of
+ * targetLevelDbfs
+ * (desired level) if we have no compression gain. This level should be set high
+ * enough not
+ * to compress the peaks due to the dynamics.
+ */
+#define DIGITAL_REF_AT_0_COMP_GAIN 4
+/* Speed of reference level decrease.
+ */
+#define DIFF_REF_TO_ANALOG 5
+
+/* Size of analog gain table */
+#define GAIN_TBL_LEN 32
+/* Matlab code:
+ * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
+ */
+/* Q12 */
+static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = {
+ 4096, 4251, 4412, 4579, 4752, 4932, 5118, 5312, 5513, 5722, 5938,
+ 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992, 8295, 8609, 8934,
+ 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
+
+/* Gain/Suppression tables for virtual Mic (in Q10) */
+static const uint16_t kGainTableVirtualMic[128] = {
+ 1052, 1081, 1110, 1141, 1172, 1204, 1237, 1271, 1305, 1341, 1378,
+ 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757, 1805, 1854,
+ 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495,
+ 2563, 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357,
+ 3449, 3543, 3640, 3739, 3842, 3947, 4055, 4166, 4280, 4397, 4517,
+ 4640, 4767, 4898, 5032, 5169, 5311, 5456, 5605, 5758, 5916, 6078,
+ 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960, 8178,
+ 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004,
+ 11305, 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807,
+ 15212, 15628, 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923,
+ 20468, 21028, 21603, 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808,
+ 27541, 28295, 29069, 29864, 30681, 31520, 32382};
+static const uint16_t kSuppressionTableVirtualMic[128] = {
+ 1024, 1006, 988, 970, 952, 935, 918, 902, 886, 870, 854, 839, 824, 809, 794,
+ 780, 766, 752, 739, 726, 713, 700, 687, 675, 663, 651, 639, 628, 616, 605,
+ 594, 584, 573, 563, 553, 543, 533, 524, 514, 505, 496, 487, 478, 470, 461,
+ 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378, 371, 364, 358, 351,
+ 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278, 273, 268,
+ 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
+ 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155,
+ 153, 150, 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118,
+ 116, 114, 112, 110, 108, 106, 104, 102};
+
+/* Table for target energy levels. Values in Q(-7)
+ * Matlab code
+ * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n',
+ * round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
+
+static const int32_t kTargetLevelTable[64] = {
+ 134209536, 106606424, 84680493, 67264106, 53429779, 42440782, 33711911,
+ 26778323, 21270778, 16895980, 13420954, 10660642, 8468049, 6726411,
+ 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095,
+ 1066064, 846805, 672641, 534298, 424408, 337119, 267783,
+ 212708, 168960, 134210, 106606, 84680, 67264, 53430,
+ 42441, 33712, 26778, 21271, 16896, 13421, 10661,
+ 8468, 6726, 5343, 4244, 3371, 2678, 2127,
+ 1690, 1342, 1066, 847, 673, 534, 424,
+ 337, 268, 213, 169, 134, 107, 85,
+ 67};
+
+} // namespace
+
+int WebRtcAgc_AddMic(void* state,
+ int16_t* const* in_mic,
+ size_t num_bands,
+ size_t samples) {
+ int32_t nrg, max_nrg, sample, tmp32;
+ int32_t* ptr;
+ uint16_t targetGainIdx, gain;
+ size_t i;
+ int16_t n, L, tmp16, tmp_speech[16];
+ LegacyAgc* stt;
+ stt = reinterpret_cast<LegacyAgc*>(state);
+
+ if (stt->fs == 8000) {
+ L = 8;
+ if (samples != 80) {
+ return -1;
+ }
+ } else {
+ L = 16;
+ if (samples != 160) {
+ return -1;
+ }
+ }
+
+ /* apply slowly varying digital gain */
+ if (stt->micVol > stt->maxAnalog) {
+ /* |maxLevel| is strictly >= |micVol|, so this condition should be
+ * satisfied here, ensuring there is no divide-by-zero. */
+ RTC_DCHECK_GT(stt->maxLevel, stt->maxAnalog);
+
+ /* Q1 */
+ tmp16 = (int16_t)(stt->micVol - stt->maxAnalog);
+ tmp32 = (GAIN_TBL_LEN - 1) * tmp16;
+ tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog);
+ targetGainIdx = tmp32 / tmp16;
+ RTC_DCHECK_LT(targetGainIdx, GAIN_TBL_LEN);
+
+ /* Increment through the table towards the target gain.
+ * If micVol drops below maxAnalog, we allow the gain
+ * to be dropped immediately. */
+ if (stt->gainTableIdx < targetGainIdx) {
+ stt->gainTableIdx++;
+ } else if (stt->gainTableIdx > targetGainIdx) {
+ stt->gainTableIdx--;
+ }
+
+ /* Q12 */
+ gain = kGainTableAnalog[stt->gainTableIdx];
+
+ for (i = 0; i < samples; i++) {
+ size_t j;
+ for (j = 0; j < num_bands; ++j) {
+ sample = (in_mic[j][i] * gain) >> 12;
+ if (sample > 32767) {
+ in_mic[j][i] = 32767;
+ } else if (sample < -32768) {
+ in_mic[j][i] = -32768;
+ } else {
+ in_mic[j][i] = (int16_t)sample;
+ }
+ }
+ }
+ } else {
+ stt->gainTableIdx = 0;
+ }
+
+ /* compute envelope */
+ if (stt->inQueue > 0) {
+ ptr = stt->env[1];
+ } else {
+ ptr = stt->env[0];
+ }
+
+ for (i = 0; i < kNumSubframes; i++) {
+ /* iterate over samples */
+ max_nrg = 0;
+ for (n = 0; n < L; n++) {
+ nrg = in_mic[0][i * L + n] * in_mic[0][i * L + n];
+ if (nrg > max_nrg) {
+ max_nrg = nrg;
+ }
+ }
+ ptr[i] = max_nrg;
+ }
+
+ /* compute energy */
+ if (stt->inQueue > 0) {
+ ptr = stt->Rxx16w32_array[1];
+ } else {
+ ptr = stt->Rxx16w32_array[0];
+ }
+
+ for (i = 0; i < kNumSubframes / 2; i++) {
+ if (stt->fs == 16000) {
+ WebRtcSpl_DownsampleBy2(&in_mic[0][i * 32], 32, tmp_speech,
+ stt->filterState);
+ } else {
+ memcpy(tmp_speech, &in_mic[0][i * 16], 16 * sizeof(int16_t));
+ }
+ /* Compute energy in blocks of 16 samples */
+ ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
+ }
+
+ /* update queue information */
+ if (stt->inQueue == 0) {
+ stt->inQueue = 1;
+ } else {
+ stt->inQueue = 2;
+ }
+
+ /* call VAD (use low band only) */
+ WebRtcAgc_ProcessVad(&stt->vadMic, in_mic[0], samples);
+
+ return 0;
+}
+
+int WebRtcAgc_AddFarend(void* state, const int16_t* in_far, size_t samples) {
+ LegacyAgc* stt = reinterpret_cast<LegacyAgc*>(state);
+
+ int err = WebRtcAgc_GetAddFarendError(state, samples);
+
+ if (err != 0)
+ return err;
+
+ return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
+}
+
+int WebRtcAgc_GetAddFarendError(void* state, size_t samples) {
+ LegacyAgc* stt;
+ stt = reinterpret_cast<LegacyAgc*>(state);
+
+ if (stt == NULL)
+ return -1;
+
+ if (stt->fs == 8000) {
+ if (samples != 80)
+ return -1;
+ } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
+ if (samples != 160)
+ return -1;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+int WebRtcAgc_VirtualMic(void* agcInst,
+ int16_t* const* in_near,
+ size_t num_bands,
+ size_t samples,
+ int32_t micLevelIn,
+ int32_t* micLevelOut) {
+ int32_t tmpFlt, micLevelTmp, gainIdx;
+ uint16_t gain;
+ size_t ii, j;
+ LegacyAgc* stt;
+
+ uint32_t nrg;
+ size_t sampleCntr;
+ uint32_t frameNrg = 0;
+ uint32_t frameNrgLimit = 5500;
+ int16_t numZeroCrossing = 0;
+ const int16_t kZeroCrossingLowLim = 15;
+ const int16_t kZeroCrossingHighLim = 20;
+
+ stt = reinterpret_cast<LegacyAgc*>(agcInst);
+
+ /*
+ * Before applying gain decide if this is a low-level signal.
+ * The idea is that digital AGC will not adapt to low-level
+ * signals.
+ */
+ if (stt->fs != 8000) {
+ frameNrgLimit = frameNrgLimit << 1;
+ }
+
+ frameNrg = (uint32_t)(in_near[0][0] * in_near[0][0]);
+ for (sampleCntr = 1; sampleCntr < samples; sampleCntr++) {
+ // increment frame energy if it is less than the limit
+ // the correct value of the energy is not important
+ if (frameNrg < frameNrgLimit) {
+ nrg = (uint32_t)(in_near[0][sampleCntr] * in_near[0][sampleCntr]);
+ frameNrg += nrg;
+ }
+
+ // Count the zero crossings
+ numZeroCrossing +=
+ ((in_near[0][sampleCntr] ^ in_near[0][sampleCntr - 1]) < 0);
+ }
+
+ if ((frameNrg < 500) || (numZeroCrossing <= 5)) {
+ stt->lowLevelSignal = 1;
+ } else if (numZeroCrossing <= kZeroCrossingLowLim) {
+ stt->lowLevelSignal = 0;
+ } else if (frameNrg <= frameNrgLimit) {
+ stt->lowLevelSignal = 1;
+ } else if (numZeroCrossing >= kZeroCrossingHighLim) {
+ stt->lowLevelSignal = 1;
+ } else {
+ stt->lowLevelSignal = 0;
+ }
+
+ micLevelTmp = micLevelIn << stt->scale;
+ /* Set desired level */
+ gainIdx = stt->micVol;
+ if (stt->micVol > stt->maxAnalog) {
+ gainIdx = stt->maxAnalog;
+ }
+ if (micLevelTmp != stt->micRef) {
+ /* Something has happened with the physical level, restart. */
+ stt->micRef = micLevelTmp;
+ stt->micVol = 127;
+ *micLevelOut = 127;
+ stt->micGainIdx = 127;
+ gainIdx = 127;
+ }
+ /* Pre-process the signal to emulate the microphone level. */
+ /* Take one step at a time in the gain table. */
+ if (gainIdx > 127) {
+ gain = kGainTableVirtualMic[gainIdx - 128];
+ } else {
+ gain = kSuppressionTableVirtualMic[127 - gainIdx];
+ }
+ for (ii = 0; ii < samples; ii++) {
+ tmpFlt = (in_near[0][ii] * gain) >> 10;
+ if (tmpFlt > 32767) {
+ tmpFlt = 32767;
+ gainIdx--;
+ if (gainIdx >= 127) {
+ gain = kGainTableVirtualMic[gainIdx - 127];
+ } else {
+ gain = kSuppressionTableVirtualMic[127 - gainIdx];
+ }
+ }
+ if (tmpFlt < -32768) {
+ tmpFlt = -32768;
+ gainIdx--;
+ if (gainIdx >= 127) {
+ gain = kGainTableVirtualMic[gainIdx - 127];
+ } else {
+ gain = kSuppressionTableVirtualMic[127 - gainIdx];
+ }
+ }
+ in_near[0][ii] = (int16_t)tmpFlt;
+ for (j = 1; j < num_bands; ++j) {
+ tmpFlt = (in_near[j][ii] * gain) >> 10;
+ if (tmpFlt > 32767) {
+ tmpFlt = 32767;
+ }
+ if (tmpFlt < -32768) {
+ tmpFlt = -32768;
+ }
+ in_near[j][ii] = (int16_t)tmpFlt;
+ }
+ }
+ /* Set the level we (finally) used */
+ stt->micGainIdx = gainIdx;
+ // *micLevelOut = stt->micGainIdx;
+ *micLevelOut = stt->micGainIdx >> stt->scale;
+ /* Add to Mic as if it was the output from a true microphone */
+ if (WebRtcAgc_AddMic(agcInst, in_near, num_bands, samples) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+void WebRtcAgc_UpdateAgcThresholds(LegacyAgc* stt) {
+ int16_t tmp16;
+
+ /* Set analog target level in envelope dBOv scale */
+ tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
+ tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
+ stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
+ if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN) {
+ stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
+ }
+ if (stt->agcMode == kAgcModeFixedDigital) {
+ /* Adjust for different parameter interpretation in FixedDigital mode */
+ stt->analogTarget = stt->compressionGaindB;
+ }
+ /* Since the offset between RMS and ENV is not constant, we should make this
+ * into a
+ * table, but for now, we'll stick with a constant, tuned for the chosen
+ * analog
+ * target level.
+ */
+ stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
+ /* Analog adaptation limits */
+ /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
+ stt->analogTargetLevel =
+ kRxxBufferLen * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
+ stt->startUpperLimit =
+ kRxxBufferLen * kTargetLevelTable[stt->targetIdx - 1]; /* -19 dBov */
+ stt->startLowerLimit =
+ kRxxBufferLen * kTargetLevelTable[stt->targetIdx + 1]; /* -21 dBov */
+ stt->upperPrimaryLimit =
+ kRxxBufferLen * kTargetLevelTable[stt->targetIdx - 2]; /* -18 dBov */
+ stt->lowerPrimaryLimit =
+ kRxxBufferLen * kTargetLevelTable[stt->targetIdx + 2]; /* -22 dBov */
+ stt->upperSecondaryLimit =
+ kRxxBufferLen * kTargetLevelTable[stt->targetIdx - 5]; /* -15 dBov */
+ stt->lowerSecondaryLimit =
+ kRxxBufferLen * kTargetLevelTable[stt->targetIdx + 5]; /* -25 dBov */
+ stt->upperLimit = stt->startUpperLimit;
+ stt->lowerLimit = stt->startLowerLimit;
+}
+
+void WebRtcAgc_SaturationCtrl(LegacyAgc* stt,
+ uint8_t* saturated,
+ int32_t* env) {
+ int16_t i, tmpW16;
+
+ /* Check if the signal is saturated */
+ for (i = 0; i < 10; i++) {
+ tmpW16 = (int16_t)(env[i] >> 20);
+ if (tmpW16 > 875) {
+ stt->envSum += tmpW16;
+ }
+ }
+
+ if (stt->envSum > 25000) {
+ *saturated = 1;
+ stt->envSum = 0;
+ }
+
+ /* stt->envSum *= 0.99; */
+ stt->envSum = (int16_t)((stt->envSum * 32440) >> 15);
+}
+
+void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) {
+ int16_t i;
+ int64_t tmp = 0;
+ int32_t midVal;
+
+ /* Is the input signal zero? */
+ for (i = 0; i < 10; i++) {
+ tmp += env[i];
+ }
+
+ /* Each block is allowed to have a few non-zero
+ * samples.
+ */
+ if (tmp < 500) {
+ stt->msZero += 10;
+ } else {
+ stt->msZero = 0;
+ }
+
+ if (stt->muteGuardMs > 0) {
+ stt->muteGuardMs -= 10;
+ }
+
+ if (stt->msZero > 500) {
+ stt->msZero = 0;
+
+ /* Increase microphone level only if it's less than 50% */
+ midVal = (stt->maxAnalog + stt->minLevel + 1) / 2;
+ if (*inMicLevel < midVal) {
+ /* *inMicLevel *= 1.1; */
+ *inMicLevel = (1126 * *inMicLevel) >> 10;
+ /* Reduces risk of a muted mic repeatedly triggering excessive levels due
+ * to zero signal detection. */
+ *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
+ stt->micVol = *inMicLevel;
+ }
+
+ stt->activeSpeech = 0;
+ stt->Rxx16_LPw32Max = 0;
+
+ /* The AGC has a tendency (due to problems with the VAD parameters), to
+ * vastly increase the volume after a muting event. This timer prevents
+ * upwards adaptation for a short period. */
+ stt->muteGuardMs = kMuteGuardTimeMs;
+ }
+}
+
+void WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc* stt) {
+ /* Check if the near end speaker is inactive.
+ * If that is the case the VAD threshold is
+ * increased since the VAD speech model gets
+ * more sensitive to any sound after a long
+ * silence.
+ */
+
+ int32_t tmp32;
+ int16_t vadThresh;
+
+ if (stt->vadMic.stdLongTerm < 2500) {
+ stt->vadThreshold = 1500;
+ } else {
+ vadThresh = kNormalVadThreshold;
+ if (stt->vadMic.stdLongTerm < 4500) {
+ /* Scale between min and max threshold */
+ vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2;
+ }
+
+ /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
+ tmp32 = vadThresh + 31 * stt->vadThreshold;
+ stt->vadThreshold = (int16_t)(tmp32 >> 5);
+ }
+}
+
+void WebRtcAgc_ExpCurve(int16_t volume, int16_t* index) {
+ // volume in Q14
+ // index in [0-7]
+ /* 8 different curves */
+ if (volume > 5243) {
+ if (volume > 7864) {
+ if (volume > 12124) {
+ *index = 7;
+ } else {
+ *index = 6;
+ }
+ } else {
+ if (volume > 6554) {
+ *index = 5;
+ } else {
+ *index = 4;
+ }
+ }
+ } else {
+ if (volume > 2621) {
+ if (volume > 3932) {
+ *index = 3;
+ } else {
+ *index = 2;
+ }
+ } else {
+ if (volume > 1311) {
+ *index = 1;
+ } else {
+ *index = 0;
+ }
+ }
+ }
+}
+
+int32_t WebRtcAgc_ProcessAnalog(void* state,
+ int32_t inMicLevel,
+ int32_t* outMicLevel,
+ int16_t vadLogRatio,
+ int16_t echo,
+ uint8_t* saturationWarning) {
+ uint32_t tmpU32;
+ int32_t Rxx16w32, tmp32;
+ int32_t inMicLevelTmp, lastMicVol;
+ int16_t i;
+ uint8_t saturated = 0;
+ LegacyAgc* stt;
+
+ stt = reinterpret_cast<LegacyAgc*>(state);
+ inMicLevelTmp = inMicLevel << stt->scale;
+
+ if (inMicLevelTmp > stt->maxAnalog) {
+ return -1;
+ } else if (inMicLevelTmp < stt->minLevel) {
+ return -1;
+ }
+
+ if (stt->firstCall == 0) {
+ int32_t tmpVol;
+ stt->firstCall = 1;
+ tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
+ tmpVol = (stt->minLevel + tmp32);
+
+ /* If the mic level is very low at start, increase it! */
+ if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog)) {
+ inMicLevelTmp = tmpVol;
+ }
+ stt->micVol = inMicLevelTmp;
+ }
+
+ /* Set the mic level to the previous output value if there is digital input
+ * gain */
+ if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog)) {
+ inMicLevelTmp = stt->micVol;
+ }
+
+ /* If the mic level was manually changed to a very low value raise it! */
+ if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput)) {
+ tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
+ inMicLevelTmp = (stt->minLevel + tmp32);
+ stt->micVol = inMicLevelTmp;
+ }
+
+ if (inMicLevelTmp != stt->micVol) {
+ if (inMicLevel == stt->lastInMicLevel) {
+ // We requested a volume adjustment, but it didn't occur. This is
+ // probably due to a coarse quantization of the volume slider.
+ // Restore the requested value to prevent getting stuck.
+ inMicLevelTmp = stt->micVol;
+ } else {
+ // As long as the value changed, update to match.
+ stt->micVol = inMicLevelTmp;
+ }
+ }
+
+ if (inMicLevelTmp > stt->maxLevel) {
+ // Always allow the user to raise the volume above the maxLevel.
+ stt->maxLevel = inMicLevelTmp;
+ }
+
+ // Store last value here, after we've taken care of manual updates etc.
+ stt->lastInMicLevel = inMicLevel;
+ lastMicVol = stt->micVol;
+
+ /* Checks if the signal is saturated. Also a check if individual samples
+ * are larger than 12000 is done. If they are the counter for increasing
+ * the volume level is set to -100ms
+ */
+ WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
+
+ /* The AGC is always allowed to lower the level if the signal is saturated */
+ if (saturated == 1) {
+ /* Lower the recording level
+ * Rxx160_LP is adjusted down because it is so slow it could
+ * cause the AGC to make wrong decisions. */
+ /* stt->Rxx160_LPw32 *= 0.875; */
+ stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7;
+
+ stt->zeroCtrlMax = stt->micVol;
+
+ /* stt->micVol *= 0.903; */
+ tmp32 = inMicLevelTmp - stt->minLevel;
+ tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
+ stt->micVol = (tmpU32 >> 15) + stt->minLevel;
+ if (stt->micVol > lastMicVol - 2) {
+ stt->micVol = lastMicVol - 2;
+ }
+ inMicLevelTmp = stt->micVol;
+
+ if (stt->micVol < stt->minOutput) {
+ *saturationWarning = 1;
+ }
+
+ /* Reset counter for decrease of volume level to avoid
+ * decreasing too much. The saturation control can still
+ * lower the level if needed. */
+ stt->msTooHigh = -100;
+
+ /* Enable the control mechanism to ensure that our measure,
+ * Rxx160_LP, is in the correct range. This must be done since
+ * the measure is very slow. */
+ stt->activeSpeech = 0;
+ stt->Rxx16_LPw32Max = 0;
+
+ /* Reset to initial values */
+ stt->msecSpeechInnerChange = kMsecSpeechInner;
+ stt->msecSpeechOuterChange = kMsecSpeechOuter;
+ stt->changeToSlowMode = 0;
+
+ stt->muteGuardMs = 0;
+
+ stt->upperLimit = stt->startUpperLimit;
+ stt->lowerLimit = stt->startLowerLimit;
+ }
+
+ /* Check if the input speech is zero. If so the mic volume
+ * is increased. On some computers the input is zero up as high
+ * level as 17% */
+ WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
+
+ /* Check if the near end speaker is inactive.
+ * If that is the case the VAD threshold is
+ * increased since the VAD speech model gets
+ * more sensitive to any sound after a long
+ * silence.
+ */
+ WebRtcAgc_SpeakerInactiveCtrl(stt);
+
+ for (i = 0; i < 5; i++) {
+ /* Computed on blocks of 16 samples */
+
+ Rxx16w32 = stt->Rxx16w32_array[0][i];
+
+ /* Rxx160w32 in Q(-7) */
+ tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3;
+ stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
+ stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
+
+ /* Circular buffer */
+ stt->Rxx16pos++;
+ if (stt->Rxx16pos == kRxxBufferLen) {
+ stt->Rxx16pos = 0;
+ }
+
+ /* Rxx16_LPw32 in Q(-4) */
+ tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm;
+ stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
+
+ if (vadLogRatio > stt->vadThreshold) {
+ /* Speech detected! */
+
+ /* Check if Rxx160_LP is in the correct range. If
+ * it is too high/low then we set it to the maximum of
+ * Rxx16_LPw32 during the first 200ms of speech.
+ */
+ if (stt->activeSpeech < 250) {
+ stt->activeSpeech += 2;
+
+ if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max) {
+ stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
+ }
+ } else if (stt->activeSpeech == 250) {
+ stt->activeSpeech += 2;
+ tmp32 = stt->Rxx16_LPw32Max >> 3;
+ stt->Rxx160_LPw32 = tmp32 * kRxxBufferLen;
+ }
+
+ tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm;
+ stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
+
+ if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit) {
+ stt->msTooHigh += 2;
+ stt->msTooLow = 0;
+ stt->changeToSlowMode = 0;
+
+ if (stt->msTooHigh > stt->msecSpeechOuterChange) {
+ stt->msTooHigh = 0;
+
+ /* Lower the recording level */
+ /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
+ tmp32 = stt->Rxx160_LPw32 >> 6;
+ stt->Rxx160_LPw32 = tmp32 * 53;
+
+ /* Reduce the max gain to avoid excessive oscillation
+ * (but never drop below the maximum analog level).
+ */
+ stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
+ stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
+
+ stt->zeroCtrlMax = stt->micVol;
+
+ /* 0.95 in Q15 */
+ tmp32 = inMicLevelTmp - stt->minLevel;
+ tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
+ stt->micVol = (tmpU32 >> 15) + stt->minLevel;
+ if (stt->micVol > lastMicVol - 1) {
+ stt->micVol = lastMicVol - 1;
+ }
+ inMicLevelTmp = stt->micVol;
+
+ /* Enable the control mechanism to ensure that our measure,
+ * Rxx160_LP, is in the correct range.
+ */
+ stt->activeSpeech = 0;
+ stt->Rxx16_LPw32Max = 0;
+ }
+ } else if (stt->Rxx160_LPw32 > stt->upperLimit) {
+ stt->msTooHigh += 2;
+ stt->msTooLow = 0;
+ stt->changeToSlowMode = 0;
+
+ if (stt->msTooHigh > stt->msecSpeechInnerChange) {
+ /* Lower the recording level */
+ stt->msTooHigh = 0;
+ /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
+ stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53;
+
+ /* Reduce the max gain to avoid excessive oscillation
+ * (but never drop below the maximum analog level).
+ */
+ stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
+ stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
+
+ stt->zeroCtrlMax = stt->micVol;
+
+ /* 0.965 in Q15 */
+ tmp32 = inMicLevelTmp - stt->minLevel;
+ tmpU32 =
+ WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
+ stt->micVol = (tmpU32 >> 15) + stt->minLevel;
+ if (stt->micVol > lastMicVol - 1) {
+ stt->micVol = lastMicVol - 1;
+ }
+ inMicLevelTmp = stt->micVol;
+ }
+ } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit) {
+ stt->msTooHigh = 0;
+ stt->changeToSlowMode = 0;
+ stt->msTooLow += 2;
+
+ if (stt->msTooLow > stt->msecSpeechOuterChange) {
+ /* Raise the recording level */
+ int16_t index, weightFIX;
+ int16_t volNormFIX = 16384; // =1 in Q14.
+
+ stt->msTooLow = 0;
+
+ /* Normalize the volume level */
+ tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
+ if (stt->maxInit != stt->minLevel) {
+ volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
+ }
+
+ /* Find correct curve */
+ WebRtcAgc_ExpCurve(volNormFIX, &index);
+
+ /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05
+ */
+ weightFIX =
+ kOffset1[index] - (int16_t)((kSlope1[index] * volNormFIX) >> 13);
+
+ /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
+ stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
+
+ tmp32 = inMicLevelTmp - stt->minLevel;
+ tmpU32 =
+ ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
+ stt->micVol = (tmpU32 >> 14) + stt->minLevel;
+ if (stt->micVol < lastMicVol + 2) {
+ stt->micVol = lastMicVol + 2;
+ }
+
+ inMicLevelTmp = stt->micVol;
+ }
+ } else if (stt->Rxx160_LPw32 < stt->lowerLimit) {
+ stt->msTooHigh = 0;
+ stt->changeToSlowMode = 0;
+ stt->msTooLow += 2;
+
+ if (stt->msTooLow > stt->msecSpeechInnerChange) {
+ /* Raise the recording level */
+ int16_t index, weightFIX;
+ int16_t volNormFIX = 16384; // =1 in Q14.
+
+ stt->msTooLow = 0;
+
+ /* Normalize the volume level */
+ tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
+ if (stt->maxInit != stt->minLevel) {
+ volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
+ }
+
+ /* Find correct curve */
+ WebRtcAgc_ExpCurve(volNormFIX, &index);
+
+ /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1
+ */
+ weightFIX =
+ kOffset2[index] - (int16_t)((kSlope2[index] * volNormFIX) >> 13);
+
+ /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
+ stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
+
+ tmp32 = inMicLevelTmp - stt->minLevel;
+ tmpU32 =
+ ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
+ stt->micVol = (tmpU32 >> 14) + stt->minLevel;
+ if (stt->micVol < lastMicVol + 1) {
+ stt->micVol = lastMicVol + 1;
+ }
+
+ inMicLevelTmp = stt->micVol;
+ }
+ } else {
+ /* The signal is inside the desired range which is:
+ * lowerLimit < Rxx160_LP/640 < upperLimit
+ */
+ if (stt->changeToSlowMode > 4000) {
+ stt->msecSpeechInnerChange = 1000;
+ stt->msecSpeechOuterChange = 500;
+ stt->upperLimit = stt->upperPrimaryLimit;
+ stt->lowerLimit = stt->lowerPrimaryLimit;
+ } else {
+ stt->changeToSlowMode += 2; // in milliseconds
+ }
+ stt->msTooLow = 0;
+ stt->msTooHigh = 0;
+
+ stt->micVol = inMicLevelTmp;
+ }
+ }
+ }
+
+ /* Ensure gain is not increased in presence of echo or after a mute event
+ * (but allow the zeroCtrl() increase on the frame of a mute detection).
+ */
+ if (echo == 1 ||
+ (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs)) {
+ if (stt->micVol > lastMicVol) {
+ stt->micVol = lastMicVol;
+ }
+ }
+
+ /* limit the gain */
+ if (stt->micVol > stt->maxLevel) {
+ stt->micVol = stt->maxLevel;
+ } else if (stt->micVol < stt->minOutput) {
+ stt->micVol = stt->minOutput;
+ }
+
+ *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale;
+
+ return 0;
+}
+
+int WebRtcAgc_Analyze(void* agcInst,
+ const int16_t* const* in_near,
+ size_t num_bands,
+ size_t samples,
+ int32_t inMicLevel,
+ int32_t* outMicLevel,
+ int16_t echo,
+ uint8_t* saturationWarning,
+ int32_t gains[11]) {
+ LegacyAgc* stt = reinterpret_cast<LegacyAgc*>(agcInst);
+
+ if (stt == NULL) {
+ return -1;
+ }
+
+ if (stt->fs == 8000) {
+ if (samples != 80) {
+ return -1;
+ }
+ } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
+ if (samples != 160) {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+
+ *saturationWarning = 0;
+ // TODO(minyue): PUT IN RANGE CHECKING FOR INPUT LEVELS
+ *outMicLevel = inMicLevel;
+
+ int32_t error =
+ WebRtcAgc_ComputeDigitalGains(&stt->digitalAgc, in_near, num_bands,
+ stt->fs, stt->lowLevelSignal, gains);
+ if (error == -1) {
+ return -1;
+ }
+
+ if (stt->agcMode < kAgcModeFixedDigital &&
+ (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital)) {
+ if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevel, outMicLevel,
+ stt->vadMic.logRatio, echo,
+ saturationWarning) == -1) {
+ return -1;
+ }
+ }
+
+ /* update queue */
+ if (stt->inQueue > 1) {
+ memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
+ memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(int32_t));
+ }
+
+ if (stt->inQueue > 0) {
+ stt->inQueue--;
+ }
+
+ return 0;
+}
+
+int WebRtcAgc_Process(const void* agcInst,
+ const int32_t gains[11],
+ const int16_t* const* in_near,
+ size_t num_bands,
+ int16_t* const* out) {
+ const LegacyAgc* stt = (const LegacyAgc*)agcInst;
+ return WebRtcAgc_ApplyDigitalGains(gains, num_bands, stt->fs, in_near, out);
+}
+
+int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
+ LegacyAgc* stt;
+ stt = reinterpret_cast<LegacyAgc*>(agcInst);
+
+ if (stt == NULL) {
+ return -1;
+ }
+
+ if (stt->initFlag != kInitCheck) {
+ stt->lastError = AGC_UNINITIALIZED_ERROR;
+ return -1;
+ }
+
+ if (agcConfig.limiterEnable != kAgcFalse &&
+ agcConfig.limiterEnable != kAgcTrue) {
+ stt->lastError = AGC_BAD_PARAMETER_ERROR;
+ return -1;
+ }
+ stt->limiterEnable = agcConfig.limiterEnable;
+ stt->compressionGaindB = agcConfig.compressionGaindB;
+ if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31)) {
+ stt->lastError = AGC_BAD_PARAMETER_ERROR;
+ return -1;
+ }
+ stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
+
+ if (stt->agcMode == kAgcModeFixedDigital) {
+ /* Adjust for different parameter interpretation in FixedDigital mode */
+ stt->compressionGaindB += agcConfig.targetLevelDbfs;
+ }
+
+ /* Update threshold levels for analog adaptation */
+ WebRtcAgc_UpdateAgcThresholds(stt);
+
+ /* Recalculate gain table */
+ if (WebRtcAgc_CalculateGainTable(
+ &(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
+ stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1) {
+ return -1;
+ }
+ /* Store the config in a WebRtcAgcConfig */
+ stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
+ stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
+ stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
+
+ return 0;
+}
+
+int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) {
+ LegacyAgc* stt;
+ stt = reinterpret_cast<LegacyAgc*>(agcInst);
+
+ if (stt == NULL) {
+ return -1;
+ }
+
+ if (config == NULL) {
+ stt->lastError = AGC_NULL_POINTER_ERROR;
+ return -1;
+ }
+
+ if (stt->initFlag != kInitCheck) {
+ stt->lastError = AGC_UNINITIALIZED_ERROR;
+ return -1;
+ }
+
+ config->limiterEnable = stt->usedConfig.limiterEnable;
+ config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
+ config->compressionGaindB = stt->usedConfig.compressionGaindB;
+
+ return 0;
+}
+
+void* WebRtcAgc_Create() {
+ LegacyAgc* stt = static_cast<LegacyAgc*>(malloc(sizeof(LegacyAgc)));
+
+ stt->initFlag = 0;
+ stt->lastError = 0;
+
+ return stt;
+}
+
+void WebRtcAgc_Free(void* state) {
+ LegacyAgc* stt;
+
+ stt = reinterpret_cast<LegacyAgc*>(state);
+ free(stt);
+}
+
+/* minLevel - Minimum volume level
+ * maxLevel - Maximum volume level
+ */
+int WebRtcAgc_Init(void* agcInst,
+ int32_t minLevel,
+ int32_t maxLevel,
+ int16_t agcMode,
+ uint32_t fs) {
+ int32_t max_add, tmp32;
+ int16_t i;
+ int tmpNorm;
+ LegacyAgc* stt;
+
+ /* typecast state pointer */
+ stt = reinterpret_cast<LegacyAgc*>(agcInst);
+
+ if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0) {
+ stt->lastError = AGC_UNINITIALIZED_ERROR;
+ return -1;
+ }
+
+ /* Analog AGC variables */
+ stt->envSum = 0;
+
+ /* mode = 0 - Only saturation protection
+ * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3
+ * dBOv)]
+ * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3
+ * dBOv)]
+ * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
+ */
+ if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital) {
+ return -1;
+ }
+ stt->agcMode = agcMode;
+ stt->fs = fs;
+
+ /* initialize input VAD */
+ WebRtcAgc_InitVad(&stt->vadMic);
+
+ /* If the volume range is smaller than 0-256 then
+ * the levels are shifted up to Q8-domain */
+ tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
+ stt->scale = tmpNorm - 23;
+ if (stt->scale < 0) {
+ stt->scale = 0;
+ }
+ // TODO(bjornv): Investigate if we really need to scale up a small range now
+ // when we have
+ // a guard against zero-increments. For now, we do not support scale up (scale
+ // = 0).
+ stt->scale = 0;
+ maxLevel <<= stt->scale;
+ minLevel <<= stt->scale;
+
+ /* Make minLevel and maxLevel static in AdaptiveDigital */
+ if (stt->agcMode == kAgcModeAdaptiveDigital) {
+ minLevel = 0;
+ maxLevel = 255;
+ stt->scale = 0;
+ }
+ /* The maximum supplemental volume range is based on a vague idea
+ * of how much lower the gain will be than the real analog gain. */
+ max_add = (maxLevel - minLevel) / 4;
+
+ /* Minimum/maximum volume level that can be set */
+ stt->minLevel = minLevel;
+ stt->maxAnalog = maxLevel;
+ stt->maxLevel = maxLevel + max_add;
+ stt->maxInit = stt->maxLevel;
+
+ stt->zeroCtrlMax = stt->maxAnalog;
+ stt->lastInMicLevel = 0;
+
+ /* Initialize micVol parameter */
+ stt->micVol = stt->maxAnalog;
+ if (stt->agcMode == kAgcModeAdaptiveDigital) {
+ stt->micVol = 127; /* Mid-point of mic level */
+ }
+ stt->micRef = stt->micVol;
+ stt->micGainIdx = 127;
+
+ /* Minimum output volume is 4% higher than the available lowest volume level
+ */
+ tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
+ stt->minOutput = (stt->minLevel + tmp32);
+
+ stt->msTooLow = 0;
+ stt->msTooHigh = 0;
+ stt->changeToSlowMode = 0;
+ stt->firstCall = 0;
+ stt->msZero = 0;
+ stt->muteGuardMs = 0;
+ stt->gainTableIdx = 0;
+
+ stt->msecSpeechInnerChange = kMsecSpeechInner;
+ stt->msecSpeechOuterChange = kMsecSpeechOuter;
+
+ stt->activeSpeech = 0;
+ stt->Rxx16_LPw32Max = 0;
+
+ stt->vadThreshold = kNormalVadThreshold;
+ stt->inActive = 0;
+
+ for (i = 0; i < kRxxBufferLen; i++) {
+ stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
+ }
+ stt->Rxx160w32 = 125 * kRxxBufferLen; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
+
+ stt->Rxx16pos = 0;
+ stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
+
+ for (i = 0; i < 5; i++) {
+ stt->Rxx16w32_array[0][i] = 0;
+ }
+ for (i = 0; i < 10; i++) {
+ stt->env[0][i] = 0;
+ stt->env[1][i] = 0;
+ }
+ stt->inQueue = 0;
+
+ WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
+
+ stt->initFlag = kInitCheck;
+ // Default config settings.
+ stt->defaultConfig.limiterEnable = kAgcTrue;
+ stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
+ stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
+
+ if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1) {
+ stt->lastError = AGC_UNSPECIFIED_ERROR;
+ return -1;
+ }
+ stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
+
+ stt->lowLevelSignal = 0;
+
+ /* Only positive values are allowed that are not too large */
+ if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000)) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc/legacy/analog_agc.h b/webrtc/modules/audio_processing/agc/legacy/analog_agc.h
index 820221a..22cd924 100644
--- a/webrtc/modules/audio_processing/agc/legacy/analog_agc.h
+++ b/webrtc/modules/audio_processing/agc/legacy/analog_agc.h
@@ -8,17 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
+#ifndef MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
+#define MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
-//#define MIC_LEVEL_FEEDBACK
-#ifdef WEBRTC_AGC_DEBUG_DUMP
-#include <stdio.h>
-#endif
-#include "webrtc/modules/audio_processing/agc/legacy/digital_agc.h"
-#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_processing/agc/legacy/digital_agc.h"
+#include "modules/audio_processing/agc/legacy/gain_control.h"
+
+namespace webrtc {
/* Analog Automatic Gain Control variables:
* Constant declarations (inner limits inside which no changes are done)
@@ -32,102 +29,90 @@
* of our measure Rxx160_LP. Remember that the levels are in blocks of 16 in
* Q(-7). (Example matlab code: round(db2pow(-21.2)*16/2^7) )
*/
-#define RXX_BUFFER_LEN 10
+constexpr int16_t kRxxBufferLen = 10;
static const int16_t kMsecSpeechInner = 520;
static const int16_t kMsecSpeechOuter = 340;
static const int16_t kNormalVadThreshold = 400;
-static const int16_t kAlphaShortTerm = 6; // 1 >> 6 = 0.0156
-static const int16_t kAlphaLongTerm = 10; // 1 >> 10 = 0.000977
-
-typedef struct
-{
- // Configurable parameters/variables
- uint32_t fs; // Sampling frequency
- int16_t compressionGaindB; // Fixed gain level in dB
- int16_t targetLevelDbfs; // Target level in -dBfs of envelope (default -3)
- int16_t agcMode; // Hard coded mode (adaptAna/adaptDig/fixedDig)
- uint8_t limiterEnable; // Enabling limiter (on/off (default off))
- WebRtcAgcConfig defaultConfig;
- WebRtcAgcConfig usedConfig;
-
- // General variables
- int16_t initFlag;
- int16_t lastError;
-
- // Target level parameters
- // Based on the above: analogTargetLevel = round((32767*10^(-22/20))^2*16/2^7)
- int32_t analogTargetLevel; // = RXX_BUFFER_LEN * 846805; -22 dBfs
- int32_t startUpperLimit; // = RXX_BUFFER_LEN * 1066064; -21 dBfs
- int32_t startLowerLimit; // = RXX_BUFFER_LEN * 672641; -23 dBfs
- int32_t upperPrimaryLimit; // = RXX_BUFFER_LEN * 1342095; -20 dBfs
- int32_t lowerPrimaryLimit; // = RXX_BUFFER_LEN * 534298; -24 dBfs
- int32_t upperSecondaryLimit;// = RXX_BUFFER_LEN * 2677832; -17 dBfs
- int32_t lowerSecondaryLimit;// = RXX_BUFFER_LEN * 267783; -27 dBfs
- uint16_t targetIdx; // Table index for corresponding target level
-#ifdef MIC_LEVEL_FEEDBACK
- uint16_t targetIdxOffset; // Table index offset for level compensation
-#endif
- int16_t analogTarget; // Digital reference level in ENV scale
-
- // Analog AGC specific variables
- int32_t filterState[8]; // For downsampling wb to nb
- int32_t upperLimit; // Upper limit for mic energy
- int32_t lowerLimit; // Lower limit for mic energy
- int32_t Rxx160w32; // Average energy for one frame
- int32_t Rxx16_LPw32; // Low pass filtered subframe energies
- int32_t Rxx160_LPw32; // Low pass filtered frame energies
- int32_t Rxx16_LPw32Max; // Keeps track of largest energy subframe
- int32_t Rxx16_vectorw32[RXX_BUFFER_LEN];// Array with subframe energies
- int32_t Rxx16w32_array[2][5];// Energy values of microphone signal
- int32_t env[2][10]; // Envelope values of subframes
-
- int16_t Rxx16pos; // Current position in the Rxx16_vectorw32
- int16_t envSum; // Filtered scaled envelope in subframes
- int16_t vadThreshold; // Threshold for VAD decision
- int16_t inActive; // Inactive time in milliseconds
- int16_t msTooLow; // Milliseconds of speech at a too low level
- int16_t msTooHigh; // Milliseconds of speech at a too high level
- int16_t changeToSlowMode; // Change to slow mode after some time at target
- int16_t firstCall; // First call to the process-function
- int16_t msZero; // Milliseconds of zero input
- int16_t msecSpeechOuterChange;// Min ms of speech between volume changes
- int16_t msecSpeechInnerChange;// Min ms of speech between volume changes
- int16_t activeSpeech; // Milliseconds of active speech
- int16_t muteGuardMs; // Counter to prevent mute action
- int16_t inQueue; // 10 ms batch indicator
-
- // Microphone level variables
- int32_t micRef; // Remember ref. mic level for virtual mic
- uint16_t gainTableIdx; // Current position in virtual gain table
- int32_t micGainIdx; // Gain index of mic level to increase slowly
- int32_t micVol; // Remember volume between frames
- int32_t maxLevel; // Max possible vol level, incl dig gain
- int32_t maxAnalog; // Maximum possible analog volume level
- int32_t maxInit; // Initial value of "max"
- int32_t minLevel; // Minimum possible volume level
- int32_t minOutput; // Minimum output volume level
- int32_t zeroCtrlMax; // Remember max gain => don't amp low input
- int32_t lastInMicLevel;
-
- int16_t scale; // Scale factor for internal volume levels
-#ifdef MIC_LEVEL_FEEDBACK
- int16_t numBlocksMicLvlSat;
- uint8_t micLvlSat;
-#endif
- // Structs for VAD and digital_agc
- AgcVad vadMic;
- DigitalAgc digitalAgc;
-
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- FILE* fpt;
- FILE* agcLog;
- int32_t fcount;
-#endif
-
- int16_t lowLevelSignal;
+static const int16_t kAlphaShortTerm = 6; // 1 >> 6 = 0.0156
+static const int16_t kAlphaLongTerm = 10; // 1 >> 10 = 0.000977
+
+typedef struct {
+ // Configurable parameters/variables
+ uint32_t fs; // Sampling frequency
+ int16_t compressionGaindB; // Fixed gain level in dB
+ int16_t targetLevelDbfs; // Target level in -dBfs of envelope (default -3)
+ int16_t agcMode; // Hard coded mode (adaptAna/adaptDig/fixedDig)
+ uint8_t limiterEnable; // Enabling limiter (on/off (default off))
+ WebRtcAgcConfig defaultConfig;
+ WebRtcAgcConfig usedConfig;
+
+ // General variables
+ int16_t initFlag;
+ int16_t lastError;
+
+ // Target level parameters
+ // Based on the above: analogTargetLevel = round((32767*10^(-22/20))^2*16/2^7)
+ int32_t analogTargetLevel; // = kRxxBufferLen * 846805; -22 dBfs
+ int32_t startUpperLimit; // = kRxxBufferLen * 1066064; -21 dBfs
+ int32_t startLowerLimit; // = kRxxBufferLen * 672641; -23 dBfs
+ int32_t upperPrimaryLimit; // = kRxxBufferLen * 1342095; -20 dBfs
+ int32_t lowerPrimaryLimit; // = kRxxBufferLen * 534298; -24 dBfs
+ int32_t upperSecondaryLimit; // = kRxxBufferLen * 2677832; -17 dBfs
+ int32_t lowerSecondaryLimit; // = kRxxBufferLen * 267783; -27 dBfs
+ uint16_t targetIdx; // Table index for corresponding target level
+ int16_t analogTarget; // Digital reference level in ENV scale
+
+ // Analog AGC specific variables
+ int32_t filterState[8]; // For downsampling wb to nb
+ int32_t upperLimit; // Upper limit for mic energy
+ int32_t lowerLimit; // Lower limit for mic energy
+ int32_t Rxx160w32; // Average energy for one frame
+ int32_t Rxx16_LPw32; // Low pass filtered subframe energies
+ int32_t Rxx160_LPw32; // Low pass filtered frame energies
+ int32_t Rxx16_LPw32Max; // Keeps track of largest energy subframe
+ int32_t Rxx16_vectorw32[kRxxBufferLen]; // Array with subframe energies
+ int32_t Rxx16w32_array[2][5]; // Energy values of microphone signal
+ int32_t env[2][10]; // Envelope values of subframes
+
+ int16_t Rxx16pos; // Current position in the Rxx16_vectorw32
+ int16_t envSum; // Filtered scaled envelope in subframes
+ int16_t vadThreshold; // Threshold for VAD decision
+ int16_t inActive; // Inactive time in milliseconds
+ int16_t msTooLow; // Milliseconds of speech at a too low level
+ int16_t msTooHigh; // Milliseconds of speech at a too high level
+ int16_t changeToSlowMode; // Change to slow mode after some time at target
+ int16_t firstCall; // First call to the process-function
+ int16_t msZero; // Milliseconds of zero input
+ int16_t msecSpeechOuterChange; // Min ms of speech between volume changes
+ int16_t msecSpeechInnerChange; // Min ms of speech between volume changes
+ int16_t activeSpeech; // Milliseconds of active speech
+ int16_t muteGuardMs; // Counter to prevent mute action
+ int16_t inQueue; // 10 ms batch indicator
+
+ // Microphone level variables
+ int32_t micRef; // Remember ref. mic level for virtual mic
+ uint16_t gainTableIdx; // Current position in virtual gain table
+ int32_t micGainIdx; // Gain index of mic level to increase slowly
+ int32_t micVol; // Remember volume between frames
+ int32_t maxLevel; // Max possible vol level, incl dig gain
+ int32_t maxAnalog; // Maximum possible analog volume level
+ int32_t maxInit; // Initial value of "max"
+ int32_t minLevel; // Minimum possible volume level
+ int32_t minOutput; // Minimum output volume level
+ int32_t zeroCtrlMax; // Remember max gain => don't amp low input
+ int32_t lastInMicLevel;
+
+ int16_t scale; // Scale factor for internal volume levels
+ // Structs for VAD and digital_agc
+ AgcVad vadMic;
+ DigitalAgc digitalAgc;
+
+ int16_t lowLevelSignal;
} LegacyAgc;
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
diff --git a/webrtc/modules/audio_processing/agc/legacy/digital_agc.c b/webrtc/modules/audio_processing/agc/legacy/digital_agc.c
deleted file mode 100644
index aeafb65..0000000
--- a/webrtc/modules/audio_processing/agc/legacy/digital_agc.c
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * 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.
- */
-
-/* digital_agc.c
- *
- */
-
-#include "webrtc/modules/audio_processing/agc/legacy/digital_agc.h"
-
-#include <assert.h>
-#include <string.h>
-#ifdef WEBRTC_AGC_DEBUG_DUMP
-#include <stdio.h>
-#endif
-
-#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
-
-// To generate the gaintable, copy&paste the following lines to a Matlab window:
-// MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1;
-// zeros = 0:31; lvl = 2.^(1-zeros);
-// A = -10*log10(lvl) * (CompRatio - 1) / CompRatio;
-// B = MaxGain - MinGain;
-// gains = round(2^16*10.^(0.05 * (MinGain + B * ( log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) / log(1/(1+exp(Knee*B))))));
-// fprintf(1, '\t%i, %i, %i, %i,\n', gains);
-// % Matlab code for plotting the gain and input/output level characteristic (copy/paste the following 3 lines):
-// in = 10*log10(lvl); out = 20*log10(gains/65536);
-// subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input (dB)'); ylabel('Gain (dB)');
-// subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on; xlabel('Input (dB)'); ylabel('Output (dB)');
-// zoom on;
-
-// Generator table for y=log2(1+e^x) in Q8.
-enum { kGenFuncTableSize = 128 };
-static const uint16_t kGenFuncTable[kGenFuncTableSize] = {
- 256, 485, 786, 1126, 1484, 1849, 2217, 2586,
- 2955, 3324, 3693, 4063, 4432, 4801, 5171, 5540,
- 5909, 6279, 6648, 7017, 7387, 7756, 8125, 8495,
- 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449,
- 11819, 12188, 12557, 12927, 13296, 13665, 14035, 14404,
- 14773, 15143, 15512, 15881, 16251, 16620, 16989, 17359,
- 17728, 18097, 18466, 18836, 19205, 19574, 19944, 20313,
- 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268,
- 23637, 24006, 24376, 24745, 25114, 25484, 25853, 26222,
- 26592, 26961, 27330, 27700, 28069, 28438, 28808, 29177,
- 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132,
- 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086,
- 35456, 35825, 36194, 36564, 36933, 37302, 37672, 38041,
- 38410, 38780, 39149, 39518, 39888, 40257, 40626, 40996,
- 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950,
- 44320, 44689, 45058, 45428, 45797, 46166, 46536, 46905
-};
-
-static const int16_t kAvgDecayTime = 250; // frames; < 3000
-
-int32_t WebRtcAgc_CalculateGainTable(int32_t *gainTable, // Q16
- int16_t digCompGaindB, // Q0
- int16_t targetLevelDbfs,// Q0
- uint8_t limiterEnable,
- int16_t analogTarget) // Q0
-{
- // This function generates the compressor gain table used in the fixed digital part.
- uint32_t tmpU32no1, tmpU32no2, absInLevel, logApprox;
- int32_t inLevel, limiterLvl;
- int32_t tmp32, tmp32no1, tmp32no2, numFIX, den, y32;
- const uint16_t kLog10 = 54426; // log2(10) in Q14
- const uint16_t kLog10_2 = 49321; // 10*log10(2) in Q14
- const uint16_t kLogE_1 = 23637; // log2(e) in Q14
- uint16_t constMaxGain;
- uint16_t tmpU16, intPart, fracPart;
- const int16_t kCompRatio = 3;
- const int16_t kSoftLimiterLeft = 1;
- int16_t limiterOffset = 0; // Limiter offset
- int16_t limiterIdx, limiterLvlX;
- int16_t constLinApprox, zeroGainLvl, maxGain, diffGain;
- int16_t i, tmp16, tmp16no1;
- int zeros, zerosScale;
-
- // Constants
-// kLogE_1 = 23637; // log2(e) in Q14
-// kLog10 = 54426; // log2(10) in Q14
-// kLog10_2 = 49321; // 10*log10(2) in Q14
-
- // Calculate maximum digital gain and zero gain level
- tmp32no1 = (digCompGaindB - analogTarget) * (kCompRatio - 1);
- tmp16no1 = analogTarget - targetLevelDbfs;
- tmp16no1 += WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
- maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs));
- tmp32no1 = maxGain * kCompRatio;
- zeroGainLvl = digCompGaindB;
- zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1),
- kCompRatio - 1);
- if ((digCompGaindB <= analogTarget) && (limiterEnable))
- {
- zeroGainLvl += (analogTarget - digCompGaindB + kSoftLimiterLeft);
- limiterOffset = 0;
- }
-
- // Calculate the difference between maximum gain and gain at 0dB0v:
- // diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio
- // = (compRatio-1)*digCompGaindB/compRatio
- tmp32no1 = digCompGaindB * (kCompRatio - 1);
- diffGain = WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
- if (diffGain < 0 || diffGain >= kGenFuncTableSize)
- {
- assert(0);
- return -1;
- }
-
- // Calculate the limiter level and index:
- // limiterLvlX = analogTarget - limiterOffset
- // limiterLvl = targetLevelDbfs + limiterOffset/compRatio
- limiterLvlX = analogTarget - limiterOffset;
- limiterIdx =
- 2 + WebRtcSpl_DivW32W16ResW16((int32_t)limiterLvlX << 13, kLog10_2 / 2);
- tmp16no1 = WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio);
- limiterLvl = targetLevelDbfs + tmp16no1;
-
- // Calculate (through table lookup):
- // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8)
- constMaxGain = kGenFuncTable[diffGain]; // in Q8
-
- // Calculate a parameter used to approximate the fractional part of 2^x with a
- // piecewise linear function in Q14:
- // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14);
- constLinApprox = 22817; // in Q14
-
- // Calculate a denominator used in the exponential part to convert from dB to linear scale:
- // den = 20*constMaxGain (in Q8)
- den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8
-
- for (i = 0; i < 32; i++)
- {
- // Calculate scaled input level (compressor):
- // inLevel = fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio)
- tmp16 = (int16_t)((kCompRatio - 1) * (i - 1)); // Q0
- tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14
- inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14
-
- // Calculate diffGain-inLevel, to map using the genFuncTable
- inLevel = ((int32_t)diffGain << 14) - inLevel; // Q14
-
- // Make calculations on abs(inLevel) and compensate for the sign afterwards.
- absInLevel = (uint32_t)WEBRTC_SPL_ABS_W32(inLevel); // Q14
-
- // LUT with interpolation
- intPart = (uint16_t)(absInLevel >> 14);
- fracPart = (uint16_t)(absInLevel & 0x00003FFF); // extract the fractional part
- tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8
- tmpU32no1 = tmpU16 * fracPart; // Q22
- tmpU32no1 += (uint32_t)kGenFuncTable[intPart] << 14; // Q22
- logApprox = tmpU32no1 >> 8; // Q14
- // Compensate for negative exponent using the relation:
- // log2(1 + 2^-x) = log2(1 + 2^x) - x
- if (inLevel < 0)
- {
- zeros = WebRtcSpl_NormU32(absInLevel);
- zerosScale = 0;
- if (zeros < 15)
- {
- // Not enough space for multiplication
- tmpU32no2 = absInLevel >> (15 - zeros); // Q(zeros-1)
- tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13)
- if (zeros < 9)
- {
- zerosScale = 9 - zeros;
- tmpU32no1 >>= zerosScale; // Q(zeros+13)
- } else
- {
- tmpU32no2 >>= zeros - 9; // Q22
- }
- } else
- {
- tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28
- tmpU32no2 >>= 6; // Q22
- }
- logApprox = 0;
- if (tmpU32no2 < tmpU32no1)
- {
- logApprox = (tmpU32no1 - tmpU32no2) >> (8 - zerosScale); //Q14
- }
- }
- numFIX = (maxGain * constMaxGain) << 6; // Q14
- numFIX -= (int32_t)logApprox * diffGain; // Q14
-
- // Calculate ratio
- // Shift |numFIX| as much as possible.
- // Ensure we avoid wrap-around in |den| as well.
- if (numFIX > (den >> 8)) // |den| is Q8.
- {
- zeros = WebRtcSpl_NormW32(numFIX);
- } else
- {
- zeros = WebRtcSpl_NormW32(den) + 8;
- }
- numFIX <<= zeros; // Q(14+zeros)
-
- // Shift den so we end up in Qy1
- tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 8); // Q(zeros)
- if (numFIX < 0)
- {
- numFIX -= tmp32no1 / 2;
- } else
- {
- numFIX += tmp32no1 / 2;
- }
- y32 = numFIX / tmp32no1; // in Q14
- if (limiterEnable && (i < limiterIdx))
- {
- tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14
- tmp32 -= limiterLvl << 14; // Q14
- y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20);
- }
- if (y32 > 39000)
- {
- tmp32 = (y32 >> 1) * kLog10 + 4096; // in Q27
- tmp32 >>= 13; // In Q14.
- } else
- {
- tmp32 = y32 * kLog10 + 8192; // in Q28
- tmp32 >>= 14; // In Q14.
- }
- tmp32 += 16 << 14; // in Q14 (Make sure final output is in Q16)
-
- // Calculate power
- if (tmp32 > 0)
- {
- intPart = (int16_t)(tmp32 >> 14);
- fracPart = (uint16_t)(tmp32 & 0x00003FFF); // in Q14
- if ((fracPart >> 13) != 0)
- {
- tmp16 = (2 << 14) - constLinApprox;
- tmp32no2 = (1 << 14) - fracPart;
- tmp32no2 *= tmp16;
- tmp32no2 >>= 13;
- tmp32no2 = (1 << 14) - tmp32no2;
- } else
- {
- tmp16 = constLinApprox - (1 << 14);
- tmp32no2 = (fracPart * tmp16) >> 13;
- }
- fracPart = (uint16_t)tmp32no2;
- gainTable[i] =
- (1 << intPart) + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14);
- } else
- {
- gainTable[i] = 0;
- }
- }
-
- return 0;
-}
-
-int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) {
- if (agcMode == kAgcModeFixedDigital)
- {
- // start at minimum to find correct gain faster
- stt->capacitorSlow = 0;
- } else
- {
- // start out with 0 dB gain
- stt->capacitorSlow = 134217728; // (int32_t)(0.125f * 32768.0f * 32768.0f);
- }
- stt->capacitorFast = 0;
- stt->gain = 65536;
- stt->gatePrevious = 0;
- stt->agcMode = agcMode;
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- stt->frameCounter = 0;
-#endif
-
- // initialize VADs
- WebRtcAgc_InitVad(&stt->vadNearend);
- WebRtcAgc_InitVad(&stt->vadFarend);
-
- return 0;
-}
-
-int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt,
- const int16_t* in_far,
- size_t nrSamples) {
- assert(stt != NULL);
- // VAD for far end
- WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples);
-
- return 0;
-}
-
-int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
- const int16_t* const* in_near,
- size_t num_bands,
- int16_t* const* out,
- uint32_t FS,
- int16_t lowlevelSignal) {
- // array for gains (one value per ms, incl start & end)
- int32_t gains[11];
-
- int32_t out_tmp, tmp32;
- int32_t env[10];
- int32_t max_nrg;
- int32_t cur_level;
- int32_t gain32, delta;
- int16_t logratio;
- int16_t lower_thr, upper_thr;
- int16_t zeros = 0, zeros_fast, frac = 0;
- int16_t decay;
- int16_t gate, gain_adj;
- int16_t k;
- size_t n, i, L;
- int16_t L2; // samples/subframe
-
- // determine number of samples per ms
- if (FS == 8000)
- {
- L = 8;
- L2 = 3;
- } else if (FS == 16000 || FS == 32000 || FS == 48000)
- {
- L = 16;
- L2 = 4;
- } else
- {
- return -1;
- }
-
- for (i = 0; i < num_bands; ++i)
- {
- if (in_near[i] != out[i])
- {
- // Only needed if they don't already point to the same place.
- memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0]));
- }
- }
- // VAD for near end
- logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out[0], L * 10);
-
- // Account for far end VAD
- if (stt->vadFarend.counter > 10)
- {
- tmp32 = 3 * logratio;
- logratio = (int16_t)((tmp32 - stt->vadFarend.logRatio) >> 2);
- }
-
- // Determine decay factor depending on VAD
- // upper_thr = 1.0f;
- // lower_thr = 0.25f;
- upper_thr = 1024; // Q10
- lower_thr = 0; // Q10
- if (logratio > upper_thr)
- {
- // decay = -2^17 / DecayTime; -> -65
- decay = -65;
- } else if (logratio < lower_thr)
- {
- decay = 0;
- } else
- {
- // decay = (int16_t)(((lower_thr - logratio)
- // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10);
- // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65
- tmp32 = (lower_thr - logratio) * 65;
- decay = (int16_t)(tmp32 >> 10);
- }
-
- // adjust decay factor for long silence (detected as low standard deviation)
- // This is only done in the adaptive modes
- if (stt->agcMode != kAgcModeFixedDigital)
- {
- if (stt->vadNearend.stdLongTerm < 4000)
- {
- decay = 0;
- } else if (stt->vadNearend.stdLongTerm < 8096)
- {
- // decay = (int16_t)(((stt->vadNearend.stdLongTerm - 4000) * decay) >> 12);
- tmp32 = (stt->vadNearend.stdLongTerm - 4000) * decay;
- decay = (int16_t)(tmp32 >> 12);
- }
-
- if (lowlevelSignal != 0)
- {
- decay = 0;
- }
- }
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- stt->frameCounter++;
- fprintf(stt->logFile,
- "%5.2f\t%d\t%d\t%d\t",
- (float)(stt->frameCounter) / 100,
- logratio,
- decay,
- stt->vadNearend.stdLongTerm);
-#endif
- // Find max amplitude per sub frame
- // iterate over sub frames
- for (k = 0; k < 10; k++)
- {
- // iterate over samples
- max_nrg = 0;
- for (n = 0; n < L; n++)
- {
- int32_t nrg = out[0][k * L + n] * out[0][k * L + n];
- if (nrg > max_nrg)
- {
- max_nrg = nrg;
- }
- }
- env[k] = max_nrg;
- }
-
- // Calculate gain per sub frame
- gains[0] = stt->gain;
- for (k = 0; k < 10; k++)
- {
- // Fast envelope follower
- // decay time = -131000 / -1000 = 131 (ms)
- stt->capacitorFast = AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->capacitorFast);
- if (env[k] > stt->capacitorFast)
- {
- stt->capacitorFast = env[k];
- }
- // Slow envelope follower
- if (env[k] > stt->capacitorSlow)
- {
- // increase capacitorSlow
- stt->capacitorSlow
- = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow), stt->capacitorSlow);
- } else
- {
- // decrease capacitorSlow
- stt->capacitorSlow
- = AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorSlow);
- }
-
- // use maximum of both capacitors as current level
- if (stt->capacitorFast > stt->capacitorSlow)
- {
- cur_level = stt->capacitorFast;
- } else
- {
- cur_level = stt->capacitorSlow;
- }
- // Translate signal level into gain, using a piecewise linear approximation
- // find number of leading zeros
- zeros = WebRtcSpl_NormU32((uint32_t)cur_level);
- if (cur_level == 0)
- {
- zeros = 31;
- }
- tmp32 = (cur_level << zeros) & 0x7FFFFFFF;
- frac = (int16_t)(tmp32 >> 19); // Q12.
- tmp32 = (stt->gainTable[zeros-1] - stt->gainTable[zeros]) * frac;
- gains[k + 1] = stt->gainTable[zeros] + (tmp32 >> 12);
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- if (k == 0) {
- fprintf(stt->logFile,
- "%d\t%d\t%d\t%d\t%d\n",
- env[0],
- cur_level,
- stt->capacitorFast,
- stt->capacitorSlow,
- zeros);
- }
-#endif
- }
-
- // Gate processing (lower gain during absence of speech)
- zeros = (zeros << 9) - (frac >> 3);
- // find number of leading zeros
- zeros_fast = WebRtcSpl_NormU32((uint32_t)stt->capacitorFast);
- if (stt->capacitorFast == 0)
- {
- zeros_fast = 31;
- }
- tmp32 = (stt->capacitorFast << zeros_fast) & 0x7FFFFFFF;
- zeros_fast <<= 9;
- zeros_fast -= (int16_t)(tmp32 >> 22);
-
- gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm;
-
- if (gate < 0)
- {
- stt->gatePrevious = 0;
- } else
- {
- tmp32 = stt->gatePrevious * 7;
- gate = (int16_t)((gate + tmp32) >> 3);
- stt->gatePrevious = gate;
- }
- // gate < 0 -> no gate
- // gate > 2500 -> max gate
- if (gate > 0)
- {
- if (gate < 2500)
- {
- gain_adj = (2500 - gate) >> 5;
- } else
- {
- gain_adj = 0;
- }
- for (k = 0; k < 10; k++)
- {
- if ((gains[k + 1] - stt->gainTable[0]) > 8388608)
- {
- // To prevent wraparound
- tmp32 = (gains[k + 1] - stt->gainTable[0]) >> 8;
- tmp32 *= 178 + gain_adj;
- } else
- {
- tmp32 = (gains[k+1] - stt->gainTable[0]) * (178 + gain_adj);
- tmp32 >>= 8;
- }
- gains[k + 1] = stt->gainTable[0] + tmp32;
- }
- }
-
- // Limit gain to avoid overload distortion
- for (k = 0; k < 10; k++)
- {
- // To prevent wrap around
- zeros = 10;
- if (gains[k + 1] > 47453132)
- {
- zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]);
- }
- gain32 = (gains[k + 1] >> zeros) + 1;
- gain32 *= gain32;
- // check for overflow
- while (AGC_MUL32((env[k] >> 12) + 1, gain32)
- > WEBRTC_SPL_SHIFT_W32((int32_t)32767, 2 * (1 - zeros + 10)))
- {
- // multiply by 253/256 ==> -0.1 dB
- if (gains[k + 1] > 8388607)
- {
- // Prevent wrap around
- gains[k + 1] = (gains[k+1] / 256) * 253;
- } else
- {
- gains[k + 1] = (gains[k+1] * 253) / 256;
- }
- gain32 = (gains[k + 1] >> zeros) + 1;
- gain32 *= gain32;
- }
- }
- // gain reductions should be done 1 ms earlier than gain increases
- for (k = 1; k < 10; k++)
- {
- if (gains[k] > gains[k + 1])
- {
- gains[k] = gains[k + 1];
- }
- }
- // save start gain for next frame
- stt->gain = gains[10];
-
- // Apply gain
- // handle first sub frame separately
- delta = (gains[1] - gains[0]) << (4 - L2);
- gain32 = gains[0] << 4;
- // iterate over samples
- for (n = 0; n < L; n++)
- {
- for (i = 0; i < num_bands; ++i)
- {
- tmp32 = out[i][n] * ((gain32 + 127) >> 7);
- out_tmp = tmp32 >> 16;
- if (out_tmp > 4095)
- {
- out[i][n] = (int16_t)32767;
- } else if (out_tmp < -4096)
- {
- out[i][n] = (int16_t)-32768;
- } else
- {
- tmp32 = out[i][n] * (gain32 >> 4);
- out[i][n] = (int16_t)(tmp32 >> 16);
- }
- }
- //
-
- gain32 += delta;
- }
- // iterate over subframes
- for (k = 1; k < 10; k++)
- {
- delta = (gains[k+1] - gains[k]) << (4 - L2);
- gain32 = gains[k] << 4;
- // iterate over samples
- for (n = 0; n < L; n++)
- {
- for (i = 0; i < num_bands; ++i)
- {
- tmp32 = out[i][k * L + n] * (gain32 >> 4);
- out[i][k * L + n] = (int16_t)(tmp32 >> 16);
- }
- gain32 += delta;
- }
- }
-
- return 0;
-}
-
-void WebRtcAgc_InitVad(AgcVad* state) {
- int16_t k;
-
- state->HPstate = 0; // state of high pass filter
- state->logRatio = 0; // log( P(active) / P(inactive) )
- // average input level (Q10)
- state->meanLongTerm = 15 << 10;
-
- // variance of input level (Q8)
- state->varianceLongTerm = 500 << 8;
-
- state->stdLongTerm = 0; // standard deviation of input level in dB
- // short-term average input level (Q10)
- state->meanShortTerm = 15 << 10;
-
- // short-term variance of input level (Q8)
- state->varianceShortTerm = 500 << 8;
-
- state->stdShortTerm = 0; // short-term standard deviation of input level in dB
- state->counter = 3; // counts updates
- for (k = 0; k < 8; k++)
- {
- // downsampling filter
- state->downState[k] = 0;
- }
-}
-
-int16_t WebRtcAgc_ProcessVad(AgcVad* state, // (i) VAD state
- const int16_t* in, // (i) Speech signal
- size_t nrSamples) // (i) number of samples
-{
- int32_t out, nrg, tmp32, tmp32b;
- uint16_t tmpU16;
- int16_t k, subfr, tmp16;
- int16_t buf1[8];
- int16_t buf2[4];
- int16_t HPstate;
- int16_t zeros, dB;
-
- // process in 10 sub frames of 1 ms (to save on memory)
- nrg = 0;
- HPstate = state->HPstate;
- for (subfr = 0; subfr < 10; subfr++)
- {
- // downsample to 4 kHz
- if (nrSamples == 160)
- {
- for (k = 0; k < 8; k++)
- {
- tmp32 = (int32_t)in[2 * k] + (int32_t)in[2 * k + 1];
- tmp32 >>= 1;
- buf1[k] = (int16_t)tmp32;
- }
- in += 16;
-
- WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState);
- } else
- {
- WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState);
- in += 8;
- }
-
- // high pass filter and compute energy
- for (k = 0; k < 4; k++)
- {
- out = buf2[k] + HPstate;
- tmp32 = 600 * out;
- HPstate = (int16_t)((tmp32 >> 10) - buf2[k]);
- nrg += (out * out) >> 6;
- }
- }
- state->HPstate = HPstate;
-
- // find number of leading zeros
- if (!(0xFFFF0000 & nrg))
- {
- zeros = 16;
- } else
- {
- zeros = 0;
- }
- if (!(0xFF000000 & (nrg << zeros)))
- {
- zeros += 8;
- }
- if (!(0xF0000000 & (nrg << zeros)))
- {
- zeros += 4;
- }
- if (!(0xC0000000 & (nrg << zeros)))
- {
- zeros += 2;
- }
- if (!(0x80000000 & (nrg << zeros)))
- {
- zeros += 1;
- }
-
- // energy level (range {-32..30}) (Q10)
- dB = (15 - zeros) << 11;
-
- // Update statistics
-
- if (state->counter < kAvgDecayTime)
- {
- // decay time = AvgDecTime * 10 ms
- state->counter++;
- }
-
- // update short-term estimate of mean energy level (Q10)
- tmp32 = state->meanShortTerm * 15 + dB;
- state->meanShortTerm = (int16_t)(tmp32 >> 4);
-
- // update short-term estimate of variance in energy level (Q8)
- tmp32 = (dB * dB) >> 12;
- tmp32 += state->varianceShortTerm * 15;
- state->varianceShortTerm = tmp32 / 16;
-
- // update short-term estimate of standard deviation in energy level (Q10)
- tmp32 = state->meanShortTerm * state->meanShortTerm;
- tmp32 = (state->varianceShortTerm << 12) - tmp32;
- state->stdShortTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
-
- // update long-term estimate of mean energy level (Q10)
- tmp32 = state->meanLongTerm * state->counter + dB;
- state->meanLongTerm = WebRtcSpl_DivW32W16ResW16(
- tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
-
- // update long-term estimate of variance in energy level (Q8)
- tmp32 = (dB * dB) >> 12;
- tmp32 += state->varianceLongTerm * state->counter;
- state->varianceLongTerm = WebRtcSpl_DivW32W16(
- tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
-
- // update long-term estimate of standard deviation in energy level (Q10)
- tmp32 = state->meanLongTerm * state->meanLongTerm;
- tmp32 = (state->varianceLongTerm << 12) - tmp32;
- state->stdLongTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
-
- // update voice activity measure (Q10)
- tmp16 = 3 << 12;
- // TODO(bjornv): (dB - state->meanLongTerm) can overflow, e.g., in
- // ApmTest.Process unit test. Previously the macro WEBRTC_SPL_MUL_16_16()
- // was used, which did an intermediate cast to (int16_t), hence losing
- // significant bits. This cause logRatio to max out positive, rather than
- // negative. This is a bug, but has very little significance.
- tmp32 = tmp16 * (int16_t)(dB - state->meanLongTerm);
- tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm);
- tmpU16 = (13 << 12);
- tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16);
- tmp32 += tmp32b >> 10;
-
- state->logRatio = (int16_t)(tmp32 >> 6);
-
- // limit
- if (state->logRatio > 2048)
- {
- state->logRatio = 2048;
- }
- if (state->logRatio < -2048)
- {
- state->logRatio = -2048;
- }
-
- return state->logRatio; // Q10
-}
diff --git a/webrtc/modules/audio_processing/agc/legacy/digital_agc.cc b/webrtc/modules/audio_processing/agc/legacy/digital_agc.cc
new file mode 100644
index 0000000..185e849
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc/legacy/digital_agc.cc
@@ -0,0 +1,714 @@
+/*
+ * 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/audio_processing/agc/legacy/digital_agc.h"
+
+#include <string.h>
+
+#include "modules/audio_processing/agc/legacy/gain_control.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// To generate the gaintable, copy&paste the following lines to a Matlab window:
+// MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1;
+// zeros = 0:31; lvl = 2.^(1-zeros);
+// A = -10*log10(lvl) * (CompRatio - 1) / CompRatio;
+// B = MaxGain - MinGain;
+// gains = round(2^16*10.^(0.05 * (MinGain + B * (
+// log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) /
+// log(1/(1+exp(Knee*B))))));
+// fprintf(1, '\t%i, %i, %i, %i,\n', gains);
+// % Matlab code for plotting the gain and input/output level characteristic
+// (copy/paste the following 3 lines):
+// in = 10*log10(lvl); out = 20*log10(gains/65536);
+// subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input
+// (dB)'); ylabel('Gain (dB)');
+// subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on;
+// xlabel('Input (dB)'); ylabel('Output (dB)');
+// zoom on;
+
+// Generator table for y=log2(1+e^x) in Q8.
+enum { kGenFuncTableSize = 128 };
+static const uint16_t kGenFuncTable[kGenFuncTableSize] = {
+ 256, 485, 786, 1126, 1484, 1849, 2217, 2586, 2955, 3324, 3693,
+ 4063, 4432, 4801, 5171, 5540, 5909, 6279, 6648, 7017, 7387, 7756,
+ 8125, 8495, 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449, 11819,
+ 12188, 12557, 12927, 13296, 13665, 14035, 14404, 14773, 15143, 15512, 15881,
+ 16251, 16620, 16989, 17359, 17728, 18097, 18466, 18836, 19205, 19574, 19944,
+ 20313, 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268, 23637, 24006,
+ 24376, 24745, 25114, 25484, 25853, 26222, 26592, 26961, 27330, 27700, 28069,
+ 28438, 28808, 29177, 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132,
+ 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086, 35456, 35825, 36194,
+ 36564, 36933, 37302, 37672, 38041, 38410, 38780, 39149, 39518, 39888, 40257,
+ 40626, 40996, 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950, 44320,
+ 44689, 45058, 45428, 45797, 46166, 46536, 46905};
+
+static const int16_t kAvgDecayTime = 250; // frames; < 3000
+
+// the 32 most significant bits of A(19) * B(26) >> 13
+#define AGC_MUL32(A, B) (((B) >> 13) * (A) + (((0x00001FFF & (B)) * (A)) >> 13))
+// C + the 32 most significant bits of A * B
+#define AGC_SCALEDIFF32(A, B, C) \
+ ((C) + ((B) >> 16) * (A) + (((0x0000FFFF & (B)) * (A)) >> 16))
+
+} // namespace
+
+int32_t WebRtcAgc_CalculateGainTable(int32_t* gainTable, // Q16
+ int16_t digCompGaindB, // Q0
+ int16_t targetLevelDbfs, // Q0
+ uint8_t limiterEnable,
+ int16_t analogTarget) { // Q0
+ // This function generates the compressor gain table used in the fixed digital
+ // part.
+ uint32_t tmpU32no1, tmpU32no2, absInLevel, logApprox;
+ int32_t inLevel, limiterLvl;
+ int32_t tmp32, tmp32no1, tmp32no2, numFIX, den, y32;
+ const uint16_t kLog10 = 54426; // log2(10) in Q14
+ const uint16_t kLog10_2 = 49321; // 10*log10(2) in Q14
+ const uint16_t kLogE_1 = 23637; // log2(e) in Q14
+ uint16_t constMaxGain;
+ uint16_t tmpU16, intPart, fracPart;
+ const int16_t kCompRatio = 3;
+ const int16_t kSoftLimiterLeft = 1;
+ int16_t limiterOffset = 0; // Limiter offset
+ int16_t limiterIdx, limiterLvlX;
+ int16_t constLinApprox, zeroGainLvl, maxGain, diffGain;
+ int16_t i, tmp16, tmp16no1;
+ int zeros, zerosScale;
+
+ // Constants
+ // kLogE_1 = 23637; // log2(e) in Q14
+ // kLog10 = 54426; // log2(10) in Q14
+ // kLog10_2 = 49321; // 10*log10(2) in Q14
+
+ // Calculate maximum digital gain and zero gain level
+ tmp32no1 = (digCompGaindB - analogTarget) * (kCompRatio - 1);
+ tmp16no1 = analogTarget - targetLevelDbfs;
+ tmp16no1 +=
+ WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
+ maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs));
+ tmp32no1 = maxGain * kCompRatio;
+ zeroGainLvl = digCompGaindB;
+ zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1),
+ kCompRatio - 1);
+ if ((digCompGaindB <= analogTarget) && (limiterEnable)) {
+ zeroGainLvl += (analogTarget - digCompGaindB + kSoftLimiterLeft);
+ limiterOffset = 0;
+ }
+
+ // Calculate the difference between maximum gain and gain at 0dB0v:
+ // diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio
+ // = (compRatio-1)*digCompGaindB/compRatio
+ tmp32no1 = digCompGaindB * (kCompRatio - 1);
+ diffGain =
+ WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
+ if (diffGain < 0 || diffGain >= kGenFuncTableSize) {
+ RTC_DCHECK(0);
+ return -1;
+ }
+
+ // Calculate the limiter level and index:
+ // limiterLvlX = analogTarget - limiterOffset
+ // limiterLvl = targetLevelDbfs + limiterOffset/compRatio
+ limiterLvlX = analogTarget - limiterOffset;
+ limiterIdx = 2 + WebRtcSpl_DivW32W16ResW16((int32_t)limiterLvlX * (1 << 13),
+ kLog10_2 / 2);
+ tmp16no1 =
+ WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio);
+ limiterLvl = targetLevelDbfs + tmp16no1;
+
+ // Calculate (through table lookup):
+ // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8)
+ constMaxGain = kGenFuncTable[diffGain]; // in Q8
+
+ // Calculate a parameter used to approximate the fractional part of 2^x with a
+ // piecewise linear function in Q14:
+ // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14);
+ constLinApprox = 22817; // in Q14
+
+ // Calculate a denominator used in the exponential part to convert from dB to
+ // linear scale:
+ // den = 20*constMaxGain (in Q8)
+ den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8
+
+ for (i = 0; i < 32; i++) {
+ // Calculate scaled input level (compressor):
+ // inLevel =
+ // fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio)
+ tmp16 = (int16_t)((kCompRatio - 1) * (i - 1)); // Q0
+ tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14
+ inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14
+
+ // Calculate diffGain-inLevel, to map using the genFuncTable
+ inLevel = (int32_t)diffGain * (1 << 14) - inLevel; // Q14
+
+ // Make calculations on abs(inLevel) and compensate for the sign afterwards.
+ absInLevel = (uint32_t)WEBRTC_SPL_ABS_W32(inLevel); // Q14
+
+ // LUT with interpolation
+ intPart = (uint16_t)(absInLevel >> 14);
+ fracPart =
+ (uint16_t)(absInLevel & 0x00003FFF); // extract the fractional part
+ tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8
+ tmpU32no1 = tmpU16 * fracPart; // Q22
+ tmpU32no1 += (uint32_t)kGenFuncTable[intPart] << 14; // Q22
+ logApprox = tmpU32no1 >> 8; // Q14
+ // Compensate for negative exponent using the relation:
+ // log2(1 + 2^-x) = log2(1 + 2^x) - x
+ if (inLevel < 0) {
+ zeros = WebRtcSpl_NormU32(absInLevel);
+ zerosScale = 0;
+ if (zeros < 15) {
+ // Not enough space for multiplication
+ tmpU32no2 = absInLevel >> (15 - zeros); // Q(zeros-1)
+ tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13)
+ if (zeros < 9) {
+ zerosScale = 9 - zeros;
+ tmpU32no1 >>= zerosScale; // Q(zeros+13)
+ } else {
+ tmpU32no2 >>= zeros - 9; // Q22
+ }
+ } else {
+ tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28
+ tmpU32no2 >>= 6; // Q22
+ }
+ logApprox = 0;
+ if (tmpU32no2 < tmpU32no1) {
+ logApprox = (tmpU32no1 - tmpU32no2) >> (8 - zerosScale); // Q14
+ }
+ }
+ numFIX = (maxGain * constMaxGain) * (1 << 6); // Q14
+ numFIX -= (int32_t)logApprox * diffGain; // Q14
+
+ // Calculate ratio
+ // Shift |numFIX| as much as possible.
+ // Ensure we avoid wrap-around in |den| as well.
+ if (numFIX > (den >> 8) || -numFIX > (den >> 8)) { // |den| is Q8.
+ zeros = WebRtcSpl_NormW32(numFIX);
+ } else {
+ zeros = WebRtcSpl_NormW32(den) + 8;
+ }
+ numFIX *= 1 << zeros; // Q(14+zeros)
+
+ // Shift den so we end up in Qy1
+ tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 9); // Q(zeros - 1)
+ y32 = numFIX / tmp32no1; // in Q15
+ // This is to do rounding in Q14.
+ y32 = y32 >= 0 ? (y32 + 1) >> 1 : -((-y32 + 1) >> 1);
+
+ if (limiterEnable && (i < limiterIdx)) {
+ tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14
+ tmp32 -= limiterLvl * (1 << 14); // Q14
+ y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20);
+ }
+ if (y32 > 39000) {
+ tmp32 = (y32 >> 1) * kLog10 + 4096; // in Q27
+ tmp32 >>= 13; // In Q14.
+ } else {
+ tmp32 = y32 * kLog10 + 8192; // in Q28
+ tmp32 >>= 14; // In Q14.
+ }
+ tmp32 += 16 << 14; // in Q14 (Make sure final output is in Q16)
+
+ // Calculate power
+ if (tmp32 > 0) {
+ intPart = (int16_t)(tmp32 >> 14);
+ fracPart = (uint16_t)(tmp32 & 0x00003FFF); // in Q14
+ if ((fracPart >> 13) != 0) {
+ tmp16 = (2 << 14) - constLinApprox;
+ tmp32no2 = (1 << 14) - fracPart;
+ tmp32no2 *= tmp16;
+ tmp32no2 >>= 13;
+ tmp32no2 = (1 << 14) - tmp32no2;
+ } else {
+ tmp16 = constLinApprox - (1 << 14);
+ tmp32no2 = (fracPart * tmp16) >> 13;
+ }
+ fracPart = (uint16_t)tmp32no2;
+ gainTable[i] =
+ (1 << intPart) + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14);
+ } else {
+ gainTable[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) {
+ if (agcMode == kAgcModeFixedDigital) {
+ // start at minimum to find correct gain faster
+ stt->capacitorSlow = 0;
+ } else {
+ // start out with 0 dB gain
+ stt->capacitorSlow = 134217728; // (int32_t)(0.125f * 32768.0f * 32768.0f);
+ }
+ stt->capacitorFast = 0;
+ stt->gain = 65536;
+ stt->gatePrevious = 0;
+ stt->agcMode = agcMode;
+
+ // initialize VADs
+ WebRtcAgc_InitVad(&stt->vadNearend);
+ WebRtcAgc_InitVad(&stt->vadFarend);
+
+ return 0;
+}
+
+int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt,
+ const int16_t* in_far,
+ size_t nrSamples) {
+ RTC_DCHECK(stt);
+ // VAD for far end
+ WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples);
+
+ return 0;
+}
+
+// Gains is an 11 element long array (one value per ms, incl start & end).
+int32_t WebRtcAgc_ComputeDigitalGains(DigitalAgc* stt,
+ const int16_t* const* in_near,
+ size_t num_bands,
+ uint32_t FS,
+ int16_t lowlevelSignal,
+ int32_t gains[11]) {
+ int32_t tmp32;
+ int32_t env[10];
+ int32_t max_nrg;
+ int32_t cur_level;
+ int32_t gain32;
+ int16_t logratio;
+ int16_t lower_thr, upper_thr;
+ int16_t zeros = 0, zeros_fast, frac = 0;
+ int16_t decay;
+ int16_t gate, gain_adj;
+ int16_t k;
+ size_t n, L;
+ int16_t L2; // samples/subframe
+
+ // determine number of samples per ms
+ if (FS == 8000) {
+ L = 8;
+ L2 = 3;
+ } else if (FS == 16000 || FS == 32000 || FS == 48000) {
+ L = 16;
+ L2 = 4;
+ } else {
+ return -1;
+ }
+
+ // VAD for near end
+ logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, in_near[0], L * 10);
+
+ // Account for far end VAD
+ if (stt->vadFarend.counter > 10) {
+ tmp32 = 3 * logratio;
+ logratio = (int16_t)((tmp32 - stt->vadFarend.logRatio) >> 2);
+ }
+
+ // Determine decay factor depending on VAD
+ // upper_thr = 1.0f;
+ // lower_thr = 0.25f;
+ upper_thr = 1024; // Q10
+ lower_thr = 0; // Q10
+ if (logratio > upper_thr) {
+ // decay = -2^17 / DecayTime; -> -65
+ decay = -65;
+ } else if (logratio < lower_thr) {
+ decay = 0;
+ } else {
+ // decay = (int16_t)(((lower_thr - logratio)
+ // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10);
+ // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65
+ tmp32 = (lower_thr - logratio) * 65;
+ decay = (int16_t)(tmp32 >> 10);
+ }
+
+ // adjust decay factor for long silence (detected as low standard deviation)
+ // This is only done in the adaptive modes
+ if (stt->agcMode != kAgcModeFixedDigital) {
+ if (stt->vadNearend.stdLongTerm < 4000) {
+ decay = 0;
+ } else if (stt->vadNearend.stdLongTerm < 8096) {
+ // decay = (int16_t)(((stt->vadNearend.stdLongTerm - 4000) * decay) >>
+ // 12);
+ tmp32 = (stt->vadNearend.stdLongTerm - 4000) * decay;
+ decay = (int16_t)(tmp32 >> 12);
+ }
+
+ if (lowlevelSignal != 0) {
+ decay = 0;
+ }
+ }
+ // Find max amplitude per sub frame
+ // iterate over sub frames
+ for (k = 0; k < 10; k++) {
+ // iterate over samples
+ max_nrg = 0;
+ for (n = 0; n < L; n++) {
+ int32_t nrg = in_near[0][k * L + n] * in_near[0][k * L + n];
+ if (nrg > max_nrg) {
+ max_nrg = nrg;
+ }
+ }
+ env[k] = max_nrg;
+ }
+
+ // Calculate gain per sub frame
+ gains[0] = stt->gain;
+ for (k = 0; k < 10; k++) {
+ // Fast envelope follower
+ // decay time = -131000 / -1000 = 131 (ms)
+ stt->capacitorFast =
+ AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->capacitorFast);
+ if (env[k] > stt->capacitorFast) {
+ stt->capacitorFast = env[k];
+ }
+ // Slow envelope follower
+ if (env[k] > stt->capacitorSlow) {
+ // increase capacitorSlow
+ stt->capacitorSlow = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow),
+ stt->capacitorSlow);
+ } else {
+ // decrease capacitorSlow
+ stt->capacitorSlow =
+ AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorSlow);
+ }
+
+ // use maximum of both capacitors as current level
+ if (stt->capacitorFast > stt->capacitorSlow) {
+ cur_level = stt->capacitorFast;
+ } else {
+ cur_level = stt->capacitorSlow;
+ }
+ // Translate signal level into gain, using a piecewise linear approximation
+ // find number of leading zeros
+ zeros = WebRtcSpl_NormU32((uint32_t)cur_level);
+ if (cur_level == 0) {
+ zeros = 31;
+ }
+ tmp32 = ((uint32_t)cur_level << zeros) & 0x7FFFFFFF;
+ frac = (int16_t)(tmp32 >> 19); // Q12.
+ // Interpolate between gainTable[zeros] and gainTable[zeros-1].
+ tmp32 =
+ ((stt->gainTable[zeros - 1] - stt->gainTable[zeros]) * (int64_t)frac) >>
+ 12;
+ gains[k + 1] = stt->gainTable[zeros] + tmp32;
+ }
+
+ // Gate processing (lower gain during absence of speech)
+ zeros = (zeros << 9) - (frac >> 3);
+ // find number of leading zeros
+ zeros_fast = WebRtcSpl_NormU32((uint32_t)stt->capacitorFast);
+ if (stt->capacitorFast == 0) {
+ zeros_fast = 31;
+ }
+ tmp32 = ((uint32_t)stt->capacitorFast << zeros_fast) & 0x7FFFFFFF;
+ zeros_fast <<= 9;
+ zeros_fast -= (int16_t)(tmp32 >> 22);
+
+ gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm;
+
+ if (gate < 0) {
+ stt->gatePrevious = 0;
+ } else {
+ tmp32 = stt->gatePrevious * 7;
+ gate = (int16_t)((gate + tmp32) >> 3);
+ stt->gatePrevious = gate;
+ }
+ // gate < 0 -> no gate
+ // gate > 2500 -> max gate
+ if (gate > 0) {
+ if (gate < 2500) {
+ gain_adj = (2500 - gate) >> 5;
+ } else {
+ gain_adj = 0;
+ }
+ for (k = 0; k < 10; k++) {
+ if ((gains[k + 1] - stt->gainTable[0]) > 8388608) {
+ // To prevent wraparound
+ tmp32 = (gains[k + 1] - stt->gainTable[0]) >> 8;
+ tmp32 *= 178 + gain_adj;
+ } else {
+ tmp32 = (gains[k + 1] - stt->gainTable[0]) * (178 + gain_adj);
+ tmp32 >>= 8;
+ }
+ gains[k + 1] = stt->gainTable[0] + tmp32;
+ }
+ }
+
+ // Limit gain to avoid overload distortion
+ for (k = 0; k < 10; k++) {
+ // Find a shift of gains[k + 1] such that it can be squared without
+ // overflow, but at least by 10 bits.
+ zeros = 10;
+ if (gains[k + 1] > 47452159) {
+ zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]);
+ }
+ gain32 = (gains[k + 1] >> zeros) + 1;
+ gain32 *= gain32;
+ // check for overflow
+ while (AGC_MUL32((env[k] >> 12) + 1, gain32) >
+ WEBRTC_SPL_SHIFT_W32((int32_t)32767, 2 * (1 - zeros + 10))) {
+ // multiply by 253/256 ==> -0.1 dB
+ if (gains[k + 1] > 8388607) {
+ // Prevent wrap around
+ gains[k + 1] = (gains[k + 1] / 256) * 253;
+ } else {
+ gains[k + 1] = (gains[k + 1] * 253) / 256;
+ }
+ gain32 = (gains[k + 1] >> zeros) + 1;
+ gain32 *= gain32;
+ }
+ }
+ // gain reductions should be done 1 ms earlier than gain increases
+ for (k = 1; k < 10; k++) {
+ if (gains[k] > gains[k + 1]) {
+ gains[k] = gains[k + 1];
+ }
+ }
+ // save start gain for next frame
+ stt->gain = gains[10];
+
+ return 0;
+}
+
+int32_t WebRtcAgc_ApplyDigitalGains(const int32_t gains[11],
+ size_t num_bands,
+ uint32_t FS,
+ const int16_t* const* in_near,
+ int16_t* const* out) {
+ // Apply gain
+ // handle first sub frame separately
+ size_t L;
+ int16_t L2; // samples/subframe
+
+ // determine number of samples per ms
+ if (FS == 8000) {
+ L = 8;
+ L2 = 3;
+ } else if (FS == 16000 || FS == 32000 || FS == 48000) {
+ L = 16;
+ L2 = 4;
+ } else {
+ return -1;
+ }
+
+ for (size_t i = 0; i < num_bands; ++i) {
+ if (in_near[i] != out[i]) {
+ // Only needed if they don't already point to the same place.
+ memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0]));
+ }
+ }
+
+ // iterate over samples
+ int32_t delta = (gains[1] - gains[0]) * (1 << (4 - L2));
+ int32_t gain32 = gains[0] * (1 << 4);
+ for (size_t n = 0; n < L; n++) {
+ for (size_t i = 0; i < num_bands; ++i) {
+ int32_t out_tmp = (int64_t)out[i][n] * ((gain32 + 127) >> 7) >> 16;
+ if (out_tmp > 4095) {
+ out[i][n] = (int16_t)32767;
+ } else if (out_tmp < -4096) {
+ out[i][n] = (int16_t)-32768;
+ } else {
+ int32_t tmp32 = ((int64_t)out[i][n] * (gain32 >> 4)) >> 16;
+ out[i][n] = (int16_t)tmp32;
+ }
+ }
+
+ gain32 += delta;
+ }
+ // iterate over subframes
+ for (int k = 1; k < 10; k++) {
+ delta = (gains[k + 1] - gains[k]) * (1 << (4 - L2));
+ gain32 = gains[k] * (1 << 4);
+ // iterate over samples
+ for (size_t n = 0; n < L; n++) {
+ for (size_t i = 0; i < num_bands; ++i) {
+ int64_t tmp64 = ((int64_t)(out[i][k * L + n])) * (gain32 >> 4);
+ tmp64 = tmp64 >> 16;
+ if (tmp64 > 32767) {
+ out[i][k * L + n] = 32767;
+ } else if (tmp64 < -32768) {
+ out[i][k * L + n] = -32768;
+ } else {
+ out[i][k * L + n] = (int16_t)(tmp64);
+ }
+ }
+ gain32 += delta;
+ }
+ }
+ return 0;
+}
+
+void WebRtcAgc_InitVad(AgcVad* state) {
+ int16_t k;
+
+ state->HPstate = 0; // state of high pass filter
+ state->logRatio = 0; // log( P(active) / P(inactive) )
+ // average input level (Q10)
+ state->meanLongTerm = 15 << 10;
+
+ // variance of input level (Q8)
+ state->varianceLongTerm = 500 << 8;
+
+ state->stdLongTerm = 0; // standard deviation of input level in dB
+ // short-term average input level (Q10)
+ state->meanShortTerm = 15 << 10;
+
+ // short-term variance of input level (Q8)
+ state->varianceShortTerm = 500 << 8;
+
+ state->stdShortTerm =
+ 0; // short-term standard deviation of input level in dB
+ state->counter = 3; // counts updates
+ for (k = 0; k < 8; k++) {
+ // downsampling filter
+ state->downState[k] = 0;
+ }
+}
+
+int16_t WebRtcAgc_ProcessVad(AgcVad* state, // (i) VAD state
+ const int16_t* in, // (i) Speech signal
+ size_t nrSamples) { // (i) number of samples
+ uint32_t nrg;
+ int32_t out, tmp32, tmp32b;
+ uint16_t tmpU16;
+ int16_t k, subfr, tmp16;
+ int16_t buf1[8];
+ int16_t buf2[4];
+ int16_t HPstate;
+ int16_t zeros, dB;
+ int64_t tmp64;
+
+ // process in 10 sub frames of 1 ms (to save on memory)
+ nrg = 0;
+ HPstate = state->HPstate;
+ for (subfr = 0; subfr < 10; subfr++) {
+ // downsample to 4 kHz
+ if (nrSamples == 160) {
+ for (k = 0; k < 8; k++) {
+ tmp32 = (int32_t)in[2 * k] + (int32_t)in[2 * k + 1];
+ tmp32 >>= 1;
+ buf1[k] = (int16_t)tmp32;
+ }
+ in += 16;
+
+ WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState);
+ } else {
+ WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState);
+ in += 8;
+ }
+
+ // high pass filter and compute energy
+ for (k = 0; k < 4; k++) {
+ out = buf2[k] + HPstate;
+ tmp32 = 600 * out;
+ HPstate = (int16_t)((tmp32 >> 10) - buf2[k]);
+
+ // Add 'out * out / 2**6' to 'nrg' in a non-overflowing
+ // way. Guaranteed to work as long as 'out * out / 2**6' fits in
+ // an int32_t.
+ nrg += out * (out / (1 << 6));
+ nrg += out * (out % (1 << 6)) / (1 << 6);
+ }
+ }
+ state->HPstate = HPstate;
+
+ // find number of leading zeros
+ if (!(0xFFFF0000 & nrg)) {
+ zeros = 16;
+ } else {
+ zeros = 0;
+ }
+ if (!(0xFF000000 & (nrg << zeros))) {
+ zeros += 8;
+ }
+ if (!(0xF0000000 & (nrg << zeros))) {
+ zeros += 4;
+ }
+ if (!(0xC0000000 & (nrg << zeros))) {
+ zeros += 2;
+ }
+ if (!(0x80000000 & (nrg << zeros))) {
+ zeros += 1;
+ }
+
+ // energy level (range {-32..30}) (Q10)
+ dB = (15 - zeros) * (1 << 11);
+
+ // Update statistics
+
+ if (state->counter < kAvgDecayTime) {
+ // decay time = AvgDecTime * 10 ms
+ state->counter++;
+ }
+
+ // update short-term estimate of mean energy level (Q10)
+ tmp32 = state->meanShortTerm * 15 + dB;
+ state->meanShortTerm = (int16_t)(tmp32 >> 4);
+
+ // update short-term estimate of variance in energy level (Q8)
+ tmp32 = (dB * dB) >> 12;
+ tmp32 += state->varianceShortTerm * 15;
+ state->varianceShortTerm = tmp32 / 16;
+
+ // update short-term estimate of standard deviation in energy level (Q10)
+ tmp32 = state->meanShortTerm * state->meanShortTerm;
+ tmp32 = (state->varianceShortTerm << 12) - tmp32;
+ state->stdShortTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
+
+ // update long-term estimate of mean energy level (Q10)
+ tmp32 = state->meanLongTerm * state->counter + dB;
+ state->meanLongTerm =
+ WebRtcSpl_DivW32W16ResW16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
+
+ // update long-term estimate of variance in energy level (Q8)
+ tmp32 = (dB * dB) >> 12;
+ tmp32 += state->varianceLongTerm * state->counter;
+ state->varianceLongTerm =
+ WebRtcSpl_DivW32W16(tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
+
+ // update long-term estimate of standard deviation in energy level (Q10)
+ tmp32 = state->meanLongTerm * state->meanLongTerm;
+ tmp32 = (state->varianceLongTerm << 12) - tmp32;
+ state->stdLongTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
+
+ // update voice activity measure (Q10)
+ tmp16 = 3 << 12;
+ // TODO(bjornv): (dB - state->meanLongTerm) can overflow, e.g., in
+ // ApmTest.Process unit test. Previously the macro WEBRTC_SPL_MUL_16_16()
+ // was used, which did an intermediate cast to (int16_t), hence losing
+ // significant bits. This cause logRatio to max out positive, rather than
+ // negative. This is a bug, but has very little significance.
+ tmp32 = tmp16 * (int16_t)(dB - state->meanLongTerm);
+ tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm);
+ tmpU16 = (13 << 12);
+ tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16);
+ tmp64 = tmp32;
+ tmp64 += tmp32b >> 10;
+ tmp64 >>= 6;
+
+ // limit
+ if (tmp64 > 2048) {
+ tmp64 = 2048;
+ } else if (tmp64 < -2048) {
+ tmp64 = -2048;
+ }
+ state->logRatio = (int16_t)tmp64;
+
+ return state->logRatio; // Q10
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc/legacy/digital_agc.h b/webrtc/modules/audio_processing/agc/legacy/digital_agc.h
index 819844d..223c74b 100644
--- a/webrtc/modules/audio_processing/agc/legacy/digital_agc.h
+++ b/webrtc/modules/audio_processing/agc/legacy/digital_agc.h
@@ -8,58 +8,51 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
+#ifndef MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
+#define MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
-#ifdef WEBRTC_AGC_DEBUG_DUMP
-#include <stdio.h>
-#endif
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/typedefs.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
-// the 32 most significant bits of A(19) * B(26) >> 13
-#define AGC_MUL32(A, B) (((B)>>13)*(A) + ( ((0x00001FFF & (B))*(A)) >> 13 ))
-// C + the 32 most significant bits of A * B
-#define AGC_SCALEDIFF32(A, B, C) ((C) + ((B)>>16)*(A) + ( ((0x0000FFFF & (B))*(A)) >> 16 ))
+namespace webrtc {
-typedef struct
-{
- int32_t downState[8];
- int16_t HPstate;
- int16_t counter;
- int16_t logRatio; // log( P(active) / P(inactive) ) (Q10)
- int16_t meanLongTerm; // Q10
- int32_t varianceLongTerm; // Q8
- int16_t stdLongTerm; // Q10
- int16_t meanShortTerm; // Q10
- int32_t varianceShortTerm; // Q8
- int16_t stdShortTerm; // Q10
-} AgcVad; // total = 54 bytes
+typedef struct {
+ int32_t downState[8];
+ int16_t HPstate;
+ int16_t counter;
+ int16_t logRatio; // log( P(active) / P(inactive) ) (Q10)
+ int16_t meanLongTerm; // Q10
+ int32_t varianceLongTerm; // Q8
+ int16_t stdLongTerm; // Q10
+ int16_t meanShortTerm; // Q10
+ int32_t varianceShortTerm; // Q8
+ int16_t stdShortTerm; // Q10
+} AgcVad; // total = 54 bytes
-typedef struct
-{
- int32_t capacitorSlow;
- int32_t capacitorFast;
- int32_t gain;
- int32_t gainTable[32];
- int16_t gatePrevious;
- int16_t agcMode;
- AgcVad vadNearend;
- AgcVad vadFarend;
-#ifdef WEBRTC_AGC_DEBUG_DUMP
- FILE* logFile;
- int frameCounter;
-#endif
+typedef struct {
+ int32_t capacitorSlow;
+ int32_t capacitorFast;
+ int32_t gain;
+ int32_t gainTable[32];
+ int16_t gatePrevious;
+ int16_t agcMode;
+ AgcVad vadNearend;
+ AgcVad vadFarend;
} DigitalAgc;
int32_t WebRtcAgc_InitDigital(DigitalAgc* digitalAgcInst, int16_t agcMode);
-int32_t WebRtcAgc_ProcessDigital(DigitalAgc* digitalAgcInst,
- const int16_t* const* inNear,
- size_t num_bands,
- int16_t* const* out,
- uint32_t FS,
- int16_t lowLevelSignal);
+int32_t WebRtcAgc_ComputeDigitalGains(DigitalAgc* digitalAgcInst,
+ const int16_t* const* inNear,
+ size_t num_bands,
+ uint32_t FS,
+ int16_t lowLevelSignal,
+ int32_t gains[11]);
+
+int32_t WebRtcAgc_ApplyDigitalGains(const int32_t gains[11],
+ size_t num_bands,
+ uint32_t FS,
+ const int16_t* const* in_near,
+ int16_t* const* out);
int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* digitalAgcInst,
const int16_t* inFar,
@@ -67,14 +60,16 @@ int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* digitalAgcInst,
void WebRtcAgc_InitVad(AgcVad* vadInst);
-int16_t WebRtcAgc_ProcessVad(AgcVad* vadInst, // (i) VAD state
- const int16_t* in, // (i) Speech signal
+int16_t WebRtcAgc_ProcessVad(AgcVad* vadInst, // (i) VAD state
+ const int16_t* in, // (i) Speech signal
size_t nrSamples); // (i) number of samples
-int32_t WebRtcAgc_CalculateGainTable(int32_t *gainTable, // Q16
- int16_t compressionGaindB, // Q0 (in dB)
- int16_t targetLevelDbfs,// Q0 (in dB)
+int32_t WebRtcAgc_CalculateGainTable(int32_t* gainTable, // Q16
+ int16_t compressionGaindB, // Q0 (in dB)
+ int16_t targetLevelDbfs, // Q0 (in dB)
uint8_t limiterEnable,
int16_t analogTarget);
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
diff --git a/webrtc/modules/audio_processing/agc/legacy/gain_control.h b/webrtc/modules/audio_processing/agc/legacy/gain_control.h
index 08c1988..abb8e63 100644
--- a/webrtc/modules/audio_processing/agc/legacy/gain_control.h
+++ b/webrtc/modules/audio_processing/agc/legacy/gain_control.h
@@ -8,46 +8,39 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
-
-#include "webrtc/typedefs.h"
-
-// Errors
-#define AGC_UNSPECIFIED_ERROR 18000
-#define AGC_UNSUPPORTED_FUNCTION_ERROR 18001
-#define AGC_UNINITIALIZED_ERROR 18002
-#define AGC_NULL_POINTER_ERROR 18003
-#define AGC_BAD_PARAMETER_ERROR 18004
-
-// Warnings
-#define AGC_BAD_PARAMETER_WARNING 18050
-
-enum
-{
- kAgcModeUnchanged,
- kAgcModeAdaptiveAnalog,
- kAgcModeAdaptiveDigital,
- kAgcModeFixedDigital
-};
+#ifndef MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
+#define MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
+
+namespace webrtc {
-enum
-{
- kAgcFalse = 0,
- kAgcTrue
+enum {
+ kAgcModeUnchanged,
+ kAgcModeAdaptiveAnalog,
+ kAgcModeAdaptiveDigital,
+ kAgcModeFixedDigital
};
-typedef struct
-{
- int16_t targetLevelDbfs; // default 3 (-3 dBOv)
- int16_t compressionGaindB; // default 9 dB
- uint8_t limiterEnable; // default kAgcTrue (on)
+enum { kAgcFalse = 0, kAgcTrue };
+
+typedef struct {
+ int16_t targetLevelDbfs; // default 3 (-3 dBOv)
+ int16_t compressionGaindB; // default 9 dB
+ uint8_t limiterEnable; // default kAgcTrue (on)
} WebRtcAgcConfig;
-#if defined(__cplusplus)
-extern "C"
-{
-#endif
+/*
+ * This function analyses the number of samples passed to
+ * farend and produces any error code that could arise.
+ *
+ * Input:
+ * - agcInst : AGC instance.
+ * - samples : Number of samples in input vector.
+ *
+ * Return value:
+ * : 0 - Normal operation.
+ * : -1 - Error.
+ */
+int WebRtcAgc_GetAddFarendError(void* state, size_t samples);
/*
* This function processes a 10 ms frame of far-end speech to determine
@@ -64,9 +57,7 @@ extern "C"
* : 0 - Normal operation.
* : -1 - Error
*/
-int WebRtcAgc_AddFarend(void* agcInst,
- const int16_t* inFar,
- size_t samples);
+int WebRtcAgc_AddFarend(void* agcInst, const int16_t* inFar, size_t samples);
/*
* This function processes a 10 ms frame of microphone speech to determine
@@ -124,12 +115,12 @@ int WebRtcAgc_VirtualMic(void* agcInst,
int32_t* micLevelOut);
/*
- * This function processes a 10 ms frame and adjusts (normalizes) the gain both
- * analog and digitally. The gain adjustments are done only during active
- * periods of speech. The length of the speech vectors must be given in samples
- * (80 when FS=8000, and 160 when FS=16000, FS=32000 or FS=48000). The echo
- * parameter can be used to ensure the AGC will not adjust upward in the
- * presence of echo.
+ * This function analyses a 10 ms frame and produces the analog and digital
+ * gains required to normalize the signal. The gain adjustments are done only
+ * during active periods of speech. The length of the speech vectors must be
+ * given in samples (80 when FS=8000, and 160 when FS=16000, FS=32000 or
+ * FS=48000). The echo parameter can be used to ensure the AGC will not adjust
+ * upward in the presence of echo.
*
* This function should be called after processing the near-end microphone
* signal, in any case after any echo cancellation.
@@ -147,25 +138,47 @@ int WebRtcAgc_VirtualMic(void* agcInst,
*
* Output:
* - outMicLevel : Adjusted microphone volume level
- * - out : Gain-adjusted near-end speech vector
- * : May be the same vector as the input.
* - saturationWarning : A returned value of 1 indicates a saturation event
* has occurred and the volume cannot be further
* reduced. Otherwise will be set to 0.
+ * - gains : Vector of gains to apply for digital normalization
*
* Return value:
* : 0 - Normal operation.
* : -1 - Error
*/
-int WebRtcAgc_Process(void* agcInst,
+int WebRtcAgc_Analyze(void* agcInst,
const int16_t* const* inNear,
size_t num_bands,
size_t samples,
- int16_t* const* out,
int32_t inMicLevel,
int32_t* outMicLevel,
int16_t echo,
- uint8_t* saturationWarning);
+ uint8_t* saturationWarning,
+ int32_t gains[11]);
+
+/*
+ * This function processes a 10 ms frame by applying precomputed digital gains.
+ *
+ * Input:
+ * - agcInst : AGC instance
+ * - gains : Vector of gains to apply for digital normalization
+ * - in_near : Near-end input speech vector for each band
+ * - num_bands : Number of bands in input/output vector
+ *
+ * Output:
+ * - out : Gain-adjusted near-end speech vector
+ * : May be the same vector as the input.
+ *
+ * Return value:
+ * : 0 - Normal operation.
+ * : -1 - Error
+ */
+int WebRtcAgc_Process(const void* agcInst,
+ const int32_t gains[11],
+ const int16_t* const* in_near,
+ size_t num_bands,
+ int16_t* const* out);
/*
* This function sets the config parameters (targetLevelDbfs,
@@ -203,7 +216,7 @@ int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config);
* This function creates and returns an AGC instance, which will contain the
* state information for one (duplex) channel.
*/
-void* WebRtcAgc_Create();
+void* WebRtcAgc_Create(void);
/*
* This function frees the AGC instance created at the beginning.
@@ -229,14 +242,12 @@ void WebRtcAgc_Free(void* agcInst);
* Return value : 0 - Ok
* -1 - Error
*/
-int WebRtcAgc_Init(void *agcInst,
+int WebRtcAgc_Init(void* agcInst,
int32_t minLevel,
int32_t maxLevel,
int16_t agcMode,
uint32_t fs);
-#if defined(__cplusplus)
-}
-#endif
+} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
+#endif // MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
diff --git a/webrtc/modules/audio_processing/agc/histogram.cc b/webrtc/modules/audio_processing/agc/loudness_histogram.cc
index 1d3035f..4775ff7 100644
--- a/webrtc/modules/audio_processing/agc/histogram.cc
+++ b/webrtc/modules/audio_processing/agc/loudness_histogram.cc
@@ -8,57 +8,58 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/agc/histogram.h"
+#include "modules/audio_processing/agc/loudness_histogram.h"
+
+#include <string.h>
#include <cmath>
-#include <cstring>
-#include "webrtc/modules/interface/module_common_types.h"
+#include "rtc_base/checks.h"
namespace webrtc {
static const double kHistBinCenters[] = {
- 7.59621091765857e-02, 9.02036021061016e-02, 1.07115112009343e-01,
- 1.27197217770508e-01, 1.51044347572047e-01, 1.79362373905283e-01,
- 2.12989507320644e-01, 2.52921107370304e-01, 3.00339145144454e-01,
- 3.56647189489147e-01, 4.23511952494003e-01, 5.02912623991786e-01,
- 5.97199455365749e-01, 7.09163326739184e-01, 8.42118356728544e-01,
- 1.00000000000000e+00, 1.18748153630660e+00, 1.41011239906908e+00,
- 1.67448243801153e+00, 1.98841697800836e+00, 2.36120844786349e+00,
- 2.80389143520905e+00, 3.32956930911896e+00, 3.95380207843188e+00,
- 4.69506696634852e+00, 5.57530533426190e+00, 6.62057214370769e+00,
- 7.86180718043869e+00, 9.33575086877358e+00, 1.10860317842269e+01,
- 1.31644580546776e+01, 1.56325508754123e+01, 1.85633655299256e+01,
- 2.20436538184971e+01, 2.61764319021997e+01, 3.10840295702492e+01,
- 3.69117111886792e+01, 4.38319755100383e+01, 5.20496616180135e+01,
- 6.18080121423973e+01, 7.33958732149108e+01, 8.71562442838066e+01,
- 1.03496430860848e+02, 1.22900100720889e+02, 1.45941600416277e+02,
- 1.73302955873365e+02, 2.05794060286978e+02, 2.44376646872353e+02,
- 2.90192756065437e+02, 3.44598539797631e+02, 4.09204403447902e+02,
- 4.85922673669740e+02, 5.77024203055553e+02, 6.85205587130498e+02,
- 8.13668983291589e+02, 9.66216894324125e+02, 1.14736472207740e+03,
- 1.36247442287647e+03, 1.61791322085579e+03, 1.92124207711260e+03,
- 2.28143949334655e+03, 2.70916727454970e+03, 3.21708611729384e+03,
- 3.82023036499473e+03, 4.53645302286906e+03, 5.38695420497926e+03,
- 6.39690865534207e+03, 7.59621091765857e+03, 9.02036021061016e+03,
- 1.07115112009343e+04, 1.27197217770508e+04, 1.51044347572047e+04,
- 1.79362373905283e+04, 2.12989507320644e+04, 2.52921107370304e+04,
- 3.00339145144454e+04, 3.56647189489147e+04};
+ 7.59621091765857e-02, 9.02036021061016e-02, 1.07115112009343e-01,
+ 1.27197217770508e-01, 1.51044347572047e-01, 1.79362373905283e-01,
+ 2.12989507320644e-01, 2.52921107370304e-01, 3.00339145144454e-01,
+ 3.56647189489147e-01, 4.23511952494003e-01, 5.02912623991786e-01,
+ 5.97199455365749e-01, 7.09163326739184e-01, 8.42118356728544e-01,
+ 1.00000000000000e+00, 1.18748153630660e+00, 1.41011239906908e+00,
+ 1.67448243801153e+00, 1.98841697800836e+00, 2.36120844786349e+00,
+ 2.80389143520905e+00, 3.32956930911896e+00, 3.95380207843188e+00,
+ 4.69506696634852e+00, 5.57530533426190e+00, 6.62057214370769e+00,
+ 7.86180718043869e+00, 9.33575086877358e+00, 1.10860317842269e+01,
+ 1.31644580546776e+01, 1.56325508754123e+01, 1.85633655299256e+01,
+ 2.20436538184971e+01, 2.61764319021997e+01, 3.10840295702492e+01,
+ 3.69117111886792e+01, 4.38319755100383e+01, 5.20496616180135e+01,
+ 6.18080121423973e+01, 7.33958732149108e+01, 8.71562442838066e+01,
+ 1.03496430860848e+02, 1.22900100720889e+02, 1.45941600416277e+02,
+ 1.73302955873365e+02, 2.05794060286978e+02, 2.44376646872353e+02,
+ 2.90192756065437e+02, 3.44598539797631e+02, 4.09204403447902e+02,
+ 4.85922673669740e+02, 5.77024203055553e+02, 6.85205587130498e+02,
+ 8.13668983291589e+02, 9.66216894324125e+02, 1.14736472207740e+03,
+ 1.36247442287647e+03, 1.61791322085579e+03, 1.92124207711260e+03,
+ 2.28143949334655e+03, 2.70916727454970e+03, 3.21708611729384e+03,
+ 3.82023036499473e+03, 4.53645302286906e+03, 5.38695420497926e+03,
+ 6.39690865534207e+03, 7.59621091765857e+03, 9.02036021061016e+03,
+ 1.07115112009343e+04, 1.27197217770508e+04, 1.51044347572047e+04,
+ 1.79362373905283e+04, 2.12989507320644e+04, 2.52921107370304e+04,
+ 3.00339145144454e+04, 3.56647189489147e+04};
static const double kProbQDomain = 1024.0;
// Loudness of -15 dB (smallest expected loudness) in log domain,
// loudness_db = 13.5 * log10(rms);
static const double kLogDomainMinBinCenter = -2.57752062648587;
// Loudness step of 1 dB in log domain
-static const double kLogDomainStepSizeInverse = 5.81954605750359;
+static const double kLogDomainStepSizeInverse = 5.81954605750359;
static const int kTransientWidthThreshold = 7;
static const double kLowProbabilityThreshold = 0.2;
-static const int kLowProbThresholdQ10 = static_cast<int>(
- kLowProbabilityThreshold * kProbQDomain);
+static const int kLowProbThresholdQ10 =
+ static_cast<int>(kLowProbabilityThreshold * kProbQDomain);
-Histogram::Histogram()
+LoudnessHistogram::LoudnessHistogram()
: num_updates_(0),
audio_content_q10_(0),
bin_count_q10_(),
@@ -73,7 +74,7 @@ Histogram::Histogram()
"histogram bin centers incorrect size");
}
-Histogram::Histogram(int window_size)
+LoudnessHistogram::LoudnessHistogram(int window_size)
: num_updates_(0),
audio_content_q10_(0),
bin_count_q10_(),
@@ -84,9 +85,9 @@ Histogram::Histogram(int window_size)
len_circular_buffer_(window_size),
len_high_activity_(0) {}
-Histogram::~Histogram() {}
+LoudnessHistogram::~LoudnessHistogram() {}
-void Histogram::Update(double rms, double activity_probaility) {
+void LoudnessHistogram::Update(double rms, double activity_probaility) {
// If circular histogram is activated then remove the oldest entry.
if (len_circular_buffer_ > 0)
RemoveOldestEntryAndUpdate();
@@ -94,14 +95,14 @@ void Histogram::Update(double rms, double activity_probaility) {
// Find the corresponding bin.
int hist_index = GetBinIndex(rms);
// To Q10 domain.
- int prob_q10 = static_cast<int16_t>(floor(activity_probaility *
- kProbQDomain));
+ int prob_q10 =
+ static_cast<int16_t>(floor(activity_probaility * kProbQDomain));
InsertNewestEntryAndUpdate(prob_q10, hist_index);
}
// Doing nothing if buffer is not full, yet.
-void Histogram::RemoveOldestEntryAndUpdate() {
- assert(len_circular_buffer_ > 0);
+void LoudnessHistogram::RemoveOldestEntryAndUpdate() {
+ RTC_DCHECK_GT(len_circular_buffer_, 0);
// Do nothing if circular buffer is not full.
if (!buffer_is_full_)
return;
@@ -111,12 +112,12 @@ void Histogram::RemoveOldestEntryAndUpdate() {
UpdateHist(-oldest_prob, oldest_hist_index);
}
-void Histogram::RemoveTransient() {
+void LoudnessHistogram::RemoveTransient() {
// Don't expect to be here if high-activity region is longer than
// |kTransientWidthThreshold| or there has not been any transient.
- assert(len_high_activity_ <= kTransientWidthThreshold);
- int index = (buffer_index_ > 0) ? (buffer_index_ - 1) :
- len_circular_buffer_ - 1;
+ RTC_DCHECK_LE(len_high_activity_, kTransientWidthThreshold);
+ int index =
+ (buffer_index_ > 0) ? (buffer_index_ - 1) : len_circular_buffer_ - 1;
while (len_high_activity_ > 0) {
UpdateHist(-activity_probability_[index], hist_bin_index_[index]);
activity_probability_[index] = 0;
@@ -125,8 +126,8 @@ void Histogram::RemoveTransient() {
}
}
-void Histogram::InsertNewestEntryAndUpdate(int activity_prob_q10,
- int hist_index) {
+void LoudnessHistogram::InsertNewestEntryAndUpdate(int activity_prob_q10,
+ int hist_index) {
// Update the circular buffer if it is enabled.
if (len_circular_buffer_ > 0) {
// Removing transient.
@@ -158,26 +159,26 @@ void Histogram::InsertNewestEntryAndUpdate(int activity_prob_q10,
UpdateHist(activity_prob_q10, hist_index);
}
-void Histogram::UpdateHist(int activity_prob_q10, int hist_index) {
+void LoudnessHistogram::UpdateHist(int activity_prob_q10, int hist_index) {
bin_count_q10_[hist_index] += activity_prob_q10;
audio_content_q10_ += activity_prob_q10;
}
-double Histogram::AudioContent() const {
+double LoudnessHistogram::AudioContent() const {
return audio_content_q10_ / kProbQDomain;
}
-Histogram* Histogram::Create() {
- return new Histogram;
+LoudnessHistogram* LoudnessHistogram::Create() {
+ return new LoudnessHistogram;
}
-Histogram* Histogram::Create(int window_size) {
+LoudnessHistogram* LoudnessHistogram::Create(int window_size) {
if (window_size < 0)
return NULL;
- return new Histogram(window_size);
+ return new LoudnessHistogram(window_size);
}
-void Histogram::Reset() {
+void LoudnessHistogram::Reset() {
// Reset the histogram, audio-content and number of updates.
memset(bin_count_q10_, 0, sizeof(bin_count_q10_));
audio_content_q10_ = 0;
@@ -188,7 +189,7 @@ void Histogram::Reset() {
len_high_activity_ = 0;
}
-int Histogram::GetBinIndex(double rms) {
+int LoudnessHistogram::GetBinIndex(double rms) {
// First exclude overload cases.
if (rms <= kHistBinCenters[0]) {
return 0;
@@ -199,8 +200,8 @@ int Histogram::GetBinIndex(double rms) {
// search in linear domain.
double rms_log = log(rms);
- int index = static_cast<int>(floor((rms_log - kLogDomainMinBinCenter) *
- kLogDomainStepSizeInverse));
+ int index = static_cast<int>(
+ floor((rms_log - kLogDomainMinBinCenter) * kLogDomainStepSizeInverse));
// The final decision is in linear domain.
double b = 0.5 * (kHistBinCenters[index] + kHistBinCenters[index + 1]);
if (rms > b) {
@@ -210,7 +211,7 @@ int Histogram::GetBinIndex(double rms) {
}
}
-double Histogram::CurrentRms() const {
+double LoudnessHistogram::CurrentRms() const {
double p;
double mean_val = 0;
if (audio_content_q10_ > 0) {
diff --git a/webrtc/modules/audio_processing/agc/histogram.h b/webrtc/modules/audio_processing/agc/loudness_histogram.h
index a8706bb..badd443 100644
--- a/webrtc/modules/audio_processing/agc/histogram.h
+++ b/webrtc/modules/audio_processing/agc/loudness_histogram.h
@@ -8,27 +8,26 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_HISTOGRAM_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_HISTOGRAM_H_
+#ifndef MODULES_AUDIO_PROCESSING_AGC_LOUDNESS_HISTOGRAM_H_
+#define MODULES_AUDIO_PROCESSING_AGC_LOUDNESS_HISTOGRAM_H_
-#include <string.h>
+#include <stdint.h>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/typedefs.h"
+#include <memory>
namespace webrtc {
// This class implements the histogram of loudness with circular buffers so that
// the histogram tracks the last T seconds of the loudness.
-class Histogram {
+class LoudnessHistogram {
public:
- // Create a non-sliding Histogram.
- static Histogram* Create();
+ // Create a non-sliding LoudnessHistogram.
+ static LoudnessHistogram* Create();
- // Create a sliding Histogram, i.e. the histogram represents the last
+ // Create a sliding LoudnessHistogram, i.e. the histogram represents the last
// |window_size| samples.
- static Histogram* Create(int window_size);
- ~Histogram();
+ static LoudnessHistogram* Create(int window_size);
+ ~LoudnessHistogram();
// Insert RMS and the corresponding activity probability.
void Update(double rms, double activity_probability);
@@ -47,8 +46,8 @@ class Histogram {
int num_updates() const { return num_updates_; }
private:
- Histogram();
- explicit Histogram(int window);
+ LoudnessHistogram();
+ explicit LoudnessHistogram(int window);
// Find the histogram bin associated with the given |rms|.
int GetBinIndex(double rms);
@@ -67,15 +66,15 @@ class Histogram {
// |bin_count_q10_|.
int64_t audio_content_q10_;
- // Histogram of input RMS in Q10 with |kHistSize_| bins. In each 'Update(),'
- // we increment the associated histogram-bin with the given probability. The
- // increment is implemented in Q10 to avoid rounding errors.
+ // LoudnessHistogram of input RMS in Q10 with |kHistSize_| bins. In each
+ // 'Update(),' we increment the associated histogram-bin with the given
+ // probability. The increment is implemented in Q10 to avoid rounding errors.
int64_t bin_count_q10_[kHistSize];
// Circular buffer for probabilities
- rtc::scoped_ptr<int[]> activity_probability_;
+ std::unique_ptr<int[]> activity_probability_;
// Circular buffer for histogram-indices of probabilities.
- rtc::scoped_ptr<int[]> hist_bin_index_;
+ std::unique_ptr<int[]> hist_bin_index_;
// Current index of circular buffer, where the newest data will be written to,
// therefore, pointing to the oldest data if buffer is full.
int buffer_index_;
@@ -88,4 +87,4 @@ class Histogram {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_HISTOGRAM_H_
+#endif // MODULES_AUDIO_PROCESSING_AGC_LOUDNESS_HISTOGRAM_H_
diff --git a/webrtc/modules/audio_processing/agc/mock_agc.h b/webrtc/modules/audio_processing/agc/mock_agc.h
new file mode 100644
index 0000000..0ef41c6
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc/mock_agc.h
@@ -0,0 +1,34 @@
+/*
+ * 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_AUDIO_PROCESSING_AGC_MOCK_AGC_H_
+#define MODULES_AUDIO_PROCESSING_AGC_MOCK_AGC_H_
+
+#include "modules/audio_processing/agc/agc.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+class MockAgc : public Agc {
+ public:
+ virtual ~MockAgc() {}
+ MOCK_METHOD(void,
+ Process,
+ (const int16_t* audio, size_t length, int sample_rate_hz),
+ (override));
+ MOCK_METHOD(bool, GetRmsErrorDb, (int* error), (override));
+ MOCK_METHOD(void, Reset, (), (override));
+ MOCK_METHOD(int, set_target_level_dbfs, (int level), (override));
+ MOCK_METHOD(int, target_level_dbfs, (), (const, override));
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC_MOCK_AGC_H_
diff --git a/webrtc/modules/audio_processing/agc/utility.cc b/webrtc/modules/audio_processing/agc/utility.cc
index 48458ad..2a87e5c 100644
--- a/webrtc/modules/audio_processing/agc/utility.cc
+++ b/webrtc/modules/audio_processing/agc/utility.cc
@@ -8,10 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/agc/utility.h"
+#include "modules/audio_processing/agc/utility.h"
#include <math.h>
+namespace webrtc {
+
static const double kLog10 = 2.30258509299;
static const double kLinear2DbScale = 20.0 / kLog10;
static const double kLinear2LoudnessScale = 13.4 / kLog10;
@@ -33,3 +35,5 @@ double Db2Loudness(double db) {
double Dbfs2Loudness(double dbfs) {
return Db2Loudness(90 + dbfs);
}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc/utility.h b/webrtc/modules/audio_processing/agc/utility.h
index df85c2e..56eec24 100644
--- a/webrtc/modules/audio_processing/agc/utility.h
+++ b/webrtc/modules/audio_processing/agc/utility.h
@@ -8,8 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
+#ifndef MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
+#define MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
+
+namespace webrtc {
// TODO(turajs): Add description of function.
double Loudness2Db(double loudness);
@@ -20,4 +22,6 @@ double Db2Loudness(double db);
double Dbfs2Loudness(double dbfs);
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
diff --git a/webrtc/modules/audio_processing/agc2/BUILD.gn b/webrtc/modules/audio_processing/agc2/BUILD.gn
new file mode 100644
index 0000000..bf09533
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/BUILD.gn
@@ -0,0 +1,290 @@
+# 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.
+
+import("../../../webrtc.gni")
+
+group("agc2") {
+ deps = [
+ ":adaptive_digital",
+ ":fixed_digital",
+ ]
+}
+
+rtc_library("level_estimation_agc") {
+ sources = [
+ "adaptive_mode_level_estimator_agc.cc",
+ "adaptive_mode_level_estimator_agc.h",
+ ]
+ configs += [ "..:apm_debug_dump" ]
+ deps = [
+ ":adaptive_digital",
+ ":common",
+ ":gain_applier",
+ ":noise_level_estimator",
+ ":rnn_vad_with_level",
+ "..:api",
+ "..:apm_logging",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../common_audio",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:safe_minmax",
+ "../agc:level_estimation",
+ "../vad",
+ ]
+}
+
+rtc_library("adaptive_digital") {
+ sources = [
+ "adaptive_agc.cc",
+ "adaptive_agc.h",
+ "adaptive_digital_gain_applier.cc",
+ "adaptive_digital_gain_applier.h",
+ "adaptive_mode_level_estimator.cc",
+ "adaptive_mode_level_estimator.h",
+ "saturation_protector.cc",
+ "saturation_protector.h",
+ ]
+
+ configs += [ "..:apm_debug_dump" ]
+
+ deps = [
+ ":common",
+ ":gain_applier",
+ ":noise_level_estimator",
+ ":rnn_vad_with_level",
+ "..:api",
+ "..:apm_logging",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../common_audio",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:logging",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:safe_compare",
+ "../../../rtc_base:safe_minmax",
+ "../../../system_wrappers:metrics",
+ ]
+
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_library("biquad_filter") {
+ visibility = [ "./*" ]
+ sources = [
+ "biquad_filter.cc",
+ "biquad_filter.h",
+ ]
+ deps = [
+ "../../../api:array_view",
+ "../../../rtc_base:rtc_base_approved",
+ ]
+}
+
+rtc_source_set("common") {
+ sources = [ "agc2_common.h" ]
+}
+
+rtc_library("fixed_digital") {
+ sources = [
+ "fixed_digital_level_estimator.cc",
+ "fixed_digital_level_estimator.h",
+ "interpolated_gain_curve.cc",
+ "interpolated_gain_curve.h",
+ "limiter.cc",
+ "limiter.h",
+ ]
+
+ configs += [ "..:apm_debug_dump" ]
+
+ deps = [
+ ":common",
+ "..:apm_logging",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../common_audio",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gtest_prod",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:safe_minmax",
+ "../../../system_wrappers:metrics",
+ ]
+}
+
+rtc_library("gain_applier") {
+ sources = [
+ "gain_applier.cc",
+ "gain_applier.h",
+ ]
+ deps = [
+ ":common",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../rtc_base:safe_minmax",
+ ]
+}
+
+rtc_library("noise_level_estimator") {
+ sources = [
+ "down_sampler.cc",
+ "down_sampler.h",
+ "noise_level_estimator.cc",
+ "noise_level_estimator.h",
+ "noise_spectrum_estimator.cc",
+ "noise_spectrum_estimator.h",
+ "signal_classifier.cc",
+ "signal_classifier.h",
+ ]
+ deps = [
+ ":biquad_filter",
+ "..:apm_logging",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../common_audio",
+ "../../../common_audio/third_party/ooura:fft_size_128",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:macromagic",
+ "../../../system_wrappers",
+ ]
+
+ configs += [ "..:apm_debug_dump" ]
+}
+
+rtc_library("rnn_vad_with_level") {
+ sources = [
+ "vad_with_level.cc",
+ "vad_with_level.h",
+ ]
+ deps = [
+ ":common",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../common_audio",
+ "../../../rtc_base:checks",
+ "rnn_vad",
+ "rnn_vad:rnn_vad_common",
+ ]
+}
+
+rtc_library("adaptive_digital_unittests") {
+ testonly = true
+ configs += [ "..:apm_debug_dump" ]
+
+ sources = [
+ "adaptive_digital_gain_applier_unittest.cc",
+ "adaptive_mode_level_estimator_unittest.cc",
+ "gain_applier_unittest.cc",
+ "saturation_protector_unittest.cc",
+ ]
+ deps = [
+ ":adaptive_digital",
+ ":common",
+ ":gain_applier",
+ ":test_utils",
+ "..:apm_logging",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../common_audio",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gunit_helpers",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../test:test_support",
+ ]
+}
+
+rtc_library("biquad_filter_unittests") {
+ testonly = true
+ sources = [ "biquad_filter_unittest.cc" ]
+ deps = [
+ ":biquad_filter",
+ "../../../rtc_base:gunit_helpers",
+ ]
+}
+
+rtc_library("fixed_digital_unittests") {
+ testonly = true
+ configs += [ "..:apm_debug_dump" ]
+
+ sources = [
+ "agc2_testing_common_unittest.cc",
+ "compute_interpolated_gain_curve.cc",
+ "compute_interpolated_gain_curve.h",
+ "fixed_digital_level_estimator_unittest.cc",
+ "interpolated_gain_curve_unittest.cc",
+ "limiter_db_gain_curve.cc",
+ "limiter_db_gain_curve.h",
+ "limiter_db_gain_curve_unittest.cc",
+ "limiter_unittest.cc",
+ ]
+ deps = [
+ ":common",
+ ":fixed_digital",
+ ":test_utils",
+ "..:apm_logging",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../common_audio",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gunit_helpers",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../system_wrappers:metrics",
+ ]
+}
+
+rtc_library("noise_estimator_unittests") {
+ testonly = true
+ configs += [ "..:apm_debug_dump" ]
+
+ sources = [
+ "noise_level_estimator_unittest.cc",
+ "signal_classifier_unittest.cc",
+ ]
+ deps = [
+ ":noise_level_estimator",
+ ":test_utils",
+ "..:apm_logging",
+ "..:audio_frame_view",
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gunit_helpers",
+ "../../../rtc_base:rtc_base_approved",
+ ]
+}
+
+rtc_library("rnn_vad_with_level_unittests") {
+ testonly = true
+ sources = [ "vad_with_level_unittest.cc" ]
+ deps = [
+ ":common",
+ ":rnn_vad_with_level",
+ "..:audio_frame_view",
+ "../../../rtc_base:gunit_helpers",
+ "../../../rtc_base:safe_compare",
+ "../../../test:test_support",
+ ]
+}
+
+rtc_library("test_utils") {
+ testonly = true
+ visibility = [
+ ":*",
+ "..:audio_processing_unittests",
+ ]
+ sources = [
+ "agc2_testing_common.cc",
+ "agc2_testing_common.h",
+ "vector_float_frame.cc",
+ "vector_float_frame.h",
+ ]
+ deps = [
+ "..:audio_frame_view",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ ]
+}
diff --git a/webrtc/modules/audio_processing/agc2/adaptive_agc.cc b/webrtc/modules/audio_processing/agc2/adaptive_agc.cc
new file mode 100644
index 0000000..0372ccf
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/adaptive_agc.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/adaptive_agc.h"
+
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace {
+
+void DumpDebugData(const AdaptiveDigitalGainApplier::FrameInfo& info,
+ ApmDataDumper& dumper) {
+ dumper.DumpRaw("agc2_vad_probability", info.vad_result.speech_probability);
+ dumper.DumpRaw("agc2_vad_rms_dbfs", info.vad_result.rms_dbfs);
+ dumper.DumpRaw("agc2_vad_peak_dbfs", info.vad_result.peak_dbfs);
+ dumper.DumpRaw("agc2_noise_estimate_dbfs", info.input_noise_level_dbfs);
+ dumper.DumpRaw("agc2_last_limiter_audio_level", info.limiter_envelope_dbfs);
+}
+
+constexpr int kGainApplierAdjacentSpeechFramesThreshold = 1;
+constexpr float kMaxGainChangePerSecondDb = 3.f;
+constexpr float kMaxOutputNoiseLevelDbfs = -50.f;
+
+} // namespace
+
+AdaptiveAgc::AdaptiveAgc(ApmDataDumper* apm_data_dumper)
+ : speech_level_estimator_(apm_data_dumper),
+ gain_applier_(apm_data_dumper,
+ kGainApplierAdjacentSpeechFramesThreshold,
+ kMaxGainChangePerSecondDb,
+ kMaxOutputNoiseLevelDbfs),
+ apm_data_dumper_(apm_data_dumper),
+ noise_level_estimator_(apm_data_dumper) {
+ RTC_DCHECK(apm_data_dumper);
+}
+
+AdaptiveAgc::AdaptiveAgc(ApmDataDumper* apm_data_dumper,
+ const AudioProcessing::Config::GainController2& config)
+ : speech_level_estimator_(
+ apm_data_dumper,
+ config.adaptive_digital.level_estimator,
+ config.adaptive_digital
+ .level_estimator_adjacent_speech_frames_threshold,
+ config.adaptive_digital.initial_saturation_margin_db,
+ config.adaptive_digital.extra_saturation_margin_db),
+ vad_(config.adaptive_digital.vad_probability_attack),
+ gain_applier_(
+ apm_data_dumper,
+ config.adaptive_digital.gain_applier_adjacent_speech_frames_threshold,
+ config.adaptive_digital.max_gain_change_db_per_second,
+ config.adaptive_digital.max_output_noise_level_dbfs),
+ apm_data_dumper_(apm_data_dumper),
+ noise_level_estimator_(apm_data_dumper) {
+ RTC_DCHECK(apm_data_dumper);
+ if (!config.adaptive_digital.use_saturation_protector) {
+ RTC_LOG(LS_WARNING) << "The saturation protector cannot be disabled.";
+ }
+}
+
+AdaptiveAgc::~AdaptiveAgc() = default;
+
+void AdaptiveAgc::Process(AudioFrameView<float> frame, float limiter_envelope) {
+ AdaptiveDigitalGainApplier::FrameInfo info;
+ info.vad_result = vad_.AnalyzeFrame(frame);
+ speech_level_estimator_.Update(info.vad_result);
+ info.input_level_dbfs = speech_level_estimator_.level_dbfs();
+ info.input_noise_level_dbfs = noise_level_estimator_.Analyze(frame);
+ info.limiter_envelope_dbfs =
+ limiter_envelope > 0 ? FloatS16ToDbfs(limiter_envelope) : -90.f;
+ info.estimate_is_confident = speech_level_estimator_.IsConfident();
+ DumpDebugData(info, *apm_data_dumper_);
+ gain_applier_.Process(info, frame);
+}
+
+void AdaptiveAgc::Reset() {
+ speech_level_estimator_.Reset();
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/adaptive_agc.h b/webrtc/modules/audio_processing/agc2/adaptive_agc.h
new file mode 100644
index 0000000..f3c7854
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/adaptive_agc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_AGC_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_AGC_H_
+
+#include "modules/audio_processing/agc2/adaptive_digital_gain_applier.h"
+#include "modules/audio_processing/agc2/adaptive_mode_level_estimator.h"
+#include "modules/audio_processing/agc2/noise_level_estimator.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+#include "modules/audio_processing/include/audio_processing.h"
+
+namespace webrtc {
+class ApmDataDumper;
+
+// Adaptive digital gain controller.
+// TODO(crbug.com/webrtc/7494): Unify with `AdaptiveDigitalGainApplier`.
+class AdaptiveAgc {
+ public:
+ explicit AdaptiveAgc(ApmDataDumper* apm_data_dumper);
+ // TODO(crbug.com/webrtc/7494): Remove ctor above.
+ AdaptiveAgc(ApmDataDumper* apm_data_dumper,
+ const AudioProcessing::Config::GainController2& config);
+ ~AdaptiveAgc();
+
+ // Analyzes `frame` and applies a digital adaptive gain to it. Takes into
+ // account the envelope measured by the limiter.
+ // TODO(crbug.com/webrtc/7494): Make the class depend on the limiter.
+ void Process(AudioFrameView<float> frame, float limiter_envelope);
+ void Reset();
+
+ private:
+ AdaptiveModeLevelEstimator speech_level_estimator_;
+ VadLevelAnalyzer vad_;
+ AdaptiveDigitalGainApplier gain_applier_;
+ ApmDataDumper* const apm_data_dumper_;
+ NoiseLevelEstimator noise_level_estimator_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_AGC_H_
diff --git a/webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc b/webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
new file mode 100644
index 0000000..36ef9be
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/adaptive_digital_gain_applier.h"
+
+#include <algorithm>
+
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_minmax.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+namespace {
+
+// This function maps input level to desired applied gain. We want to
+// boost the signal so that peaks are at -kHeadroomDbfs. We can't
+// apply more than kMaxGainDb gain.
+float ComputeGainDb(float input_level_dbfs) {
+ // If the level is very low, boost it as much as we can.
+ if (input_level_dbfs < -(kHeadroomDbfs + kMaxGainDb)) {
+ return kMaxGainDb;
+ }
+
+ // We expect to end up here most of the time: the level is below
+ // -headroom, but we can boost it to -headroom.
+ if (input_level_dbfs < -kHeadroomDbfs) {
+ return -kHeadroomDbfs - input_level_dbfs;
+ }
+
+ // Otherwise, the level is too high and we can't boost. The
+ // LevelEstimator is responsible for not reporting bogus gain
+ // values.
+ RTC_DCHECK_LE(input_level_dbfs, 0.f);
+ return 0.f;
+}
+
+// Returns `target_gain` if the output noise level is below
+// `max_output_noise_level_dbfs`; otherwise returns a capped gain so that the
+// output noise level equals `max_output_noise_level_dbfs`.
+float LimitGainByNoise(float target_gain,
+ float input_noise_level_dbfs,
+ float max_output_noise_level_dbfs,
+ ApmDataDumper& apm_data_dumper) {
+ const float noise_headroom_db =
+ max_output_noise_level_dbfs - input_noise_level_dbfs;
+ apm_data_dumper.DumpRaw("agc2_noise_headroom_db", noise_headroom_db);
+ return std::min(target_gain, std::max(noise_headroom_db, 0.f));
+}
+
+float LimitGainByLowConfidence(float target_gain,
+ float last_gain,
+ float limiter_audio_level_dbfs,
+ bool estimate_is_confident) {
+ if (estimate_is_confident ||
+ limiter_audio_level_dbfs <= kLimiterThresholdForAgcGainDbfs) {
+ return target_gain;
+ }
+ const float limiter_level_before_gain = limiter_audio_level_dbfs - last_gain;
+
+ // Compute a new gain so that limiter_level_before_gain + new_gain <=
+ // kLimiterThreshold.
+ const float new_target_gain = std::max(
+ kLimiterThresholdForAgcGainDbfs - limiter_level_before_gain, 0.f);
+ return std::min(new_target_gain, target_gain);
+}
+
+// Computes how the gain should change during this frame.
+// Return the gain difference in db to 'last_gain_db'.
+float ComputeGainChangeThisFrameDb(float target_gain_db,
+ float last_gain_db,
+ bool gain_increase_allowed,
+ float max_gain_change_db) {
+ float target_gain_difference_db = target_gain_db - last_gain_db;
+ if (!gain_increase_allowed) {
+ target_gain_difference_db = std::min(target_gain_difference_db, 0.f);
+ }
+ return rtc::SafeClamp(target_gain_difference_db, -max_gain_change_db,
+ max_gain_change_db);
+}
+
+} // namespace
+
+AdaptiveDigitalGainApplier::AdaptiveDigitalGainApplier(
+ ApmDataDumper* apm_data_dumper,
+ int adjacent_speech_frames_threshold,
+ float max_gain_change_db_per_second,
+ float max_output_noise_level_dbfs)
+ : apm_data_dumper_(apm_data_dumper),
+ gain_applier_(
+ /*hard_clip_samples=*/false,
+ /*initial_gain_factor=*/DbToRatio(kInitialAdaptiveDigitalGainDb)),
+ adjacent_speech_frames_threshold_(adjacent_speech_frames_threshold),
+ max_gain_change_db_per_10ms_(max_gain_change_db_per_second *
+ kFrameDurationMs / 1000.f),
+ max_output_noise_level_dbfs_(max_output_noise_level_dbfs),
+ calls_since_last_gain_log_(0),
+ frames_to_gain_increase_allowed_(adjacent_speech_frames_threshold_),
+ last_gain_db_(kInitialAdaptiveDigitalGainDb) {
+ RTC_DCHECK_GT(max_gain_change_db_per_second, 0.f);
+ RTC_DCHECK_GE(frames_to_gain_increase_allowed_, 1);
+ RTC_DCHECK_GE(max_output_noise_level_dbfs_, -90.f);
+ RTC_DCHECK_LE(max_output_noise_level_dbfs_, 0.f);
+}
+
+void AdaptiveDigitalGainApplier::Process(const FrameInfo& info,
+ AudioFrameView<float> frame) {
+ RTC_DCHECK_GE(info.input_level_dbfs, -150.f);
+ RTC_DCHECK_GE(frame.num_channels(), 1);
+ RTC_DCHECK(
+ frame.samples_per_channel() == 80 || frame.samples_per_channel() == 160 ||
+ frame.samples_per_channel() == 320 || frame.samples_per_channel() == 480)
+ << "`frame` does not look like a 10 ms frame for an APM supported sample "
+ "rate";
+
+ const float target_gain_db = LimitGainByLowConfidence(
+ LimitGainByNoise(ComputeGainDb(std::min(info.input_level_dbfs, 0.f)),
+ info.input_noise_level_dbfs,
+ max_output_noise_level_dbfs_, *apm_data_dumper_),
+ last_gain_db_, info.limiter_envelope_dbfs, info.estimate_is_confident);
+
+ // Forbid increasing the gain until enough adjacent speech frames are
+ // observed.
+ if (info.vad_result.speech_probability < kVadConfidenceThreshold) {
+ frames_to_gain_increase_allowed_ = adjacent_speech_frames_threshold_;
+ } else if (frames_to_gain_increase_allowed_ > 0) {
+ frames_to_gain_increase_allowed_--;
+ }
+
+ const float gain_change_this_frame_db = ComputeGainChangeThisFrameDb(
+ target_gain_db, last_gain_db_,
+ /*gain_increase_allowed=*/frames_to_gain_increase_allowed_ == 0,
+ max_gain_change_db_per_10ms_);
+
+ apm_data_dumper_->DumpRaw("agc2_want_to_change_by_db",
+ target_gain_db - last_gain_db_);
+ apm_data_dumper_->DumpRaw("agc2_will_change_by_db",
+ gain_change_this_frame_db);
+
+ // Optimization: avoid calling math functions if gain does not
+ // change.
+ if (gain_change_this_frame_db != 0.f) {
+ gain_applier_.SetGainFactor(
+ DbToRatio(last_gain_db_ + gain_change_this_frame_db));
+ }
+ gain_applier_.ApplyGain(frame);
+
+ // Remember that the gain has changed for the next iteration.
+ last_gain_db_ = last_gain_db_ + gain_change_this_frame_db;
+ apm_data_dumper_->DumpRaw("agc2_applied_gain_db", last_gain_db_);
+
+ // Log every 10 seconds.
+ calls_since_last_gain_log_++;
+ if (calls_since_last_gain_log_ == 1000) {
+ calls_since_last_gain_log_ = 0;
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc2.DigitalGainApplied",
+ last_gain_db_, 0, kMaxGainDb, kMaxGainDb + 1);
+ RTC_HISTOGRAM_COUNTS_LINEAR(
+ "WebRTC.Audio.Agc2.EstimatedSpeechPlusNoiseLevel",
+ -info.input_level_dbfs, 0, 100, 101);
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.Agc2.EstimatedNoiseLevel",
+ -info.input_noise_level_dbfs, 0, 100, 101);
+ RTC_LOG(LS_INFO) << "AGC2 adaptive digital"
+ << " | speech_plus_noise_dbfs: " << info.input_level_dbfs
+ << " | noise_dbfs: " << info.input_noise_level_dbfs
+ << " | gain_db: " << last_gain_db_;
+ }
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.h b/webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.h
new file mode 100644
index 0000000..a65379f
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/adaptive_digital_gain_applier.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_DIGITAL_GAIN_APPLIER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_DIGITAL_GAIN_APPLIER_H_
+
+#include "modules/audio_processing/agc2/gain_applier.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+
+// Part of the adaptive digital controller that applies a digital adaptive gain.
+// The gain is updated towards a target. The logic decides when gain updates are
+// allowed, it controls the adaptation speed and caps the target based on the
+// estimated noise level and the speech level estimate confidence.
+class AdaptiveDigitalGainApplier {
+ public:
+ // Information about a frame to process.
+ struct FrameInfo {
+ float input_level_dbfs; // Estimated speech plus noise level.
+ float input_noise_level_dbfs; // Estimated noise level.
+ VadLevelAnalyzer::Result vad_result;
+ float limiter_envelope_dbfs; // Envelope level from the limiter.
+ bool estimate_is_confident;
+ };
+
+ // Ctor.
+ // `adjacent_speech_frames_threshold` indicates how many speech frames are
+ // required before a gain increase is allowed. `max_gain_change_db_per_second`
+ // limits the adaptation speed (uniformly operated across frames).
+ // `max_output_noise_level_dbfs` limits the output noise level.
+ AdaptiveDigitalGainApplier(ApmDataDumper* apm_data_dumper,
+ int adjacent_speech_frames_threshold,
+ float max_gain_change_db_per_second,
+ float max_output_noise_level_dbfs);
+ AdaptiveDigitalGainApplier(const AdaptiveDigitalGainApplier&) = delete;
+ AdaptiveDigitalGainApplier& operator=(const AdaptiveDigitalGainApplier&) =
+ delete;
+
+ // Analyzes `info`, updates the digital gain and applies it to a 10 ms
+ // `frame`. Supports any sample rate supported by APM.
+ void Process(const FrameInfo& info, AudioFrameView<float> frame);
+
+ private:
+ ApmDataDumper* const apm_data_dumper_;
+ GainApplier gain_applier_;
+
+ const int adjacent_speech_frames_threshold_;
+ const float max_gain_change_db_per_10ms_;
+ const float max_output_noise_level_dbfs_;
+
+ int calls_since_last_gain_log_;
+ int frames_to_gain_increase_allowed_;
+ float last_gain_db_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_DIGITAL_GAIN_APPLIER_H_
diff --git a/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc b/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc
new file mode 100644
index 0000000..f09f63b
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/adaptive_mode_level_estimator.h"
+
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+namespace {
+
+using LevelEstimatorType =
+ AudioProcessing::Config::GainController2::LevelEstimator;
+
+// Combines a level estimation with the saturation protector margins.
+float ComputeLevelEstimateDbfs(float level_estimate_dbfs,
+ float saturation_margin_db,
+ float extra_saturation_margin_db) {
+ return rtc::SafeClamp<float>(
+ level_estimate_dbfs + saturation_margin_db + extra_saturation_margin_db,
+ -90.f, 30.f);
+}
+
+// Returns the level of given type from `vad_level`.
+float GetLevel(const VadLevelAnalyzer::Result& vad_level,
+ LevelEstimatorType type) {
+ switch (type) {
+ case LevelEstimatorType::kRms:
+ return vad_level.rms_dbfs;
+ break;
+ case LevelEstimatorType::kPeak:
+ return vad_level.peak_dbfs;
+ break;
+ }
+}
+
+} // namespace
+
+bool AdaptiveModeLevelEstimator::LevelEstimatorState::operator==(
+ const AdaptiveModeLevelEstimator::LevelEstimatorState& b) const {
+ return time_to_full_buffer_ms == b.time_to_full_buffer_ms &&
+ level_dbfs.numerator == b.level_dbfs.numerator &&
+ level_dbfs.denominator == b.level_dbfs.denominator &&
+ saturation_protector == b.saturation_protector;
+}
+
+float AdaptiveModeLevelEstimator::LevelEstimatorState::Ratio::GetRatio() const {
+ RTC_DCHECK_NE(denominator, 0.f);
+ return numerator / denominator;
+}
+
+AdaptiveModeLevelEstimator::AdaptiveModeLevelEstimator(
+ ApmDataDumper* apm_data_dumper)
+ : AdaptiveModeLevelEstimator(
+ apm_data_dumper,
+ AudioProcessing::Config::GainController2::LevelEstimator::kRms,
+ kDefaultLevelEstimatorAdjacentSpeechFramesThreshold,
+ kDefaultInitialSaturationMarginDb,
+ kDefaultExtraSaturationMarginDb) {}
+
+AdaptiveModeLevelEstimator::AdaptiveModeLevelEstimator(
+ ApmDataDumper* apm_data_dumper,
+ AudioProcessing::Config::GainController2::LevelEstimator level_estimator,
+ int adjacent_speech_frames_threshold,
+ float initial_saturation_margin_db,
+ float extra_saturation_margin_db)
+ : apm_data_dumper_(apm_data_dumper),
+ level_estimator_type_(level_estimator),
+ adjacent_speech_frames_threshold_(adjacent_speech_frames_threshold),
+ initial_saturation_margin_db_(initial_saturation_margin_db),
+ extra_saturation_margin_db_(extra_saturation_margin_db),
+ level_dbfs_(ComputeLevelEstimateDbfs(kInitialSpeechLevelEstimateDbfs,
+ initial_saturation_margin_db_,
+ extra_saturation_margin_db_)) {
+ RTC_DCHECK(apm_data_dumper_);
+ RTC_DCHECK_GE(adjacent_speech_frames_threshold_, 1);
+ Reset();
+}
+
+void AdaptiveModeLevelEstimator::Update(
+ const VadLevelAnalyzer::Result& vad_level) {
+ RTC_DCHECK_GT(vad_level.rms_dbfs, -150.f);
+ RTC_DCHECK_LT(vad_level.rms_dbfs, 50.f);
+ RTC_DCHECK_GT(vad_level.peak_dbfs, -150.f);
+ RTC_DCHECK_LT(vad_level.peak_dbfs, 50.f);
+ RTC_DCHECK_GE(vad_level.speech_probability, 0.f);
+ RTC_DCHECK_LE(vad_level.speech_probability, 1.f);
+ DumpDebugData();
+
+ if (vad_level.speech_probability < kVadConfidenceThreshold) {
+ // Not a speech frame.
+ if (adjacent_speech_frames_threshold_ > 1) {
+ // When two or more adjacent speech frames are required in order to update
+ // the state, we need to decide whether to discard or confirm the updates
+ // based on the speech sequence length.
+ if (num_adjacent_speech_frames_ >= adjacent_speech_frames_threshold_) {
+ // First non-speech frame after a long enough sequence of speech frames.
+ // Update the reliable state.
+ reliable_state_ = preliminary_state_;
+ } else if (num_adjacent_speech_frames_ > 0) {
+ // First non-speech frame after a too short sequence of speech frames.
+ // Reset to the last reliable state.
+ preliminary_state_ = reliable_state_;
+ }
+ }
+ num_adjacent_speech_frames_ = 0;
+ return;
+ }
+
+ // Speech frame observed.
+ num_adjacent_speech_frames_++;
+
+ // Update preliminary level estimate.
+ RTC_DCHECK_GE(preliminary_state_.time_to_full_buffer_ms, 0);
+ const bool buffer_is_full = preliminary_state_.time_to_full_buffer_ms == 0;
+ if (!buffer_is_full) {
+ preliminary_state_.time_to_full_buffer_ms -= kFrameDurationMs;
+ }
+ // Weighted average of levels with speech probability as weight.
+ RTC_DCHECK_GT(vad_level.speech_probability, 0.f);
+ const float leak_factor = buffer_is_full ? kFullBufferLeakFactor : 1.f;
+ preliminary_state_.level_dbfs.numerator =
+ preliminary_state_.level_dbfs.numerator * leak_factor +
+ GetLevel(vad_level, level_estimator_type_) * vad_level.speech_probability;
+ preliminary_state_.level_dbfs.denominator =
+ preliminary_state_.level_dbfs.denominator * leak_factor +
+ vad_level.speech_probability;
+
+ const float level_dbfs = preliminary_state_.level_dbfs.GetRatio();
+
+ UpdateSaturationProtectorState(vad_level.peak_dbfs, level_dbfs,
+ preliminary_state_.saturation_protector);
+
+ if (num_adjacent_speech_frames_ >= adjacent_speech_frames_threshold_) {
+ // `preliminary_state_` is now reliable. Update the last level estimation.
+ level_dbfs_ = ComputeLevelEstimateDbfs(
+ level_dbfs, preliminary_state_.saturation_protector.margin_db,
+ extra_saturation_margin_db_);
+ }
+}
+
+bool AdaptiveModeLevelEstimator::IsConfident() const {
+ if (adjacent_speech_frames_threshold_ == 1) {
+ // Ignore `reliable_state_` when a single frame is enough to update the
+ // level estimate (because it is not used).
+ return preliminary_state_.time_to_full_buffer_ms == 0;
+ }
+ // Once confident, it remains confident.
+ RTC_DCHECK(reliable_state_.time_to_full_buffer_ms != 0 ||
+ preliminary_state_.time_to_full_buffer_ms == 0);
+ // During the first long enough speech sequence, `reliable_state_` must be
+ // ignored since `preliminary_state_` is used.
+ return reliable_state_.time_to_full_buffer_ms == 0 ||
+ (num_adjacent_speech_frames_ >= adjacent_speech_frames_threshold_ &&
+ preliminary_state_.time_to_full_buffer_ms == 0);
+}
+
+void AdaptiveModeLevelEstimator::Reset() {
+ ResetLevelEstimatorState(preliminary_state_);
+ ResetLevelEstimatorState(reliable_state_);
+ level_dbfs_ = ComputeLevelEstimateDbfs(kInitialSpeechLevelEstimateDbfs,
+ initial_saturation_margin_db_,
+ extra_saturation_margin_db_);
+ num_adjacent_speech_frames_ = 0;
+}
+
+void AdaptiveModeLevelEstimator::ResetLevelEstimatorState(
+ LevelEstimatorState& state) const {
+ state.time_to_full_buffer_ms = kFullBufferSizeMs;
+ state.level_dbfs.numerator = 0.f;
+ state.level_dbfs.denominator = 0.f;
+ ResetSaturationProtectorState(initial_saturation_margin_db_,
+ state.saturation_protector);
+}
+
+void AdaptiveModeLevelEstimator::DumpDebugData() const {
+ apm_data_dumper_->DumpRaw("agc2_adaptive_level_estimate_dbfs", level_dbfs_);
+ apm_data_dumper_->DumpRaw("agc2_adaptive_num_adjacent_speech_frames_",
+ num_adjacent_speech_frames_);
+ apm_data_dumper_->DumpRaw("agc2_adaptive_preliminary_level_estimate_num",
+ preliminary_state_.level_dbfs.numerator);
+ apm_data_dumper_->DumpRaw("agc2_adaptive_preliminary_level_estimate_den",
+ preliminary_state_.level_dbfs.denominator);
+ apm_data_dumper_->DumpRaw("agc2_adaptive_preliminary_saturation_margin_db",
+ preliminary_state_.saturation_protector.margin_db);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.h b/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.h
new file mode 100644
index 0000000..213fc0f
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_H_
+
+#include <stddef.h>
+#include <type_traits>
+
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/agc2/saturation_protector.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
+#include "modules/audio_processing/include/audio_processing.h"
+
+namespace webrtc {
+class ApmDataDumper;
+
+// Level estimator for the digital adaptive gain controller.
+class AdaptiveModeLevelEstimator {
+ public:
+ explicit AdaptiveModeLevelEstimator(ApmDataDumper* apm_data_dumper);
+ AdaptiveModeLevelEstimator(const AdaptiveModeLevelEstimator&) = delete;
+ AdaptiveModeLevelEstimator& operator=(const AdaptiveModeLevelEstimator&) =
+ delete;
+ AdaptiveModeLevelEstimator(
+ ApmDataDumper* apm_data_dumper,
+ AudioProcessing::Config::GainController2::LevelEstimator level_estimator,
+ int adjacent_speech_frames_threshold,
+ float initial_saturation_margin_db,
+ float extra_saturation_margin_db);
+
+ // Updates the level estimation.
+ void Update(const VadLevelAnalyzer::Result& vad_data);
+ // Returns the estimated speech plus noise level.
+ float level_dbfs() const { return level_dbfs_; }
+ // Returns true if the estimator is confident on its current estimate.
+ bool IsConfident() const;
+
+ void Reset();
+
+ private:
+ // Part of the level estimator state used for check-pointing and restore ops.
+ struct LevelEstimatorState {
+ bool operator==(const LevelEstimatorState& s) const;
+ inline bool operator!=(const LevelEstimatorState& s) const {
+ return !(*this == s);
+ }
+ struct Ratio {
+ float numerator;
+ float denominator;
+ float GetRatio() const;
+ };
+ // TODO(crbug.com/webrtc/7494): Remove time_to_full_buffer_ms if redundant.
+ int time_to_full_buffer_ms;
+ Ratio level_dbfs;
+ SaturationProtectorState saturation_protector;
+ };
+ static_assert(std::is_trivially_copyable<LevelEstimatorState>::value, "");
+
+ void ResetLevelEstimatorState(LevelEstimatorState& state) const;
+
+ void DumpDebugData() const;
+
+ ApmDataDumper* const apm_data_dumper_;
+
+ const AudioProcessing::Config::GainController2::LevelEstimator
+ level_estimator_type_;
+ const int adjacent_speech_frames_threshold_;
+ const float initial_saturation_margin_db_;
+ const float extra_saturation_margin_db_;
+ LevelEstimatorState preliminary_state_;
+ LevelEstimatorState reliable_state_;
+ float level_dbfs_;
+ int num_adjacent_speech_frames_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc b/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc
new file mode 100644
index 0000000..5ceeb7d
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h"
+
+#include <cmath>
+#include <vector>
+
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+
+namespace webrtc {
+
+AdaptiveModeLevelEstimatorAgc::AdaptiveModeLevelEstimatorAgc(
+ ApmDataDumper* apm_data_dumper)
+ : level_estimator_(apm_data_dumper) {
+ set_target_level_dbfs(kDefaultAgc2LevelHeadroomDbfs);
+}
+
+// |audio| must be mono; in a multi-channel stream, provide the first (usually
+// left) channel.
+void AdaptiveModeLevelEstimatorAgc::Process(const int16_t* audio,
+ size_t length,
+ int sample_rate_hz) {
+ std::vector<float> float_audio_frame(audio, audio + length);
+ const float* const first_channel = &float_audio_frame[0];
+ AudioFrameView<const float> frame_view(&first_channel, 1 /* num channels */,
+ length);
+ const auto vad_prob = agc2_vad_.AnalyzeFrame(frame_view);
+ latest_voice_probability_ = vad_prob.speech_probability;
+ if (latest_voice_probability_ > kVadConfidenceThreshold) {
+ time_in_ms_since_last_estimate_ += kFrameDurationMs;
+ }
+ level_estimator_.Update(vad_prob);
+}
+
+// Retrieves the difference between the target RMS level and the current
+// signal RMS level in dB. Returns true if an update is available and false
+// otherwise, in which case |error| should be ignored and no action taken.
+bool AdaptiveModeLevelEstimatorAgc::GetRmsErrorDb(int* error) {
+ if (time_in_ms_since_last_estimate_ <= kTimeUntilConfidentMs) {
+ return false;
+ }
+ *error =
+ std::floor(target_level_dbfs() - level_estimator_.level_dbfs() + 0.5f);
+ time_in_ms_since_last_estimate_ = 0;
+ return true;
+}
+
+void AdaptiveModeLevelEstimatorAgc::Reset() {
+ level_estimator_.Reset();
+}
+
+float AdaptiveModeLevelEstimatorAgc::voice_probability() const {
+ return latest_voice_probability_;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h b/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h
new file mode 100644
index 0000000..bc6fa84
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "modules/audio_processing/agc/agc.h"
+#include "modules/audio_processing/agc2/adaptive_mode_level_estimator.h"
+#include "modules/audio_processing/agc2/saturation_protector.h"
+#include "modules/audio_processing/agc2/vad_with_level.h"
+
+namespace webrtc {
+class AdaptiveModeLevelEstimatorAgc : public Agc {
+ public:
+ explicit AdaptiveModeLevelEstimatorAgc(ApmDataDumper* apm_data_dumper);
+
+ // |audio| must be mono; in a multi-channel stream, provide the first (usually
+ // left) channel.
+ void Process(const int16_t* audio,
+ size_t length,
+ int sample_rate_hz) override;
+
+ // Retrieves the difference between the target RMS level and the current
+ // signal RMS level in dB. Returns true if an update is available and false
+ // otherwise, in which case |error| should be ignored and no action taken.
+ bool GetRmsErrorDb(int* error) override;
+ void Reset() override;
+
+ float voice_probability() const override;
+
+ private:
+ static constexpr int kTimeUntilConfidentMs = 700;
+ static constexpr int kDefaultAgc2LevelHeadroomDbfs = -1;
+ int32_t time_in_ms_since_last_estimate_ = 0;
+ AdaptiveModeLevelEstimator level_estimator_;
+ VadLevelAnalyzer agc2_vad_;
+ float latest_voice_probability_ = 0.f;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_ADAPTIVE_MODE_LEVEL_ESTIMATOR_AGC_H_
diff --git a/webrtc/modules/audio_processing/agc2/agc2_common.h b/webrtc/modules/audio_processing/agc2/agc2_common.h
new file mode 100644
index 0000000..5d01100
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/agc2_common.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_AGC2_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_AGC2_COMMON_H_
+
+#include <stddef.h>
+
+namespace webrtc {
+
+constexpr float kMinFloatS16Value = -32768.f;
+constexpr float kMaxFloatS16Value = 32767.f;
+constexpr float kMaxAbsFloatS16Value = 32768.0f;
+
+constexpr size_t kFrameDurationMs = 10;
+constexpr size_t kSubFramesInFrame = 20;
+constexpr size_t kMaximalNumberOfSamplesPerChannel = 480;
+
+constexpr float kAttackFilterConstant = 0.f;
+
+// Adaptive digital gain applier settings below.
+constexpr float kHeadroomDbfs = 1.f;
+constexpr float kMaxGainDb = 30.f;
+constexpr float kInitialAdaptiveDigitalGainDb = 8.f;
+// At what limiter levels should we start decreasing the adaptive digital gain.
+constexpr float kLimiterThresholdForAgcGainDbfs = -kHeadroomDbfs;
+
+// This is the threshold for speech. Speech frames are used for updating the
+// speech level, measuring the amount of speech, and decide when to allow target
+// gain reduction.
+constexpr float kVadConfidenceThreshold = 0.9f;
+
+// The amount of 'memory' of the Level Estimator. Decides leak factors.
+constexpr size_t kFullBufferSizeMs = 1200;
+constexpr float kFullBufferLeakFactor = 1.f - 1.f / kFullBufferSizeMs;
+
+constexpr float kInitialSpeechLevelEstimateDbfs = -30.f;
+
+// Robust VAD probability and speech decisions.
+constexpr float kDefaultSmoothedVadProbabilityAttack = 1.f;
+constexpr int kDefaultLevelEstimatorAdjacentSpeechFramesThreshold = 1;
+
+// Saturation Protector settings.
+constexpr float kDefaultInitialSaturationMarginDb = 20.f;
+constexpr float kDefaultExtraSaturationMarginDb = 2.f;
+
+constexpr size_t kPeakEnveloperSuperFrameLengthMs = 400;
+static_assert(kFullBufferSizeMs % kPeakEnveloperSuperFrameLengthMs == 0,
+ "Full buffer size should be a multiple of super frame length for "
+ "optimal Saturation Protector performance.");
+
+constexpr size_t kPeakEnveloperBufferSize =
+ kFullBufferSizeMs / kPeakEnveloperSuperFrameLengthMs + 1;
+
+// This value is 10 ** (-1/20 * frame_size_ms / satproc_attack_ms),
+// where satproc_attack_ms is 5000.
+constexpr float kSaturationProtectorAttackConstant = 0.9988493699365052f;
+
+// This value is 10 ** (-1/20 * frame_size_ms / satproc_decay_ms),
+// where satproc_decay_ms is 1000.
+constexpr float kSaturationProtectorDecayConstant = 0.9997697679981565f;
+
+// This is computed from kDecayMs by
+// 10 ** (-1/20 * subframe_duration / kDecayMs).
+// |subframe_duration| is |kFrameDurationMs / kSubFramesInFrame|.
+// kDecayMs is defined in agc2_testing_common.h
+constexpr float kDecayFilterConstant = 0.9998848773724686f;
+
+// Number of interpolation points for each region of the limiter.
+// These values have been tuned to limit the interpolated gain curve error given
+// the limiter parameters and allowing a maximum error of +/- 32768^-1.
+constexpr size_t kInterpolatedGainCurveKneePoints = 22;
+constexpr size_t kInterpolatedGainCurveBeyondKneePoints = 10;
+constexpr size_t kInterpolatedGainCurveTotalPoints =
+ kInterpolatedGainCurveKneePoints + kInterpolatedGainCurveBeyondKneePoints;
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_AGC2_COMMON_H_
diff --git a/webrtc/modules/audio_processing/agc2/agc2_testing_common.cc b/webrtc/modules/audio_processing/agc2/agc2_testing_common.cc
new file mode 100644
index 0000000..6c22492
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/agc2_testing_common.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/agc2_testing_common.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace test {
+
+std::vector<double> LinSpace(const double l,
+ const double r,
+ size_t num_points) {
+ RTC_CHECK(num_points >= 2);
+ std::vector<double> points(num_points);
+ const double step = (r - l) / (num_points - 1.0);
+ points[0] = l;
+ for (size_t i = 1; i < num_points - 1; i++) {
+ points[i] = static_cast<double>(l) + i * step;
+ }
+ points[num_points - 1] = r;
+ return points;
+}
+} // namespace test
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/agc2_testing_common.h b/webrtc/modules/audio_processing/agc2/agc2_testing_common.h
new file mode 100644
index 0000000..7bfadbb
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/agc2_testing_common.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_AGC2_TESTING_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_AGC2_TESTING_COMMON_H_
+
+#include <math.h>
+
+#include <limits>
+#include <vector>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace test {
+
+// Level Estimator test parameters.
+constexpr float kDecayMs = 500.f;
+
+// Limiter parameters.
+constexpr float kLimiterMaxInputLevelDbFs = 1.f;
+constexpr float kLimiterKneeSmoothnessDb = 1.f;
+constexpr float kLimiterCompressionRatio = 5.f;
+constexpr float kPi = 3.1415926536f;
+
+std::vector<double> LinSpace(const double l, const double r, size_t num_points);
+
+class SineGenerator {
+ public:
+ SineGenerator(float frequency, int rate)
+ : frequency_(frequency), rate_(rate) {}
+ float operator()() {
+ x_radians_ += frequency_ / rate_ * 2 * kPi;
+ if (x_radians_ > 2 * kPi) {
+ x_radians_ -= 2 * kPi;
+ }
+ return 1000.f * sinf(x_radians_);
+ }
+
+ private:
+ float frequency_;
+ int rate_;
+ float x_radians_ = 0.f;
+};
+
+class PulseGenerator {
+ public:
+ PulseGenerator(float frequency, int rate)
+ : samples_period_(
+ static_cast<int>(static_cast<float>(rate) / frequency)) {
+ RTC_DCHECK_GT(rate, frequency);
+ }
+ float operator()() {
+ sample_counter_++;
+ if (sample_counter_ >= samples_period_) {
+ sample_counter_ -= samples_period_;
+ }
+ return static_cast<float>(
+ sample_counter_ == 0 ? std::numeric_limits<int16_t>::max() : 10.f);
+ }
+
+ private:
+ int samples_period_;
+ int sample_counter_ = 0;
+};
+
+} // namespace test
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_AGC2_TESTING_COMMON_H_
diff --git a/webrtc/modules/audio_processing/agc2/biquad_filter.cc b/webrtc/modules/audio_processing/agc2/biquad_filter.cc
new file mode 100644
index 0000000..da8557c
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/biquad_filter.cc
@@ -0,0 +1,36 @@
+/*
+ * 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/audio_processing/agc2/biquad_filter.h"
+
+#include <stddef.h>
+
+namespace webrtc {
+
+// Transposed direct form I implementation of a bi-quad filter applied to an
+// input signal |x| to produce an output signal |y|.
+void BiQuadFilter::Process(rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> y) {
+ for (size_t k = 0; k < x.size(); ++k) {
+ // Use temporary variable for x[k] to allow in-place function call
+ // (that x and y refer to the same array).
+ const float tmp = x[k];
+ y[k] = coefficients_.b[0] * tmp + coefficients_.b[1] * biquad_state_.b[0] +
+ coefficients_.b[2] * biquad_state_.b[1] -
+ coefficients_.a[0] * biquad_state_.a[0] -
+ coefficients_.a[1] * biquad_state_.a[1];
+ biquad_state_.b[1] = biquad_state_.b[0];
+ biquad_state_.b[0] = tmp;
+ biquad_state_.a[1] = biquad_state_.a[0];
+ biquad_state_.a[0] = y[k];
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/biquad_filter.h b/webrtc/modules/audio_processing/agc2/biquad_filter.h
new file mode 100644
index 0000000..7bf3301
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/biquad_filter.h
@@ -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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_BIQUAD_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_BIQUAD_FILTER_H_
+
+#include <algorithm>
+
+#include "api/array_view.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class BiQuadFilter {
+ public:
+ // Normalized filter coefficients.
+ // b_0 + b_1 • z^(-1) + b_2 • z^(-2)
+ // H(z) = ---------------------------------
+ // 1 + a_1 • z^(-1) + a_2 • z^(-2)
+ struct BiQuadCoefficients {
+ float b[3];
+ float a[2];
+ };
+
+ BiQuadFilter() = default;
+
+ void Initialize(const BiQuadCoefficients& coefficients) {
+ coefficients_ = coefficients;
+ }
+
+ void Reset() { biquad_state_.Reset(); }
+
+ // Produces a filtered output y of the input x. Both x and y need to
+ // have the same length. In-place modification is allowed.
+ void Process(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
+
+ private:
+ struct BiQuadState {
+ BiQuadState() { Reset(); }
+
+ void Reset() {
+ std::fill(b, b + arraysize(b), 0.f);
+ std::fill(a, a + arraysize(a), 0.f);
+ }
+
+ float b[2];
+ float a[2];
+ };
+
+ BiQuadState biquad_state_;
+ BiQuadCoefficients coefficients_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(BiQuadFilter);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_BIQUAD_FILTER_H_
diff --git a/webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc b/webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc
new file mode 100644
index 0000000..bc92613
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/compute_interpolated_gain_curve.h"
+
+#include <algorithm>
+#include <cmath>
+#include <queue>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/agc2/agc2_testing_common.h"
+#include "modules/audio_processing/agc2/limiter_db_gain_curve.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+std::pair<double, double> ComputeLinearApproximationParams(
+ const LimiterDbGainCurve* limiter,
+ const double x) {
+ const double m = limiter->GetGainFirstDerivativeLinear(x);
+ const double q = limiter->GetGainLinear(x) - m * x;
+ return {m, q};
+}
+
+double ComputeAreaUnderPiecewiseLinearApproximation(
+ const LimiterDbGainCurve* limiter,
+ const double x0,
+ const double x1) {
+ RTC_CHECK_LT(x0, x1);
+
+ // Linear approximation in x0 and x1.
+ double m0, q0, m1, q1;
+ std::tie(m0, q0) = ComputeLinearApproximationParams(limiter, x0);
+ std::tie(m1, q1) = ComputeLinearApproximationParams(limiter, x1);
+
+ // Intersection point between two adjacent linear pieces.
+ RTC_CHECK_NE(m1, m0);
+ const double x_split = (q0 - q1) / (m1 - m0);
+ RTC_CHECK_LT(x0, x_split);
+ RTC_CHECK_LT(x_split, x1);
+
+ auto area_under_linear_piece = [](double x_l, double x_r, double m,
+ double q) {
+ return x_r * (m * x_r / 2.0 + q) - x_l * (m * x_l / 2.0 + q);
+ };
+ return area_under_linear_piece(x0, x_split, m0, q0) +
+ area_under_linear_piece(x_split, x1, m1, q1);
+}
+
+// Computes the approximation error in the limiter region for a given interval.
+// The error is computed as the difference between the areas beneath the limiter
+// curve to approximate and its linear under-approximation.
+double LimiterUnderApproximationNegativeError(const LimiterDbGainCurve* limiter,
+ const double x0,
+ const double x1) {
+ const double area_limiter = limiter->GetGainIntegralLinear(x0, x1);
+ const double area_interpolated_curve =
+ ComputeAreaUnderPiecewiseLinearApproximation(limiter, x0, x1);
+ RTC_CHECK_GE(area_limiter, area_interpolated_curve);
+ return area_limiter - area_interpolated_curve;
+}
+
+// Automatically finds where to sample the beyond-knee region of a limiter using
+// a greedy optimization algorithm that iteratively decreases the approximation
+// error.
+// The solution is sub-optimal because the algorithm is greedy and the points
+// are assigned by halving intervals (starting with the whole beyond-knee region
+// as a single interval). However, even if sub-optimal, this algorithm works
+// well in practice and it is efficiently implemented using priority queues.
+std::vector<double> SampleLimiterRegion(const LimiterDbGainCurve* limiter) {
+ static_assert(kInterpolatedGainCurveBeyondKneePoints > 2, "");
+
+ struct Interval {
+ Interval() = default; // Ctor required by std::priority_queue.
+ Interval(double l, double r, double e) : x0(l), x1(r), error(e) {
+ RTC_CHECK(x0 < x1);
+ }
+ bool operator<(const Interval& other) const { return error < other.error; }
+
+ double x0;
+ double x1;
+ double error;
+ };
+
+ std::priority_queue<Interval, std::vector<Interval>> q;
+ q.emplace(limiter->limiter_start_linear(), limiter->max_input_level_linear(),
+ LimiterUnderApproximationNegativeError(
+ limiter, limiter->limiter_start_linear(),
+ limiter->max_input_level_linear()));
+
+ // Iteratively find points by halving the interval with greatest error.
+ while (q.size() < kInterpolatedGainCurveBeyondKneePoints) {
+ // Get the interval with highest error.
+ const auto interval = q.top();
+ q.pop();
+
+ // Split |interval| and enqueue.
+ double x_split = (interval.x0 + interval.x1) / 2.0;
+ q.emplace(interval.x0, x_split,
+ LimiterUnderApproximationNegativeError(limiter, interval.x0,
+ x_split)); // Left.
+ q.emplace(x_split, interval.x1,
+ LimiterUnderApproximationNegativeError(limiter, x_split,
+ interval.x1)); // Right.
+ }
+
+ // Copy x1 values and sort them.
+ RTC_CHECK_EQ(q.size(), kInterpolatedGainCurveBeyondKneePoints);
+ std::vector<double> samples(kInterpolatedGainCurveBeyondKneePoints);
+ for (size_t i = 0; i < kInterpolatedGainCurveBeyondKneePoints; ++i) {
+ const auto interval = q.top();
+ q.pop();
+ samples[i] = interval.x1;
+ }
+ RTC_CHECK(q.empty());
+ std::sort(samples.begin(), samples.end());
+
+ return samples;
+}
+
+// Compute the parameters to over-approximate the knee region via linear
+// interpolation. Over-approximating is saturation-safe since the knee region is
+// convex.
+void PrecomputeKneeApproxParams(const LimiterDbGainCurve* limiter,
+ test::InterpolatedParameters* parameters) {
+ static_assert(kInterpolatedGainCurveKneePoints > 2, "");
+ // Get |kInterpolatedGainCurveKneePoints| - 1 equally spaced points.
+ const std::vector<double> points = test::LinSpace(
+ limiter->knee_start_linear(), limiter->limiter_start_linear(),
+ kInterpolatedGainCurveKneePoints - 1);
+
+ // Set the first two points. The second is computed to help with the beginning
+ // of the knee region, which has high curvature.
+ parameters->computed_approximation_params_x[0] = points[0];
+ parameters->computed_approximation_params_x[1] =
+ (points[0] + points[1]) / 2.0;
+ // Copy the remaining points.
+ std::copy(std::begin(points) + 1, std::end(points),
+ std::begin(parameters->computed_approximation_params_x) + 2);
+
+ // Compute (m, q) pairs for each linear piece y = mx + q.
+ for (size_t i = 0; i < kInterpolatedGainCurveKneePoints - 1; ++i) {
+ const double x0 = parameters->computed_approximation_params_x[i];
+ const double x1 = parameters->computed_approximation_params_x[i + 1];
+ const double y0 = limiter->GetGainLinear(x0);
+ const double y1 = limiter->GetGainLinear(x1);
+ RTC_CHECK_NE(x1, x0);
+ parameters->computed_approximation_params_m[i] = (y1 - y0) / (x1 - x0);
+ parameters->computed_approximation_params_q[i] =
+ y0 - parameters->computed_approximation_params_m[i] * x0;
+ }
+}
+
+// Compute the parameters to under-approximate the beyond-knee region via linear
+// interpolation and greedy sampling. Under-approximating is saturation-safe
+// since the beyond-knee region is concave.
+void PrecomputeBeyondKneeApproxParams(
+ const LimiterDbGainCurve* limiter,
+ test::InterpolatedParameters* parameters) {
+ // Find points on which the linear pieces are tangent to the gain curve.
+ const auto samples = SampleLimiterRegion(limiter);
+
+ // Parametrize each linear piece.
+ double m, q;
+ std::tie(m, q) = ComputeLinearApproximationParams(
+ limiter,
+ parameters
+ ->computed_approximation_params_x[kInterpolatedGainCurveKneePoints -
+ 1]);
+ parameters
+ ->computed_approximation_params_m[kInterpolatedGainCurveKneePoints - 1] =
+ m;
+ parameters
+ ->computed_approximation_params_q[kInterpolatedGainCurveKneePoints - 1] =
+ q;
+ for (size_t i = 0; i < samples.size(); ++i) {
+ std::tie(m, q) = ComputeLinearApproximationParams(limiter, samples[i]);
+ parameters
+ ->computed_approximation_params_m[i +
+ kInterpolatedGainCurveKneePoints] = m;
+ parameters
+ ->computed_approximation_params_q[i +
+ kInterpolatedGainCurveKneePoints] = q;
+ }
+
+ // Find the point of intersection between adjacent linear pieces. They will be
+ // used as boundaries between adjacent linear pieces.
+ for (size_t i = kInterpolatedGainCurveKneePoints;
+ i < kInterpolatedGainCurveKneePoints +
+ kInterpolatedGainCurveBeyondKneePoints;
+ ++i) {
+ RTC_CHECK_NE(parameters->computed_approximation_params_m[i],
+ parameters->computed_approximation_params_m[i - 1]);
+ parameters->computed_approximation_params_x[i] =
+ ( // Formula: (q0 - q1) / (m1 - m0).
+ parameters->computed_approximation_params_q[i - 1] -
+ parameters->computed_approximation_params_q[i]) /
+ (parameters->computed_approximation_params_m[i] -
+ parameters->computed_approximation_params_m[i - 1]);
+ }
+}
+
+} // namespace
+
+namespace test {
+
+InterpolatedParameters ComputeInterpolatedGainCurveApproximationParams() {
+ InterpolatedParameters parameters;
+ LimiterDbGainCurve limiter;
+ parameters.computed_approximation_params_x.fill(0.0f);
+ parameters.computed_approximation_params_m.fill(0.0f);
+ parameters.computed_approximation_params_q.fill(0.0f);
+ PrecomputeKneeApproxParams(&limiter, &parameters);
+ PrecomputeBeyondKneeApproxParams(&limiter, &parameters);
+ return parameters;
+}
+} // namespace test
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.h b/webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.h
new file mode 100644
index 0000000..5f52441
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/compute_interpolated_gain_curve.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_COMPUTE_INTERPOLATED_GAIN_CURVE_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_COMPUTE_INTERPOLATED_GAIN_CURVE_H_
+
+#include <array>
+
+#include "modules/audio_processing/agc2/agc2_common.h"
+
+namespace webrtc {
+
+namespace test {
+
+// Parameters for interpolated gain curve using under-approximation to
+// avoid saturation.
+//
+// The saturation gain is defined in order to let hard-clipping occur for
+// those samples having a level that falls in the saturation region. It is an
+// upper bound of the actual gain to apply - i.e., that returned by the
+// limiter.
+
+// Knee and beyond-knee regions approximation parameters.
+// The gain curve is approximated as a piece-wise linear function.
+// |approx_params_x_| are the boundaries between adjacent linear pieces,
+// |approx_params_m_| and |approx_params_q_| are the slope and the y-intercept
+// values of each piece.
+struct InterpolatedParameters {
+ std::array<float, kInterpolatedGainCurveTotalPoints>
+ computed_approximation_params_x;
+ std::array<float, kInterpolatedGainCurveTotalPoints>
+ computed_approximation_params_m;
+ std::array<float, kInterpolatedGainCurveTotalPoints>
+ computed_approximation_params_q;
+};
+
+InterpolatedParameters ComputeInterpolatedGainCurveApproximationParams();
+} // namespace test
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_COMPUTE_INTERPOLATED_GAIN_CURVE_H_
diff --git a/webrtc/modules/audio_processing/agc2/down_sampler.cc b/webrtc/modules/audio_processing/agc2/down_sampler.cc
new file mode 100644
index 0000000..654ed4b
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/down_sampler.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/audio_processing/agc2/down_sampler.h"
+
+#include <string.h>
+
+#include <algorithm>
+
+#include "modules/audio_processing/agc2/biquad_filter.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+constexpr int kChunkSizeMs = 10;
+constexpr int kSampleRate8kHz = 8000;
+constexpr int kSampleRate16kHz = 16000;
+constexpr int kSampleRate32kHz = 32000;
+constexpr int kSampleRate48kHz = 48000;
+
+// Bandlimiter coefficients computed based on that only
+// the first 40 bins of the spectrum for the downsampled
+// signal are used.
+// [B,A] = butter(2,(41/64*4000)/8000)
+const BiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients_16kHz = {
+ {0.1455f, 0.2911f, 0.1455f},
+ {-0.6698f, 0.2520f}};
+
+// [B,A] = butter(2,(41/64*4000)/16000)
+const BiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients_32kHz = {
+ {0.0462f, 0.0924f, 0.0462f},
+ {-1.3066f, 0.4915f}};
+
+// [B,A] = butter(2,(41/64*4000)/24000)
+const BiQuadFilter::BiQuadCoefficients kLowPassFilterCoefficients_48kHz = {
+ {0.0226f, 0.0452f, 0.0226f},
+ {-1.5320f, 0.6224f}};
+
+} // namespace
+
+DownSampler::DownSampler(ApmDataDumper* data_dumper)
+ : data_dumper_(data_dumper) {
+ Initialize(48000);
+}
+void DownSampler::Initialize(int sample_rate_hz) {
+ RTC_DCHECK(
+ sample_rate_hz == kSampleRate8kHz || sample_rate_hz == kSampleRate16kHz ||
+ sample_rate_hz == kSampleRate32kHz || sample_rate_hz == kSampleRate48kHz);
+
+ sample_rate_hz_ = sample_rate_hz;
+ down_sampling_factor_ = rtc::CheckedDivExact(sample_rate_hz_, 8000);
+
+ /// Note that the down sampling filter is not used if the sample rate is 8
+ /// kHz.
+ if (sample_rate_hz_ == kSampleRate16kHz) {
+ low_pass_filter_.Initialize(kLowPassFilterCoefficients_16kHz);
+ } else if (sample_rate_hz_ == kSampleRate32kHz) {
+ low_pass_filter_.Initialize(kLowPassFilterCoefficients_32kHz);
+ } else if (sample_rate_hz_ == kSampleRate48kHz) {
+ low_pass_filter_.Initialize(kLowPassFilterCoefficients_48kHz);
+ }
+}
+
+void DownSampler::DownSample(rtc::ArrayView<const float> in,
+ rtc::ArrayView<float> out) {
+ data_dumper_->DumpWav("lc_down_sampler_input", in, sample_rate_hz_, 1);
+ RTC_DCHECK_EQ(sample_rate_hz_ * kChunkSizeMs / 1000, in.size());
+ RTC_DCHECK_EQ(kSampleRate8kHz * kChunkSizeMs / 1000, out.size());
+ const size_t kMaxNumFrames = kSampleRate48kHz * kChunkSizeMs / 1000;
+ float x[kMaxNumFrames];
+
+ // Band-limit the signal to 4 kHz.
+ if (sample_rate_hz_ != kSampleRate8kHz) {
+ low_pass_filter_.Process(in, rtc::ArrayView<float>(x, in.size()));
+
+ // Downsample the signal.
+ size_t k = 0;
+ for (size_t j = 0; j < out.size(); ++j) {
+ RTC_DCHECK_GT(kMaxNumFrames, k);
+ out[j] = x[k];
+ k += down_sampling_factor_;
+ }
+ } else {
+ std::copy(in.data(), in.data() + in.size(), out.data());
+ }
+
+ data_dumper_->DumpWav("lc_down_sampler_output", out, kSampleRate8kHz, 1);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/down_sampler.h b/webrtc/modules/audio_processing/agc2/down_sampler.h
new file mode 100644
index 0000000..be7cbb3
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/down_sampler.h
@@ -0,0 +1,42 @@
+/*
+ * 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_AUDIO_PROCESSING_AGC2_DOWN_SAMPLER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_DOWN_SAMPLER_H_
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/biquad_filter.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+
+class DownSampler {
+ public:
+ explicit DownSampler(ApmDataDumper* data_dumper);
+
+ DownSampler() = delete;
+ DownSampler(const DownSampler&) = delete;
+ DownSampler& operator=(const DownSampler&) = delete;
+
+ void Initialize(int sample_rate_hz);
+
+ void DownSample(rtc::ArrayView<const float> in, rtc::ArrayView<float> out);
+
+ private:
+ ApmDataDumper* data_dumper_;
+ int sample_rate_hz_;
+ int down_sampling_factor_;
+ BiQuadFilter low_pass_filter_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_DOWN_SAMPLER_H_
diff --git a/webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.cc b/webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.cc
new file mode 100644
index 0000000..971f4f6
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/fixed_digital_level_estimator.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+constexpr float kInitialFilterStateLevel = 0.f;
+
+} // namespace
+
+FixedDigitalLevelEstimator::FixedDigitalLevelEstimator(
+ size_t sample_rate_hz,
+ ApmDataDumper* apm_data_dumper)
+ : apm_data_dumper_(apm_data_dumper),
+ filter_state_level_(kInitialFilterStateLevel) {
+ SetSampleRate(sample_rate_hz);
+ CheckParameterCombination();
+ RTC_DCHECK(apm_data_dumper_);
+ apm_data_dumper_->DumpRaw("agc2_level_estimator_samplerate", sample_rate_hz);
+}
+
+void FixedDigitalLevelEstimator::CheckParameterCombination() {
+ RTC_DCHECK_GT(samples_in_frame_, 0);
+ RTC_DCHECK_LE(kSubFramesInFrame, samples_in_frame_);
+ RTC_DCHECK_EQ(samples_in_frame_ % kSubFramesInFrame, 0);
+ RTC_DCHECK_GT(samples_in_sub_frame_, 1);
+}
+
+std::array<float, kSubFramesInFrame> FixedDigitalLevelEstimator::ComputeLevel(
+ const AudioFrameView<const float>& float_frame) {
+ RTC_DCHECK_GT(float_frame.num_channels(), 0);
+ RTC_DCHECK_EQ(float_frame.samples_per_channel(), samples_in_frame_);
+
+ // Compute max envelope without smoothing.
+ std::array<float, kSubFramesInFrame> envelope{};
+ for (size_t channel_idx = 0; channel_idx < float_frame.num_channels();
+ ++channel_idx) {
+ const auto channel = float_frame.channel(channel_idx);
+ for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame; ++sub_frame) {
+ for (size_t sample_in_sub_frame = 0;
+ sample_in_sub_frame < samples_in_sub_frame_; ++sample_in_sub_frame) {
+ envelope[sub_frame] =
+ std::max(envelope[sub_frame],
+ std::abs(channel[sub_frame * samples_in_sub_frame_ +
+ sample_in_sub_frame]));
+ }
+ }
+ }
+
+ // Make sure envelope increases happen one step earlier so that the
+ // corresponding *gain decrease* doesn't miss a sudden signal
+ // increase due to interpolation.
+ for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame - 1; ++sub_frame) {
+ if (envelope[sub_frame] < envelope[sub_frame + 1]) {
+ envelope[sub_frame] = envelope[sub_frame + 1];
+ }
+ }
+
+ // Add attack / decay smoothing.
+ for (size_t sub_frame = 0; sub_frame < kSubFramesInFrame; ++sub_frame) {
+ const float envelope_value = envelope[sub_frame];
+ if (envelope_value > filter_state_level_) {
+ envelope[sub_frame] = envelope_value * (1 - kAttackFilterConstant) +
+ filter_state_level_ * kAttackFilterConstant;
+ } else {
+ envelope[sub_frame] = envelope_value * (1 - kDecayFilterConstant) +
+ filter_state_level_ * kDecayFilterConstant;
+ }
+ filter_state_level_ = envelope[sub_frame];
+
+ // Dump data for debug.
+ RTC_DCHECK(apm_data_dumper_);
+ const auto channel = float_frame.channel(0);
+ apm_data_dumper_->DumpRaw("agc2_level_estimator_samples",
+ samples_in_sub_frame_,
+ &channel[sub_frame * samples_in_sub_frame_]);
+ apm_data_dumper_->DumpRaw("agc2_level_estimator_level",
+ envelope[sub_frame]);
+ }
+
+ return envelope;
+}
+
+void FixedDigitalLevelEstimator::SetSampleRate(size_t sample_rate_hz) {
+ samples_in_frame_ = rtc::CheckedDivExact(sample_rate_hz * kFrameDurationMs,
+ static_cast<size_t>(1000));
+ samples_in_sub_frame_ =
+ rtc::CheckedDivExact(samples_in_frame_, kSubFramesInFrame);
+ CheckParameterCombination();
+}
+
+void FixedDigitalLevelEstimator::Reset() {
+ filter_state_level_ = kInitialFilterStateLevel;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.h b/webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.h
new file mode 100644
index 0000000..aa84a2e
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/fixed_digital_level_estimator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_FIXED_DIGITAL_LEVEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_FIXED_DIGITAL_LEVEL_ESTIMATOR_H_
+
+#include <array>
+#include <vector>
+
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+// Produces a smooth signal level estimate from an input audio
+// stream. The estimate smoothing is done through exponential
+// filtering.
+class FixedDigitalLevelEstimator {
+ public:
+ // Sample rates are allowed if the number of samples in a frame
+ // (sample_rate_hz * kFrameDurationMs / 1000) is divisible by
+ // kSubFramesInSample. For kFrameDurationMs=10 and
+ // kSubFramesInSample=20, this means that sample_rate_hz has to be
+ // divisible by 2000.
+ FixedDigitalLevelEstimator(size_t sample_rate_hz,
+ ApmDataDumper* apm_data_dumper);
+
+ // The input is assumed to be in FloatS16 format. Scaled input will
+ // produce similarly scaled output. A frame of with kFrameDurationMs
+ // ms of audio produces a level estimates in the same scale. The
+ // level estimate contains kSubFramesInFrame values.
+ std::array<float, kSubFramesInFrame> ComputeLevel(
+ const AudioFrameView<const float>& float_frame);
+
+ // Rate may be changed at any time (but not concurrently) from the
+ // value passed to the constructor. The class is not thread safe.
+ void SetSampleRate(size_t sample_rate_hz);
+
+ // Resets the level estimator internal state.
+ void Reset();
+
+ float LastAudioLevel() const { return filter_state_level_; }
+
+ private:
+ void CheckParameterCombination();
+
+ ApmDataDumper* const apm_data_dumper_ = nullptr;
+ float filter_state_level_;
+ size_t samples_in_frame_;
+ size_t samples_in_sub_frame_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(FixedDigitalLevelEstimator);
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_FIXED_DIGITAL_LEVEL_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/agc2/fixed_gain_controller.cc b/webrtc/modules/audio_processing/agc2/fixed_gain_controller.cc
new file mode 100644
index 0000000..ef908dc
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/fixed_gain_controller.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/fixed_gain_controller.h"
+
+#include "api/array_view.h"
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+namespace {
+
+// Returns true when the gain factor is so close to 1 that it would
+// not affect int16 samples.
+bool CloseToOne(float gain_factor) {
+ return 1.f - 1.f / kMaxFloatS16Value <= gain_factor &&
+ gain_factor <= 1.f + 1.f / kMaxFloatS16Value;
+}
+} // namespace
+
+FixedGainController::FixedGainController(ApmDataDumper* apm_data_dumper)
+ : FixedGainController(apm_data_dumper, "Agc2") {}
+
+FixedGainController::FixedGainController(ApmDataDumper* apm_data_dumper,
+ std::string histogram_name_prefix)
+ : apm_data_dumper_(apm_data_dumper),
+ limiter_(48000, apm_data_dumper_, histogram_name_prefix) {
+ // Do update histograms.xml when adding name prefixes.
+ RTC_DCHECK(histogram_name_prefix == "" || histogram_name_prefix == "Test" ||
+ histogram_name_prefix == "AudioMixer" ||
+ histogram_name_prefix == "Agc2");
+}
+
+void FixedGainController::SetGain(float gain_to_apply_db) {
+ // Changes in gain_to_apply_ cause discontinuities. We assume
+ // gain_to_apply_ is set in the beginning of the call. If it is
+ // frequently changed, we should add interpolation between the
+ // values.
+ // The gain
+ RTC_DCHECK_LE(-50.f, gain_to_apply_db);
+ RTC_DCHECK_LE(gain_to_apply_db, 50.f);
+ const float previous_applied_gained = gain_to_apply_;
+ gain_to_apply_ = DbToRatio(gain_to_apply_db);
+ RTC_DCHECK_LT(0.f, gain_to_apply_);
+ RTC_DLOG(LS_INFO) << "Gain to apply: " << gain_to_apply_db << " db.";
+ // Reset the gain curve applier to quickly react on abrupt level changes
+ // caused by large changes of the applied gain.
+ if (previous_applied_gained != gain_to_apply_) {
+ limiter_.Reset();
+ }
+}
+
+void FixedGainController::SetSampleRate(size_t sample_rate_hz) {
+ limiter_.SetSampleRate(sample_rate_hz);
+}
+
+void FixedGainController::Process(AudioFrameView<float> signal) {
+ // Apply fixed digital gain. One of the
+ // planned usages of the FGC is to only use the limiter. In that
+ // case, the gain would be 1.0. Not doing the multiplications speeds
+ // it up considerably. Hence the check.
+ if (!CloseToOne(gain_to_apply_)) {
+ for (size_t k = 0; k < signal.num_channels(); ++k) {
+ rtc::ArrayView<float> channel_view = signal.channel(k);
+ for (auto& sample : channel_view) {
+ sample *= gain_to_apply_;
+ }
+ }
+ }
+
+ // Use the limiter.
+ limiter_.Process(signal);
+
+ // Dump data for debug.
+ const auto channel_view = signal.channel(0);
+ apm_data_dumper_->DumpRaw("agc2_fixed_digital_gain_curve_applier",
+ channel_view.size(), channel_view.data());
+ // Hard-clipping.
+ for (size_t k = 0; k < signal.num_channels(); ++k) {
+ rtc::ArrayView<float> channel_view = signal.channel(k);
+ for (auto& sample : channel_view) {
+ sample = rtc::SafeClamp(sample, kMinFloatS16Value, kMaxFloatS16Value);
+ }
+ }
+}
+
+float FixedGainController::LastAudioLevel() const {
+ return limiter_.LastAudioLevel();
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/gain_applier.cc b/webrtc/modules/audio_processing/agc2/gain_applier.cc
new file mode 100644
index 0000000..8c43717
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/gain_applier.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/gain_applier.h"
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+namespace {
+
+// Returns true when the gain factor is so close to 1 that it would
+// not affect int16 samples.
+bool GainCloseToOne(float gain_factor) {
+ return 1.f - 1.f / kMaxFloatS16Value <= gain_factor &&
+ gain_factor <= 1.f + 1.f / kMaxFloatS16Value;
+}
+
+void ClipSignal(AudioFrameView<float> signal) {
+ for (size_t k = 0; k < signal.num_channels(); ++k) {
+ rtc::ArrayView<float> channel_view = signal.channel(k);
+ for (auto& sample : channel_view) {
+ sample = rtc::SafeClamp(sample, kMinFloatS16Value, kMaxFloatS16Value);
+ }
+ }
+}
+
+void ApplyGainWithRamping(float last_gain_linear,
+ float gain_at_end_of_frame_linear,
+ float inverse_samples_per_channel,
+ AudioFrameView<float> float_frame) {
+ // Do not modify the signal.
+ if (last_gain_linear == gain_at_end_of_frame_linear &&
+ GainCloseToOne(gain_at_end_of_frame_linear)) {
+ return;
+ }
+
+ // Gain is constant and different from 1.
+ if (last_gain_linear == gain_at_end_of_frame_linear) {
+ for (size_t k = 0; k < float_frame.num_channels(); ++k) {
+ rtc::ArrayView<float> channel_view = float_frame.channel(k);
+ for (auto& sample : channel_view) {
+ sample *= gain_at_end_of_frame_linear;
+ }
+ }
+ return;
+ }
+
+ // The gain changes. We have to change slowly to avoid discontinuities.
+ const float increment = (gain_at_end_of_frame_linear - last_gain_linear) *
+ inverse_samples_per_channel;
+ float gain = last_gain_linear;
+ for (size_t i = 0; i < float_frame.samples_per_channel(); ++i) {
+ for (size_t ch = 0; ch < float_frame.num_channels(); ++ch) {
+ float_frame.channel(ch)[i] *= gain;
+ }
+ gain += increment;
+ }
+}
+
+} // namespace
+
+GainApplier::GainApplier(bool hard_clip_samples, float initial_gain_factor)
+ : hard_clip_samples_(hard_clip_samples),
+ last_gain_factor_(initial_gain_factor),
+ current_gain_factor_(initial_gain_factor) {}
+
+void GainApplier::ApplyGain(AudioFrameView<float> signal) {
+ if (static_cast<int>(signal.samples_per_channel()) != samples_per_channel_) {
+ Initialize(signal.samples_per_channel());
+ }
+
+ ApplyGainWithRamping(last_gain_factor_, current_gain_factor_,
+ inverse_samples_per_channel_, signal);
+
+ last_gain_factor_ = current_gain_factor_;
+
+ if (hard_clip_samples_) {
+ ClipSignal(signal);
+ }
+}
+
+void GainApplier::SetGainFactor(float gain_factor) {
+ RTC_DCHECK_GT(gain_factor, 0.f);
+ current_gain_factor_ = gain_factor;
+}
+
+void GainApplier::Initialize(size_t samples_per_channel) {
+ RTC_DCHECK_GT(samples_per_channel, 0);
+ samples_per_channel_ = static_cast<int>(samples_per_channel);
+ inverse_samples_per_channel_ = 1.f / samples_per_channel_;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/gain_applier.h b/webrtc/modules/audio_processing/agc2/gain_applier.h
new file mode 100644
index 0000000..d9aa19d
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/gain_applier.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_GAIN_APPLIER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_GAIN_APPLIER_H_
+
+#include <stddef.h>
+
+#include "modules/audio_processing/include/audio_frame_view.h"
+
+namespace webrtc {
+class GainApplier {
+ public:
+ GainApplier(bool hard_clip_samples, float initial_gain_factor);
+
+ void ApplyGain(AudioFrameView<float> signal);
+ void SetGainFactor(float gain_factor);
+ float GetGainFactor() const { return current_gain_factor_; }
+
+ private:
+ void Initialize(size_t samples_per_channel);
+
+ // Whether to clip samples after gain is applied. If 'true', result
+ // will fit in FloatS16 range.
+ const bool hard_clip_samples_;
+ float last_gain_factor_;
+
+ // If this value is not equal to 'last_gain_factor', gain will be
+ // ramped from 'last_gain_factor_' to this value during the next
+ // 'ApplyGain'.
+ float current_gain_factor_;
+ int samples_per_channel_ = -1;
+ float inverse_samples_per_channel_ = -1.f;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_GAIN_APPLIER_H_
diff --git a/webrtc/modules/audio_processing/agc2/interpolated_gain_curve.cc b/webrtc/modules/audio_processing/agc2/interpolated_gain_curve.cc
new file mode 100644
index 0000000..502e702
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/interpolated_gain_curve.cc
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/interpolated_gain_curve.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+constexpr std::array<float, kInterpolatedGainCurveTotalPoints>
+ InterpolatedGainCurve::approximation_params_x_;
+
+constexpr std::array<float, kInterpolatedGainCurveTotalPoints>
+ InterpolatedGainCurve::approximation_params_m_;
+
+constexpr std::array<float, kInterpolatedGainCurveTotalPoints>
+ InterpolatedGainCurve::approximation_params_q_;
+
+InterpolatedGainCurve::InterpolatedGainCurve(ApmDataDumper* apm_data_dumper,
+ std::string histogram_name_prefix)
+ : region_logger_("WebRTC.Audio." + histogram_name_prefix +
+ ".FixedDigitalGainCurveRegion.Identity",
+ "WebRTC.Audio." + histogram_name_prefix +
+ ".FixedDigitalGainCurveRegion.Knee",
+ "WebRTC.Audio." + histogram_name_prefix +
+ ".FixedDigitalGainCurveRegion.Limiter",
+ "WebRTC.Audio." + histogram_name_prefix +
+ ".FixedDigitalGainCurveRegion.Saturation"),
+ apm_data_dumper_(apm_data_dumper) {}
+
+InterpolatedGainCurve::~InterpolatedGainCurve() {
+ if (stats_.available) {
+ RTC_DCHECK(apm_data_dumper_);
+ apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_identity",
+ stats_.look_ups_identity_region);
+ apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_knee",
+ stats_.look_ups_knee_region);
+ apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_limiter",
+ stats_.look_ups_limiter_region);
+ apm_data_dumper_->DumpRaw("agc2_interp_gain_curve_lookups_saturation",
+ stats_.look_ups_saturation_region);
+ region_logger_.LogRegionStats(stats_);
+ }
+}
+
+InterpolatedGainCurve::RegionLogger::RegionLogger(
+ std::string identity_histogram_name,
+ std::string knee_histogram_name,
+ std::string limiter_histogram_name,
+ std::string saturation_histogram_name)
+ : identity_histogram(
+ metrics::HistogramFactoryGetCounts(identity_histogram_name,
+ 1,
+ 10000,
+ 50)),
+ knee_histogram(metrics::HistogramFactoryGetCounts(knee_histogram_name,
+ 1,
+ 10000,
+ 50)),
+ limiter_histogram(
+ metrics::HistogramFactoryGetCounts(limiter_histogram_name,
+ 1,
+ 10000,
+ 50)),
+ saturation_histogram(
+ metrics::HistogramFactoryGetCounts(saturation_histogram_name,
+ 1,
+ 10000,
+ 50)) {}
+
+InterpolatedGainCurve::RegionLogger::~RegionLogger() = default;
+
+void InterpolatedGainCurve::RegionLogger::LogRegionStats(
+ const InterpolatedGainCurve::Stats& stats) const {
+ using Region = InterpolatedGainCurve::GainCurveRegion;
+ const int duration_s =
+ stats.region_duration_frames / (1000 / kFrameDurationMs);
+
+ switch (stats.region) {
+ case Region::kIdentity: {
+ if (identity_histogram) {
+ metrics::HistogramAdd(identity_histogram, duration_s);
+ }
+ break;
+ }
+ case Region::kKnee: {
+ if (knee_histogram) {
+ metrics::HistogramAdd(knee_histogram, duration_s);
+ }
+ break;
+ }
+ case Region::kLimiter: {
+ if (limiter_histogram) {
+ metrics::HistogramAdd(limiter_histogram, duration_s);
+ }
+ break;
+ }
+ case Region::kSaturation: {
+ if (saturation_histogram) {
+ metrics::HistogramAdd(saturation_histogram, duration_s);
+ }
+ break;
+ }
+ default: {
+ RTC_NOTREACHED();
+ }
+ }
+}
+
+void InterpolatedGainCurve::UpdateStats(float input_level) const {
+ stats_.available = true;
+
+ GainCurveRegion region;
+
+ if (input_level < approximation_params_x_[0]) {
+ stats_.look_ups_identity_region++;
+ region = GainCurveRegion::kIdentity;
+ } else if (input_level <
+ approximation_params_x_[kInterpolatedGainCurveKneePoints - 1]) {
+ stats_.look_ups_knee_region++;
+ region = GainCurveRegion::kKnee;
+ } else if (input_level < kMaxInputLevelLinear) {
+ stats_.look_ups_limiter_region++;
+ region = GainCurveRegion::kLimiter;
+ } else {
+ stats_.look_ups_saturation_region++;
+ region = GainCurveRegion::kSaturation;
+ }
+
+ if (region == stats_.region) {
+ ++stats_.region_duration_frames;
+ } else {
+ region_logger_.LogRegionStats(stats_);
+
+ stats_.region_duration_frames = 0;
+ stats_.region = region;
+ }
+}
+
+// Looks up a gain to apply given a non-negative input level.
+// The cost of this operation depends on the region in which |input_level|
+// falls.
+// For the identity and the saturation regions the cost is O(1).
+// For the other regions, namely knee and limiter, the cost is
+// O(2 + log2(|LightkInterpolatedGainCurveTotalPoints|), plus O(1) for the
+// linear interpolation (one product and one sum).
+float InterpolatedGainCurve::LookUpGainToApply(float input_level) const {
+ UpdateStats(input_level);
+
+ if (input_level <= approximation_params_x_[0]) {
+ // Identity region.
+ return 1.0f;
+ }
+
+ if (input_level >= kMaxInputLevelLinear) {
+ // Saturating lower bound. The saturing samples exactly hit the clipping
+ // level. This method achieves has the lowest harmonic distorsion, but it
+ // may reduce the amplitude of the non-saturating samples too much.
+ return 32768.f / input_level;
+ }
+
+ // Knee and limiter regions; find the linear piece index. Spelling
+ // out the complete type was the only way to silence both the clang
+ // plugin and the windows compilers.
+ std::array<float, kInterpolatedGainCurveTotalPoints>::const_iterator it =
+ std::lower_bound(approximation_params_x_.begin(),
+ approximation_params_x_.end(), input_level);
+ const size_t index = std::distance(approximation_params_x_.begin(), it) - 1;
+ RTC_DCHECK_LE(0, index);
+ RTC_DCHECK_LT(index, approximation_params_m_.size());
+ RTC_DCHECK_LE(approximation_params_x_[index], input_level);
+ if (index < approximation_params_m_.size() - 1) {
+ RTC_DCHECK_LE(input_level, approximation_params_x_[index + 1]);
+ }
+
+ // Piece-wise linear interploation.
+ const float gain = approximation_params_m_[index] * input_level +
+ approximation_params_q_[index];
+ RTC_DCHECK_LE(0.f, gain);
+ return gain;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/interpolated_gain_curve.h b/webrtc/modules/audio_processing/agc2/interpolated_gain_curve.h
new file mode 100644
index 0000000..ef1c027
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/interpolated_gain_curve.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_
+
+#include <array>
+#include <string>
+
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/gtest_prod_util.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+
+constexpr float kInputLevelScalingFactor = 32768.0f;
+
+// Defined as DbfsToLinear(kLimiterMaxInputLevelDbFs)
+constexpr float kMaxInputLevelLinear = static_cast<float>(36766.300710566735);
+
+// Interpolated gain curve using under-approximation to avoid saturation.
+//
+// The goal of this class is allowing fast look ups to get an accurate
+// estimates of the gain to apply given an estimated input level.
+class InterpolatedGainCurve {
+ public:
+ enum class GainCurveRegion {
+ kIdentity = 0,
+ kKnee = 1,
+ kLimiter = 2,
+ kSaturation = 3
+ };
+
+ struct Stats {
+ // Region in which the output level equals the input one.
+ size_t look_ups_identity_region = 0;
+ // Smoothing between the identity and the limiter regions.
+ size_t look_ups_knee_region = 0;
+ // Limiter region in which the output and input levels are linearly related.
+ size_t look_ups_limiter_region = 0;
+ // Region in which saturation may occur since the input level is beyond the
+ // maximum expected by the limiter.
+ size_t look_ups_saturation_region = 0;
+ // True if stats have been populated.
+ bool available = false;
+
+ // The current region, and for how many frames the level has been
+ // in that region.
+ GainCurveRegion region = GainCurveRegion::kIdentity;
+ int64_t region_duration_frames = 0;
+ };
+
+ InterpolatedGainCurve(ApmDataDumper* apm_data_dumper,
+ std::string histogram_name_prefix);
+ ~InterpolatedGainCurve();
+
+ Stats get_stats() const { return stats_; }
+
+ // Given a non-negative input level (linear scale), a scalar factor to apply
+ // to a sub-frame is returned.
+ // Levels above kLimiterMaxInputLevelDbFs will be reduced to 0 dBFS
+ // after applying this gain
+ float LookUpGainToApply(float input_level) const;
+
+ private:
+ // For comparing 'approximation_params_*_' with ones computed by
+ // ComputeInterpolatedGainCurve.
+ FRIEND_TEST_ALL_PREFIXES(AutomaticGainController2InterpolatedGainCurve,
+ CheckApproximationParams);
+
+ struct RegionLogger {
+ metrics::Histogram* identity_histogram;
+ metrics::Histogram* knee_histogram;
+ metrics::Histogram* limiter_histogram;
+ metrics::Histogram* saturation_histogram;
+
+ RegionLogger(std::string identity_histogram_name,
+ std::string knee_histogram_name,
+ std::string limiter_histogram_name,
+ std::string saturation_histogram_name);
+
+ ~RegionLogger();
+
+ void LogRegionStats(const InterpolatedGainCurve::Stats& stats) const;
+ } region_logger_;
+
+ void UpdateStats(float input_level) const;
+
+ ApmDataDumper* const apm_data_dumper_;
+
+ static constexpr std::array<float, kInterpolatedGainCurveTotalPoints>
+ approximation_params_x_ = {
+ {30057.296875, 30148.986328125, 30240.67578125, 30424.052734375,
+ 30607.4296875, 30790.806640625, 30974.18359375, 31157.560546875,
+ 31340.939453125, 31524.31640625, 31707.693359375, 31891.0703125,
+ 32074.447265625, 32257.82421875, 32441.201171875, 32624.580078125,
+ 32807.95703125, 32991.33203125, 33174.7109375, 33358.08984375,
+ 33541.46484375, 33724.84375, 33819.53515625, 34009.5390625,
+ 34200.05859375, 34389.81640625, 34674.48828125, 35054.375,
+ 35434.86328125, 35814.81640625, 36195.16796875, 36575.03125}};
+ static constexpr std::array<float, kInterpolatedGainCurveTotalPoints>
+ approximation_params_m_ = {
+ {-3.515235675877192989e-07, -1.050251626111275982e-06,
+ -2.085213736791047268e-06, -3.443004743530764244e-06,
+ -4.773849468620028347e-06, -6.077375928725814447e-06,
+ -7.353257842623861507e-06, -8.601219633419532329e-06,
+ -9.821013009059242904e-06, -1.101243378798244521e-05,
+ -1.217532644659513608e-05, -1.330956911260727793e-05,
+ -1.441507538402220234e-05, -1.549179251014720649e-05,
+ -1.653970684856176376e-05, -1.755882840370759368e-05,
+ -1.854918446042574942e-05, -1.951086778717581183e-05,
+ -2.044398024736437947e-05, -2.1348627342376858e-05,
+ -2.222496914328075945e-05, -2.265374678245279938e-05,
+ -2.242570917587727308e-05, -2.220122041762806475e-05,
+ -2.19802095671184361e-05, -2.176260204578284174e-05,
+ -2.133731686626560986e-05, -2.092481918225530535e-05,
+ -2.052459603874012828e-05, -2.013615448959171772e-05,
+ -1.975903069251216948e-05, -1.939277899509761482e-05}};
+
+ static constexpr std::array<float, kInterpolatedGainCurveTotalPoints>
+ approximation_params_q_ = {
+ {1.010565876960754395, 1.031631827354431152, 1.062929749488830566,
+ 1.104239225387573242, 1.144973039627075195, 1.185109615325927734,
+ 1.224629044532775879, 1.263512492179870605, 1.301741957664489746,
+ 1.339300632476806641, 1.376173257827758789, 1.412345528602600098,
+ 1.447803974151611328, 1.482536554336547852, 1.516532182693481445,
+ 1.549780607223510742, 1.582272171974182129, 1.613999366760253906,
+ 1.644955039024353027, 1.675132393836975098, 1.704526185989379883,
+ 1.718986630439758301, 1.711274504661560059, 1.703639745712280273,
+ 1.696081161499023438, 1.688597679138183594, 1.673851132392883301,
+ 1.659391283988952637, 1.645209431648254395, 1.631297469139099121,
+ 1.617647409439086914, 1.604251742362976074}};
+
+ // Stats.
+ mutable Stats stats_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(InterpolatedGainCurve);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_INTERPOLATED_GAIN_CURVE_H_
diff --git a/webrtc/modules/audio_processing/agc2/limiter.cc b/webrtc/modules/audio_processing/agc2/limiter.cc
new file mode 100644
index 0000000..1589f07
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/limiter.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/limiter.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+namespace {
+
+// This constant affects the way scaling factors are interpolated for the first
+// sub-frame of a frame. Only in the case in which the first sub-frame has an
+// estimated level which is greater than the that of the previous analyzed
+// sub-frame, linear interpolation is replaced with a power function which
+// reduces the chances of over-shooting (and hence saturation), however reducing
+// the fixed gain effectiveness.
+constexpr float kAttackFirstSubframeInterpolationPower = 8.f;
+
+void InterpolateFirstSubframe(float last_factor,
+ float current_factor,
+ rtc::ArrayView<float> subframe) {
+ const auto n = subframe.size();
+ constexpr auto p = kAttackFirstSubframeInterpolationPower;
+ for (size_t i = 0; i < n; ++i) {
+ subframe[i] = std::pow(1.f - i / n, p) * (last_factor - current_factor) +
+ current_factor;
+ }
+}
+
+void ComputePerSampleSubframeFactors(
+ const std::array<float, kSubFramesInFrame + 1>& scaling_factors,
+ size_t samples_per_channel,
+ rtc::ArrayView<float> per_sample_scaling_factors) {
+ const size_t num_subframes = scaling_factors.size() - 1;
+ const size_t subframe_size =
+ rtc::CheckedDivExact(samples_per_channel, num_subframes);
+
+ // Handle first sub-frame differently in case of attack.
+ const bool is_attack = scaling_factors[0] > scaling_factors[1];
+ if (is_attack) {
+ InterpolateFirstSubframe(
+ scaling_factors[0], scaling_factors[1],
+ rtc::ArrayView<float>(
+ per_sample_scaling_factors.subview(0, subframe_size)));
+ }
+
+ for (size_t i = is_attack ? 1 : 0; i < num_subframes; ++i) {
+ const size_t subframe_start = i * subframe_size;
+ const float scaling_start = scaling_factors[i];
+ const float scaling_end = scaling_factors[i + 1];
+ const float scaling_diff = (scaling_end - scaling_start) / subframe_size;
+ for (size_t j = 0; j < subframe_size; ++j) {
+ per_sample_scaling_factors[subframe_start + j] =
+ scaling_start + scaling_diff * j;
+ }
+ }
+}
+
+void ScaleSamples(rtc::ArrayView<const float> per_sample_scaling_factors,
+ AudioFrameView<float> signal) {
+ const size_t samples_per_channel = signal.samples_per_channel();
+ RTC_DCHECK_EQ(samples_per_channel, per_sample_scaling_factors.size());
+ for (size_t i = 0; i < signal.num_channels(); ++i) {
+ auto channel = signal.channel(i);
+ for (size_t j = 0; j < samples_per_channel; ++j) {
+ channel[j] = rtc::SafeClamp(channel[j] * per_sample_scaling_factors[j],
+ kMinFloatS16Value, kMaxFloatS16Value);
+ }
+ }
+}
+
+void CheckLimiterSampleRate(size_t sample_rate_hz) {
+ // Check that per_sample_scaling_factors_ is large enough.
+ RTC_DCHECK_LE(sample_rate_hz,
+ kMaximalNumberOfSamplesPerChannel * 1000 / kFrameDurationMs);
+}
+
+} // namespace
+
+Limiter::Limiter(size_t sample_rate_hz,
+ ApmDataDumper* apm_data_dumper,
+ std::string histogram_name)
+ : interp_gain_curve_(apm_data_dumper, histogram_name),
+ level_estimator_(sample_rate_hz, apm_data_dumper),
+ apm_data_dumper_(apm_data_dumper) {
+ CheckLimiterSampleRate(sample_rate_hz);
+}
+
+Limiter::~Limiter() = default;
+
+void Limiter::Process(AudioFrameView<float> signal) {
+ const auto level_estimate = level_estimator_.ComputeLevel(signal);
+
+ RTC_DCHECK_EQ(level_estimate.size() + 1, scaling_factors_.size());
+ scaling_factors_[0] = last_scaling_factor_;
+ std::transform(level_estimate.begin(), level_estimate.end(),
+ scaling_factors_.begin() + 1, [this](float x) {
+ return interp_gain_curve_.LookUpGainToApply(x);
+ });
+
+ const size_t samples_per_channel = signal.samples_per_channel();
+ RTC_DCHECK_LE(samples_per_channel, kMaximalNumberOfSamplesPerChannel);
+
+ auto per_sample_scaling_factors = rtc::ArrayView<float>(
+ &per_sample_scaling_factors_[0], samples_per_channel);
+ ComputePerSampleSubframeFactors(scaling_factors_, samples_per_channel,
+ per_sample_scaling_factors);
+ ScaleSamples(per_sample_scaling_factors, signal);
+
+ last_scaling_factor_ = scaling_factors_.back();
+
+ // Dump data for debug.
+ apm_data_dumper_->DumpRaw("agc2_gain_curve_applier_scaling_factors",
+ samples_per_channel,
+ per_sample_scaling_factors_.data());
+}
+
+InterpolatedGainCurve::Stats Limiter::GetGainCurveStats() const {
+ return interp_gain_curve_.get_stats();
+}
+
+void Limiter::SetSampleRate(size_t sample_rate_hz) {
+ CheckLimiterSampleRate(sample_rate_hz);
+ level_estimator_.SetSampleRate(sample_rate_hz);
+}
+
+void Limiter::Reset() {
+ level_estimator_.Reset();
+}
+
+float Limiter::LastAudioLevel() const {
+ return level_estimator_.LastAudioLevel();
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/limiter.h b/webrtc/modules/audio_processing/agc2/limiter.h
new file mode 100644
index 0000000..599fd0f
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/limiter.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_
+
+#include <string>
+#include <vector>
+
+#include "modules/audio_processing/agc2/fixed_digital_level_estimator.h"
+#include "modules/audio_processing/agc2/interpolated_gain_curve.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+class ApmDataDumper;
+
+class Limiter {
+ public:
+ Limiter(size_t sample_rate_hz,
+ ApmDataDumper* apm_data_dumper,
+ std::string histogram_name_prefix);
+ Limiter(const Limiter& limiter) = delete;
+ Limiter& operator=(const Limiter& limiter) = delete;
+ ~Limiter();
+
+ // Applies limiter and hard-clipping to |signal|.
+ void Process(AudioFrameView<float> signal);
+ InterpolatedGainCurve::Stats GetGainCurveStats() const;
+
+ // Supported rates must be
+ // * supported by FixedDigitalLevelEstimator
+ // * below kMaximalNumberOfSamplesPerChannel*1000/kFrameDurationMs
+ // so that samples_per_channel fit in the
+ // per_sample_scaling_factors_ array.
+ void SetSampleRate(size_t sample_rate_hz);
+
+ // Resets the internal state.
+ void Reset();
+
+ float LastAudioLevel() const;
+
+ private:
+ const InterpolatedGainCurve interp_gain_curve_;
+ FixedDigitalLevelEstimator level_estimator_;
+ ApmDataDumper* const apm_data_dumper_ = nullptr;
+
+ // Work array containing the sub-frame scaling factors to be interpolated.
+ std::array<float, kSubFramesInFrame + 1> scaling_factors_ = {};
+ std::array<float, kMaximalNumberOfSamplesPerChannel>
+ per_sample_scaling_factors_ = {};
+ float last_scaling_factor_ = 1.f;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_LIMITER_H_
diff --git a/webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.cc b/webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.cc
new file mode 100644
index 0000000..d55ed5d
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.cc
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/limiter_db_gain_curve.h"
+
+#include <cmath>
+
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+double ComputeKneeStart(double max_input_level_db,
+ double knee_smoothness_db,
+ double compression_ratio) {
+ RTC_CHECK_LT((compression_ratio - 1.0) * knee_smoothness_db /
+ (2.0 * compression_ratio),
+ max_input_level_db);
+ return -knee_smoothness_db / 2.0 -
+ max_input_level_db / (compression_ratio - 1.0);
+}
+
+std::array<double, 3> ComputeKneeRegionPolynomial(double knee_start_dbfs,
+ double knee_smoothness_db,
+ double compression_ratio) {
+ const double a = (1.0 - compression_ratio) /
+ (2.0 * knee_smoothness_db * compression_ratio);
+ const double b = 1.0 - 2.0 * a * knee_start_dbfs;
+ const double c = a * knee_start_dbfs * knee_start_dbfs;
+ return {{a, b, c}};
+}
+
+double ComputeLimiterD1(double max_input_level_db, double compression_ratio) {
+ return (std::pow(10.0, -max_input_level_db / (20.0 * compression_ratio)) *
+ (1.0 - compression_ratio) / compression_ratio) /
+ kMaxAbsFloatS16Value;
+}
+
+constexpr double ComputeLimiterD2(double compression_ratio) {
+ return (1.0 - 2.0 * compression_ratio) / compression_ratio;
+}
+
+double ComputeLimiterI2(double max_input_level_db,
+ double compression_ratio,
+ double gain_curve_limiter_i1) {
+ RTC_CHECK_NE(gain_curve_limiter_i1, 0.f);
+ return std::pow(10.0, -max_input_level_db / (20.0 * compression_ratio)) /
+ gain_curve_limiter_i1 /
+ std::pow(kMaxAbsFloatS16Value, gain_curve_limiter_i1 - 1);
+}
+
+} // namespace
+
+LimiterDbGainCurve::LimiterDbGainCurve()
+ : max_input_level_linear_(DbfsToFloatS16(max_input_level_db_)),
+ knee_start_dbfs_(ComputeKneeStart(max_input_level_db_,
+ knee_smoothness_db_,
+ compression_ratio_)),
+ knee_start_linear_(DbfsToFloatS16(knee_start_dbfs_)),
+ limiter_start_dbfs_(knee_start_dbfs_ + knee_smoothness_db_),
+ limiter_start_linear_(DbfsToFloatS16(limiter_start_dbfs_)),
+ knee_region_polynomial_(ComputeKneeRegionPolynomial(knee_start_dbfs_,
+ knee_smoothness_db_,
+ compression_ratio_)),
+ gain_curve_limiter_d1_(
+ ComputeLimiterD1(max_input_level_db_, compression_ratio_)),
+ gain_curve_limiter_d2_(ComputeLimiterD2(compression_ratio_)),
+ gain_curve_limiter_i1_(1.0 / compression_ratio_),
+ gain_curve_limiter_i2_(ComputeLimiterI2(max_input_level_db_,
+ compression_ratio_,
+ gain_curve_limiter_i1_)) {
+ static_assert(knee_smoothness_db_ > 0.0f, "");
+ static_assert(compression_ratio_ > 1.0f, "");
+ RTC_CHECK_GE(max_input_level_db_, knee_start_dbfs_ + knee_smoothness_db_);
+}
+
+constexpr double LimiterDbGainCurve::max_input_level_db_;
+constexpr double LimiterDbGainCurve::knee_smoothness_db_;
+constexpr double LimiterDbGainCurve::compression_ratio_;
+
+double LimiterDbGainCurve::GetOutputLevelDbfs(double input_level_dbfs) const {
+ if (input_level_dbfs < knee_start_dbfs_) {
+ return input_level_dbfs;
+ } else if (input_level_dbfs < limiter_start_dbfs_) {
+ return GetKneeRegionOutputLevelDbfs(input_level_dbfs);
+ }
+ return GetCompressorRegionOutputLevelDbfs(input_level_dbfs);
+}
+
+double LimiterDbGainCurve::GetGainLinear(double input_level_linear) const {
+ if (input_level_linear < knee_start_linear_) {
+ return 1.0;
+ }
+ return DbfsToFloatS16(
+ GetOutputLevelDbfs(FloatS16ToDbfs(input_level_linear))) /
+ input_level_linear;
+}
+
+// Computes the first derivative of GetGainLinear() in |x|.
+double LimiterDbGainCurve::GetGainFirstDerivativeLinear(double x) const {
+ // Beyond-knee region only.
+ RTC_CHECK_GE(x, limiter_start_linear_ - 1e-7 * kMaxAbsFloatS16Value);
+ return gain_curve_limiter_d1_ *
+ std::pow(x / kMaxAbsFloatS16Value, gain_curve_limiter_d2_);
+}
+
+// Computes the integral of GetGainLinear() in the range [x0, x1].
+double LimiterDbGainCurve::GetGainIntegralLinear(double x0, double x1) const {
+ RTC_CHECK_LE(x0, x1); // Valid interval.
+ RTC_CHECK_GE(x0, limiter_start_linear_); // Beyond-knee region only.
+ auto limiter_integral = [this](const double& x) {
+ return gain_curve_limiter_i2_ * std::pow(x, gain_curve_limiter_i1_);
+ };
+ return limiter_integral(x1) - limiter_integral(x0);
+}
+
+double LimiterDbGainCurve::GetKneeRegionOutputLevelDbfs(
+ double input_level_dbfs) const {
+ return knee_region_polynomial_[0] * input_level_dbfs * input_level_dbfs +
+ knee_region_polynomial_[1] * input_level_dbfs +
+ knee_region_polynomial_[2];
+}
+
+double LimiterDbGainCurve::GetCompressorRegionOutputLevelDbfs(
+ double input_level_dbfs) const {
+ return (input_level_dbfs - max_input_level_db_) / compression_ratio_;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.h b/webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.h
new file mode 100644
index 0000000..9086e26
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/limiter_db_gain_curve.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_
+
+#include <array>
+
+#include "modules/audio_processing/agc2/agc2_testing_common.h"
+
+namespace webrtc {
+
+// A class for computing a limiter gain curve (in dB scale) given a set of
+// hard-coded parameters (namely, kLimiterDbGainCurveMaxInputLevelDbFs,
+// kLimiterDbGainCurveKneeSmoothnessDb, and
+// kLimiterDbGainCurveCompressionRatio). The generated curve consists of four
+// regions: identity (linear), knee (quadratic polynomial), compression
+// (linear), saturation (linear). The aforementioned constants are used to shape
+// the different regions.
+class LimiterDbGainCurve {
+ public:
+ LimiterDbGainCurve();
+
+ double max_input_level_db() const { return max_input_level_db_; }
+ double max_input_level_linear() const { return max_input_level_linear_; }
+ double knee_start_linear() const { return knee_start_linear_; }
+ double limiter_start_linear() const { return limiter_start_linear_; }
+
+ // These methods can be marked 'constexpr' in C++ 14.
+ double GetOutputLevelDbfs(double input_level_dbfs) const;
+ double GetGainLinear(double input_level_linear) const;
+ double GetGainFirstDerivativeLinear(double x) const;
+ double GetGainIntegralLinear(double x0, double x1) const;
+
+ private:
+ double GetKneeRegionOutputLevelDbfs(double input_level_dbfs) const;
+ double GetCompressorRegionOutputLevelDbfs(double input_level_dbfs) const;
+
+ static constexpr double max_input_level_db_ = test::kLimiterMaxInputLevelDbFs;
+ static constexpr double knee_smoothness_db_ = test::kLimiterKneeSmoothnessDb;
+ static constexpr double compression_ratio_ = test::kLimiterCompressionRatio;
+
+ const double max_input_level_linear_;
+
+ // Do not modify signal with level <= knee_start_dbfs_.
+ const double knee_start_dbfs_;
+ const double knee_start_linear_;
+
+ // The upper end of the knee region, which is between knee_start_dbfs_ and
+ // limiter_start_dbfs_.
+ const double limiter_start_dbfs_;
+ const double limiter_start_linear_;
+
+ // Coefficients {a, b, c} of the knee region polynomial
+ // ax^2 + bx + c in the DB scale.
+ const std::array<double, 3> knee_region_polynomial_;
+
+ // Parameters for the computation of the first derivative of GetGainLinear().
+ const double gain_curve_limiter_d1_;
+ const double gain_curve_limiter_d2_;
+
+ // Parameters for the computation of the integral of GetGainLinear().
+ const double gain_curve_limiter_i1_;
+ const double gain_curve_limiter_i2_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_LIMITER_DB_GAIN_CURVE_H_
diff --git a/webrtc/modules/audio_processing/agc2/noise_level_estimator.cc b/webrtc/modules/audio_processing/agc2/noise_level_estimator.cc
new file mode 100644
index 0000000..2ca5034
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/noise_level_estimator.cc
@@ -0,0 +1,114 @@
+/*
+ * 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/audio_processing/agc2/noise_level_estimator.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <cmath>
+#include <numeric>
+
+#include "api/array_view.h"
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+constexpr int kFramesPerSecond = 100;
+
+float FrameEnergy(const AudioFrameView<const float>& audio) {
+ float energy = 0.f;
+ for (size_t k = 0; k < audio.num_channels(); ++k) {
+ float channel_energy =
+ std::accumulate(audio.channel(k).begin(), audio.channel(k).end(), 0.f,
+ [](float a, float b) -> float { return a + b * b; });
+ energy = std::max(channel_energy, energy);
+ }
+ return energy;
+}
+
+float EnergyToDbfs(float signal_energy, size_t num_samples) {
+ const float rms = std::sqrt(signal_energy / num_samples);
+ return FloatS16ToDbfs(rms);
+}
+} // namespace
+
+NoiseLevelEstimator::NoiseLevelEstimator(ApmDataDumper* data_dumper)
+ : signal_classifier_(data_dumper) {
+ Initialize(48000);
+}
+
+NoiseLevelEstimator::~NoiseLevelEstimator() {}
+
+void NoiseLevelEstimator::Initialize(int sample_rate_hz) {
+ sample_rate_hz_ = sample_rate_hz;
+ noise_energy_ = 1.f;
+ first_update_ = true;
+ min_noise_energy_ = sample_rate_hz * 2.f * 2.f / kFramesPerSecond;
+ noise_energy_hold_counter_ = 0;
+ signal_classifier_.Initialize(sample_rate_hz);
+}
+
+float NoiseLevelEstimator::Analyze(const AudioFrameView<const float>& frame) {
+ const int rate =
+ static_cast<int>(frame.samples_per_channel() * kFramesPerSecond);
+ if (rate != sample_rate_hz_) {
+ Initialize(rate);
+ }
+ const float frame_energy = FrameEnergy(frame);
+ if (frame_energy <= 0.f) {
+ RTC_DCHECK_GE(frame_energy, 0.f);
+ return EnergyToDbfs(noise_energy_, frame.samples_per_channel());
+ }
+
+ if (first_update_) {
+ // Initialize the noise energy to the frame energy.
+ first_update_ = false;
+ return EnergyToDbfs(
+ noise_energy_ = std::max(frame_energy, min_noise_energy_),
+ frame.samples_per_channel());
+ }
+
+ const SignalClassifier::SignalType signal_type =
+ signal_classifier_.Analyze(frame.channel(0));
+
+ // Update the noise estimate in a minimum statistics-type manner.
+ if (signal_type == SignalClassifier::SignalType::kStationary) {
+ if (frame_energy > noise_energy_) {
+ // Leak the estimate upwards towards the frame energy if no recent
+ // downward update.
+ noise_energy_hold_counter_ = std::max(noise_energy_hold_counter_ - 1, 0);
+
+ if (noise_energy_hold_counter_ == 0) {
+ noise_energy_ = std::min(noise_energy_ * 1.01f, frame_energy);
+ }
+ } else {
+ // Update smoothly downwards with a limited maximum update magnitude.
+ noise_energy_ =
+ std::max(noise_energy_ * 0.9f,
+ noise_energy_ + 0.05f * (frame_energy - noise_energy_));
+ noise_energy_hold_counter_ = 1000;
+ }
+ } else {
+ // For a non-stationary signal, leak the estimate downwards in order to
+ // avoid estimate locking due to incorrect signal classification.
+ noise_energy_ = noise_energy_ * 0.99f;
+ }
+
+ // Ensure a minimum of the estimate.
+ return EnergyToDbfs(
+ noise_energy_ = std::max(noise_energy_, min_noise_energy_),
+ frame.samples_per_channel());
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/noise_level_estimator.h b/webrtc/modules/audio_processing/agc2/noise_level_estimator.h
new file mode 100644
index 0000000..ca2f9f2
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/noise_level_estimator.h
@@ -0,0 +1,43 @@
+/*
+ * 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_AUDIO_PROCESSING_AGC2_NOISE_LEVEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_NOISE_LEVEL_ESTIMATOR_H_
+
+#include "modules/audio_processing/agc2/signal_classifier.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+class ApmDataDumper;
+
+class NoiseLevelEstimator {
+ public:
+ NoiseLevelEstimator(ApmDataDumper* data_dumper);
+ ~NoiseLevelEstimator();
+ // Returns the estimated noise level in dBFS.
+ float Analyze(const AudioFrameView<const float>& frame);
+
+ private:
+ void Initialize(int sample_rate_hz);
+
+ int sample_rate_hz_;
+ float min_noise_energy_;
+ bool first_update_;
+ float noise_energy_;
+ int noise_energy_hold_counter_;
+ SignalClassifier signal_classifier_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(NoiseLevelEstimator);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_NOISE_LEVEL_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.cc b/webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.cc
new file mode 100644
index 0000000..31438b1
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.cc
@@ -0,0 +1,70 @@
+/*
+ * 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/audio_processing/agc2/noise_spectrum_estimator.h"
+
+#include <string.h>
+
+#include <algorithm>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+constexpr float kMinNoisePower = 100.f;
+} // namespace
+
+NoiseSpectrumEstimator::NoiseSpectrumEstimator(ApmDataDumper* data_dumper)
+ : data_dumper_(data_dumper) {
+ Initialize();
+}
+
+void NoiseSpectrumEstimator::Initialize() {
+ std::fill(noise_spectrum_, noise_spectrum_ + arraysize(noise_spectrum_),
+ kMinNoisePower);
+}
+
+void NoiseSpectrumEstimator::Update(rtc::ArrayView<const float> spectrum,
+ bool first_update) {
+ RTC_DCHECK_EQ(65, spectrum.size());
+
+ if (first_update) {
+ // Initialize the noise spectral estimate with the signal spectrum.
+ std::copy(spectrum.data(), spectrum.data() + spectrum.size(),
+ noise_spectrum_);
+ } else {
+ // Smoothly update the noise spectral estimate towards the signal spectrum
+ // such that the magnitude of the updates are limited.
+ for (size_t k = 0; k < spectrum.size(); ++k) {
+ if (noise_spectrum_[k] < spectrum[k]) {
+ noise_spectrum_[k] = std::min(
+ 1.01f * noise_spectrum_[k],
+ noise_spectrum_[k] + 0.05f * (spectrum[k] - noise_spectrum_[k]));
+ } else {
+ noise_spectrum_[k] = std::max(
+ 0.99f * noise_spectrum_[k],
+ noise_spectrum_[k] + 0.05f * (spectrum[k] - noise_spectrum_[k]));
+ }
+ }
+ }
+
+ // Ensure that the noise spectal estimate does not become too low.
+ for (auto& v : noise_spectrum_) {
+ v = std::max(v, kMinNoisePower);
+ }
+
+ data_dumper_->DumpRaw("lc_noise_spectrum", 65, noise_spectrum_);
+ data_dumper_->DumpRaw("lc_signal_spectrum", spectrum);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.h b/webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.h
new file mode 100644
index 0000000..e9895f0
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/noise_spectrum_estimator.h
@@ -0,0 +1,42 @@
+/*
+ * 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_AUDIO_PROCESSING_AGC2_NOISE_SPECTRUM_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_NOISE_SPECTRUM_ESTIMATOR_H_
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+
+class NoiseSpectrumEstimator {
+ public:
+ explicit NoiseSpectrumEstimator(ApmDataDumper* data_dumper);
+
+ NoiseSpectrumEstimator() = delete;
+ NoiseSpectrumEstimator(const NoiseSpectrumEstimator&) = delete;
+ NoiseSpectrumEstimator& operator=(const NoiseSpectrumEstimator&) = delete;
+
+ void Initialize();
+ void Update(rtc::ArrayView<const float> spectrum, bool first_update);
+
+ rtc::ArrayView<const float> GetNoiseSpectrum() const {
+ return rtc::ArrayView<const float>(noise_spectrum_);
+ }
+
+ private:
+ ApmDataDumper* data_dumper_;
+ float noise_spectrum_[65];
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_NOISE_SPECTRUM_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/BUILD.gn b/webrtc/modules/audio_processing/agc2/rnn_vad/BUILD.gn
new file mode 100644
index 0000000..8b01122
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/BUILD.gn
@@ -0,0 +1,233 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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_library("rnn_vad") {
+ visibility = [ "../*" ]
+ sources = [
+ "features_extraction.cc",
+ "features_extraction.h",
+ "rnn.cc",
+ "rnn.h",
+ ]
+
+ if (rtc_build_with_neon && current_cpu != "arm64") {
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags = [ "-mfpu=neon" ]
+ }
+
+ deps = [
+ ":rnn_vad_common",
+ ":rnn_vad_lp_residual",
+ ":rnn_vad_pitch",
+ ":rnn_vad_sequence_buffer",
+ ":rnn_vad_spectral_features",
+ "..:biquad_filter",
+ "../../../../api:array_view",
+ "../../../../api:function_view",
+ "../../../../rtc_base:checks",
+ "../../../../rtc_base:logging",
+ "../../../../rtc_base/system:arch",
+ "//third_party/rnnoise:rnn_vad",
+ ]
+}
+
+rtc_library("rnn_vad_auto_correlation") {
+ sources = [
+ "auto_correlation.cc",
+ "auto_correlation.h",
+ ]
+ deps = [
+ ":rnn_vad_common",
+ "../../../../api:array_view",
+ "../../../../rtc_base:checks",
+ "../../utility:pffft_wrapper",
+ ]
+}
+
+rtc_library("rnn_vad_common") {
+ # TODO(alessiob): Make this target visibility private.
+ visibility = [
+ ":*",
+ "..:rnn_vad_with_level",
+ ]
+ sources = [
+ "common.cc",
+ "common.h",
+ ]
+ deps = [
+ "../../../../rtc_base/system:arch",
+ "../../../../system_wrappers",
+ ]
+}
+
+rtc_library("rnn_vad_lp_residual") {
+ sources = [
+ "lp_residual.cc",
+ "lp_residual.h",
+ ]
+ deps = [
+ "../../../../api:array_view",
+ "../../../../rtc_base:checks",
+ ]
+}
+
+rtc_library("rnn_vad_pitch") {
+ sources = [
+ "pitch_info.h",
+ "pitch_search.cc",
+ "pitch_search.h",
+ "pitch_search_internal.cc",
+ "pitch_search_internal.h",
+ ]
+ deps = [
+ ":rnn_vad_auto_correlation",
+ ":rnn_vad_common",
+ "../../../../api:array_view",
+ "../../../../rtc_base:checks",
+ ]
+}
+
+rtc_source_set("rnn_vad_ring_buffer") {
+ sources = [ "ring_buffer.h" ]
+ deps = [
+ "../../../../api:array_view",
+ "../../../../rtc_base:checks",
+ ]
+}
+
+rtc_source_set("rnn_vad_sequence_buffer") {
+ sources = [ "sequence_buffer.h" ]
+ deps = [
+ "../../../../api:array_view",
+ "../../../../rtc_base:checks",
+ ]
+}
+
+rtc_library("rnn_vad_spectral_features") {
+ sources = [
+ "spectral_features.cc",
+ "spectral_features.h",
+ "spectral_features_internal.cc",
+ "spectral_features_internal.h",
+ ]
+ deps = [
+ ":rnn_vad_common",
+ ":rnn_vad_ring_buffer",
+ ":rnn_vad_symmetric_matrix_buffer",
+ "../../../../api:array_view",
+ "../../../../rtc_base:checks",
+ "../../utility:pffft_wrapper",
+ ]
+}
+
+rtc_source_set("rnn_vad_symmetric_matrix_buffer") {
+ sources = [ "symmetric_matrix_buffer.h" ]
+ deps = [
+ "../../../../api:array_view",
+ "../../../../rtc_base:checks",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("test_utils") {
+ testonly = true
+ sources = [
+ "test_utils.cc",
+ "test_utils.h",
+ ]
+ deps = [
+ ":rnn_vad",
+ ":rnn_vad_common",
+ "../../../../api:array_view",
+ "../../../../api:scoped_refptr",
+ "../../../../rtc_base:checks",
+ "../../../../rtc_base/system:arch",
+ "../../../../system_wrappers",
+ "../../../../test:fileutils",
+ "../../../../test:test_support",
+ ]
+ }
+
+ unittest_resources = [
+ "../../../../resources/audio_processing/agc2/rnn_vad/band_energies.dat",
+ "../../../../resources/audio_processing/agc2/rnn_vad/pitch_buf_24k.dat",
+ "../../../../resources/audio_processing/agc2/rnn_vad/pitch_lp_res.dat",
+ "../../../../resources/audio_processing/agc2/rnn_vad/pitch_search_int.dat",
+ "../../../../resources/audio_processing/agc2/rnn_vad/samples.pcm",
+ "../../../../resources/audio_processing/agc2/rnn_vad/vad_prob.dat",
+ ]
+
+ if (is_ios) {
+ bundle_data("unittests_bundle_data") {
+ testonly = true
+ sources = unittest_resources
+ outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
+ }
+ }
+
+ rtc_library("unittests") {
+ testonly = true
+ sources = [
+ "auto_correlation_unittest.cc",
+ "features_extraction_unittest.cc",
+ "lp_residual_unittest.cc",
+ "pitch_search_internal_unittest.cc",
+ "pitch_search_unittest.cc",
+ "ring_buffer_unittest.cc",
+ "rnn_unittest.cc",
+ "rnn_vad_unittest.cc",
+ "sequence_buffer_unittest.cc",
+ "spectral_features_internal_unittest.cc",
+ "spectral_features_unittest.cc",
+ "symmetric_matrix_buffer_unittest.cc",
+ ]
+ deps = [
+ ":rnn_vad",
+ ":rnn_vad_auto_correlation",
+ ":rnn_vad_common",
+ ":rnn_vad_lp_residual",
+ ":rnn_vad_pitch",
+ ":rnn_vad_ring_buffer",
+ ":rnn_vad_sequence_buffer",
+ ":rnn_vad_spectral_features",
+ ":rnn_vad_symmetric_matrix_buffer",
+ ":test_utils",
+ "../..:audioproc_test_utils",
+ "../../../../api:array_view",
+ "../../../../common_audio/",
+ "../../../../rtc_base:checks",
+ "../../../../rtc_base:logging",
+ "../../../../rtc_base/system:arch",
+ "../../../../test:test_support",
+ "../../utility:pffft_wrapper",
+ "//third_party/rnnoise:rnn_vad",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/memory" ]
+ data = unittest_resources
+ if (is_ios) {
+ deps += [ ":unittests_bundle_data" ]
+ }
+ }
+
+ rtc_executable("rnn_vad_tool") {
+ testonly = true
+ sources = [ "rnn_vad_tool.cc" ]
+ deps = [
+ ":rnn_vad",
+ ":rnn_vad_common",
+ "../../../../api:array_view",
+ "../../../../common_audio",
+ "../../../../rtc_base:rtc_base_approved",
+ "../../../../test:test_support",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ ]
+ }
+}
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.cc
new file mode 100644
index 0000000..d932c78
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/auto_correlation.h"
+
+#include <algorithm>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+constexpr int kAutoCorrelationFftOrder = 9; // Length-512 FFT.
+static_assert(1 << kAutoCorrelationFftOrder >
+ kNumInvertedLags12kHz + kBufSize12kHz - kMaxPitch12kHz,
+ "");
+
+} // namespace
+
+AutoCorrelationCalculator::AutoCorrelationCalculator()
+ : fft_(1 << kAutoCorrelationFftOrder, Pffft::FftType::kReal),
+ tmp_(fft_.CreateBuffer()),
+ X_(fft_.CreateBuffer()),
+ H_(fft_.CreateBuffer()) {}
+
+AutoCorrelationCalculator::~AutoCorrelationCalculator() = default;
+
+// The auto-correlations coefficients are computed as follows:
+// |.........|...........| <- pitch buffer
+// [ x (fixed) ]
+// [ y_0 ]
+// [ y_{m-1} ]
+// x and y are sub-array of equal length; x is never moved, whereas y slides.
+// The cross-correlation between y_0 and x corresponds to the auto-correlation
+// for the maximum pitch period. Hence, the first value in |auto_corr| has an
+// inverted lag equal to 0 that corresponds to a lag equal to the maximum
+// pitch period.
+void AutoCorrelationCalculator::ComputeOnPitchBuffer(
+ rtc::ArrayView<const float, kBufSize12kHz> pitch_buf,
+ rtc::ArrayView<float, kNumInvertedLags12kHz> auto_corr) {
+ RTC_DCHECK_LT(auto_corr.size(), kMaxPitch12kHz);
+ RTC_DCHECK_GT(pitch_buf.size(), kMaxPitch12kHz);
+ constexpr size_t kFftFrameSize = 1 << kAutoCorrelationFftOrder;
+ constexpr size_t kConvolutionLength = kBufSize12kHz - kMaxPitch12kHz;
+ static_assert(kConvolutionLength == kFrameSize20ms12kHz,
+ "Mismatch between pitch buffer size, frame size and maximum "
+ "pitch period.");
+ static_assert(kFftFrameSize > kNumInvertedLags12kHz + kConvolutionLength,
+ "The FFT length is not sufficiently big to avoid cyclic "
+ "convolution errors.");
+ auto tmp = tmp_->GetView();
+
+ // Compute the FFT for the reversed reference frame - i.e.,
+ // pitch_buf[-kConvolutionLength:].
+ std::reverse_copy(pitch_buf.end() - kConvolutionLength, pitch_buf.end(),
+ tmp.begin());
+ std::fill(tmp.begin() + kConvolutionLength, tmp.end(), 0.f);
+ fft_.ForwardTransform(*tmp_, H_.get(), /*ordered=*/false);
+
+ // Compute the FFT for the sliding frames chunk. The sliding frames are
+ // defined as pitch_buf[i:i+kConvolutionLength] where i in
+ // [0, kNumInvertedLags12kHz). The chunk includes all of them, hence it is
+ // defined as pitch_buf[:kNumInvertedLags12kHz+kConvolutionLength].
+ std::copy(pitch_buf.begin(),
+ pitch_buf.begin() + kConvolutionLength + kNumInvertedLags12kHz,
+ tmp.begin());
+ std::fill(tmp.begin() + kNumInvertedLags12kHz + kConvolutionLength, tmp.end(),
+ 0.f);
+ fft_.ForwardTransform(*tmp_, X_.get(), /*ordered=*/false);
+
+ // Convolve in the frequency domain.
+ constexpr float kScalingFactor = 1.f / static_cast<float>(kFftFrameSize);
+ std::fill(tmp.begin(), tmp.end(), 0.f);
+ fft_.FrequencyDomainConvolve(*X_, *H_, tmp_.get(), kScalingFactor);
+ fft_.BackwardTransform(*tmp_, tmp_.get(), /*ordered=*/false);
+
+ // Extract the auto-correlation coefficients.
+ std::copy(tmp.begin() + kConvolutionLength - 1,
+ tmp.begin() + kConvolutionLength + kNumInvertedLags12kHz - 1,
+ auto_corr.begin());
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.h b/webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.h
new file mode 100644
index 0000000..de7f453
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/auto_correlation.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_AUTO_CORRELATION_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_AUTO_CORRELATION_H_
+
+#include <memory>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/utility/pffft_wrapper.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Class to compute the auto correlation on the pitch buffer for a target pitch
+// interval.
+class AutoCorrelationCalculator {
+ public:
+ AutoCorrelationCalculator();
+ AutoCorrelationCalculator(const AutoCorrelationCalculator&) = delete;
+ AutoCorrelationCalculator& operator=(const AutoCorrelationCalculator&) =
+ delete;
+ ~AutoCorrelationCalculator();
+
+ // Computes the auto-correlation coefficients for a target pitch interval.
+ // |auto_corr| indexes are inverted lags.
+ void ComputeOnPitchBuffer(
+ rtc::ArrayView<const float, kBufSize12kHz> pitch_buf,
+ rtc::ArrayView<float, kNumInvertedLags12kHz> auto_corr);
+
+ private:
+ Pffft fft_;
+ std::unique_ptr<Pffft::FloatBuffer> tmp_;
+ std::unique_ptr<Pffft::FloatBuffer> X_;
+ std::unique_ptr<Pffft::FloatBuffer> H_;
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_AUTO_CORRELATION_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/common.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/common.cc
new file mode 100644
index 0000000..5d76b52
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/common.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+
+#include "rtc_base/system/arch.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+Optimization DetectOptimization() {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ if (GetCPUInfo(kSSE2) != 0) {
+ return Optimization::kSse2;
+ }
+#endif
+
+#if defined(WEBRTC_HAS_NEON)
+ return Optimization::kNeon;
+#endif
+
+ return Optimization::kNone;
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/common.h b/webrtc/modules/audio_processing/agc2/rnn_vad/common.h
new file mode 100644
index 0000000..c2e8df6
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/common.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_COMMON_H_
+
+#include <stddef.h>
+
+namespace webrtc {
+namespace rnn_vad {
+
+constexpr double kPi = 3.14159265358979323846;
+
+constexpr size_t kSampleRate24kHz = 24000;
+constexpr size_t kFrameSize10ms24kHz = kSampleRate24kHz / 100;
+constexpr size_t kFrameSize20ms24kHz = kFrameSize10ms24kHz * 2;
+
+// Pitch buffer.
+constexpr size_t kMinPitch24kHz = kSampleRate24kHz / 800; // 0.00125 s.
+constexpr size_t kMaxPitch24kHz = kSampleRate24kHz / 62.5; // 0.016 s.
+constexpr size_t kBufSize24kHz = kMaxPitch24kHz + kFrameSize20ms24kHz;
+static_assert((kBufSize24kHz & 1) == 0, "The buffer size must be even.");
+
+// 24 kHz analysis.
+// Define a higher minimum pitch period for the initial search. This is used to
+// avoid searching for very short periods, for which a refinement step is
+// responsible.
+constexpr size_t kInitialMinPitch24kHz = 3 * kMinPitch24kHz;
+static_assert(kMinPitch24kHz < kInitialMinPitch24kHz, "");
+static_assert(kInitialMinPitch24kHz < kMaxPitch24kHz, "");
+static_assert(kMaxPitch24kHz > kInitialMinPitch24kHz, "");
+constexpr size_t kNumInvertedLags24kHz = kMaxPitch24kHz - kInitialMinPitch24kHz;
+
+// 12 kHz analysis.
+constexpr size_t kSampleRate12kHz = 12000;
+constexpr size_t kFrameSize10ms12kHz = kSampleRate12kHz / 100;
+constexpr size_t kFrameSize20ms12kHz = kFrameSize10ms12kHz * 2;
+constexpr size_t kBufSize12kHz = kBufSize24kHz / 2;
+constexpr size_t kInitialMinPitch12kHz = kInitialMinPitch24kHz / 2;
+constexpr size_t kMaxPitch12kHz = kMaxPitch24kHz / 2;
+static_assert(kMaxPitch12kHz > kInitialMinPitch12kHz, "");
+// The inverted lags for the pitch interval [|kInitialMinPitch12kHz|,
+// |kMaxPitch12kHz|] are in the range [0, |kNumInvertedLags12kHz|].
+constexpr size_t kNumInvertedLags12kHz = kMaxPitch12kHz - kInitialMinPitch12kHz;
+
+// 48 kHz constants.
+constexpr size_t kMinPitch48kHz = kMinPitch24kHz * 2;
+constexpr size_t kMaxPitch48kHz = kMaxPitch24kHz * 2;
+
+// Spectral features.
+constexpr size_t kNumBands = 22;
+constexpr size_t kNumLowerBands = 6;
+static_assert((0 < kNumLowerBands) && (kNumLowerBands < kNumBands), "");
+constexpr size_t kCepstralCoeffsHistorySize = 8;
+static_assert(kCepstralCoeffsHistorySize > 2,
+ "The history size must at least be 3 to compute first and second "
+ "derivatives.");
+
+constexpr size_t kFeatureVectorSize = 42;
+
+enum class Optimization { kNone, kSse2, kNeon };
+
+// Detects what kind of optimizations to use for the code.
+Optimization DetectOptimization();
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_COMMON_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.cc
new file mode 100644
index 0000000..e935179
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/features_extraction.h"
+
+#include <array>
+
+#include "modules/audio_processing/agc2/rnn_vad/lp_residual.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+// Generated via "B, A = scipy.signal.butter(2, 30/12000, btype='highpass')"
+const BiQuadFilter::BiQuadCoefficients kHpfConfig24k = {
+ {0.99446179f, -1.98892358f, 0.99446179f},
+ {-1.98889291f, 0.98895425f}};
+
+} // namespace
+
+FeaturesExtractor::FeaturesExtractor()
+ : use_high_pass_filter_(false),
+ pitch_buf_24kHz_(),
+ pitch_buf_24kHz_view_(pitch_buf_24kHz_.GetBufferView()),
+ lp_residual_(kBufSize24kHz),
+ lp_residual_view_(lp_residual_.data(), kBufSize24kHz),
+ pitch_estimator_(),
+ reference_frame_view_(pitch_buf_24kHz_.GetMostRecentValuesView()) {
+ RTC_DCHECK_EQ(kBufSize24kHz, lp_residual_.size());
+ hpf_.Initialize(kHpfConfig24k);
+ Reset();
+}
+
+FeaturesExtractor::~FeaturesExtractor() = default;
+
+void FeaturesExtractor::Reset() {
+ pitch_buf_24kHz_.Reset();
+ spectral_features_extractor_.Reset();
+ if (use_high_pass_filter_)
+ hpf_.Reset();
+}
+
+bool FeaturesExtractor::CheckSilenceComputeFeatures(
+ rtc::ArrayView<const float, kFrameSize10ms24kHz> samples,
+ rtc::ArrayView<float, kFeatureVectorSize> feature_vector) {
+ // Pre-processing.
+ if (use_high_pass_filter_) {
+ std::array<float, kFrameSize10ms24kHz> samples_filtered;
+ hpf_.Process(samples, samples_filtered);
+ // Feed buffer with the pre-processed version of |samples|.
+ pitch_buf_24kHz_.Push(samples_filtered);
+ } else {
+ // Feed buffer with |samples|.
+ pitch_buf_24kHz_.Push(samples);
+ }
+ // Extract the LP residual.
+ float lpc_coeffs[kNumLpcCoefficients];
+ ComputeAndPostProcessLpcCoefficients(pitch_buf_24kHz_view_, lpc_coeffs);
+ ComputeLpResidual(lpc_coeffs, pitch_buf_24kHz_view_, lp_residual_view_);
+ // Estimate pitch on the LP-residual and write the normalized pitch period
+ // into the output vector (normalization based on training data stats).
+ pitch_info_48kHz_ = pitch_estimator_.Estimate(lp_residual_view_);
+ feature_vector[kFeatureVectorSize - 2] =
+ 0.01f * (static_cast<int>(pitch_info_48kHz_.period) - 300);
+ // Extract lagged frames (according to the estimated pitch period).
+ RTC_DCHECK_LE(pitch_info_48kHz_.period / 2, kMaxPitch24kHz);
+ auto lagged_frame = pitch_buf_24kHz_view_.subview(
+ kMaxPitch24kHz - pitch_info_48kHz_.period / 2, kFrameSize20ms24kHz);
+ // Analyze reference and lagged frames checking if silence has been detected
+ // and write the feature vector.
+ return spectral_features_extractor_.CheckSilenceComputeFeatures(
+ reference_frame_view_, {lagged_frame.data(), kFrameSize20ms24kHz},
+ {feature_vector.data() + kNumLowerBands, kNumBands - kNumLowerBands},
+ {feature_vector.data(), kNumLowerBands},
+ {feature_vector.data() + kNumBands, kNumLowerBands},
+ {feature_vector.data() + kNumBands + kNumLowerBands, kNumLowerBands},
+ {feature_vector.data() + kNumBands + 2 * kNumLowerBands, kNumLowerBands},
+ &feature_vector[kFeatureVectorSize - 1]);
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.h b/webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.h
new file mode 100644
index 0000000..ce5cce1
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/features_extraction.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/biquad_filter.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_info.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_search.h"
+#include "modules/audio_processing/agc2/rnn_vad/sequence_buffer.h"
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Feature extractor to feed the VAD RNN.
+class FeaturesExtractor {
+ public:
+ FeaturesExtractor();
+ FeaturesExtractor(const FeaturesExtractor&) = delete;
+ FeaturesExtractor& operator=(const FeaturesExtractor&) = delete;
+ ~FeaturesExtractor();
+ void Reset();
+ // Analyzes the samples, computes the feature vector and returns true if
+ // silence is detected (false if not). When silence is detected,
+ // |feature_vector| is partially written and therefore must not be used to
+ // feed the VAD RNN.
+ bool CheckSilenceComputeFeatures(
+ rtc::ArrayView<const float, kFrameSize10ms24kHz> samples,
+ rtc::ArrayView<float, kFeatureVectorSize> feature_vector);
+
+ private:
+ const bool use_high_pass_filter_;
+ // TODO(bugs.webrtc.org/7494): Remove HPF depending on how AGC2 is used in APM
+ // and on whether an HPF is already used as pre-processing step in APM.
+ BiQuadFilter hpf_;
+ SequenceBuffer<float, kBufSize24kHz, kFrameSize10ms24kHz, kFrameSize20ms24kHz>
+ pitch_buf_24kHz_;
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf_24kHz_view_;
+ std::vector<float> lp_residual_;
+ rtc::ArrayView<float, kBufSize24kHz> lp_residual_view_;
+ PitchEstimator pitch_estimator_;
+ rtc::ArrayView<const float, kFrameSize20ms24kHz> reference_frame_view_;
+ SpectralFeaturesExtractor spectral_features_extractor_;
+ PitchInfo pitch_info_48kHz_;
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_FEATURES_EXTRACTION_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.cc
new file mode 100644
index 0000000..1a124a3
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.cc
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/lp_residual.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <numeric>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+// Computes cross-correlation coefficients between |x| and |y| and writes them
+// in |x_corr|. The lag values are in {0, ..., max_lag - 1}, where max_lag
+// equals the size of |x_corr|.
+// The |x| and |y| sub-arrays used to compute a cross-correlation coefficients
+// for a lag l have both size "size of |x| - l" - i.e., the longest sub-array is
+// used. |x| and |y| must have the same size.
+void ComputeCrossCorrelation(
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float, kNumLpcCoefficients> x_corr) {
+ constexpr size_t max_lag = x_corr.size();
+ RTC_DCHECK_EQ(x.size(), y.size());
+ RTC_DCHECK_LT(max_lag, x.size());
+ for (size_t lag = 0; lag < max_lag; ++lag) {
+ x_corr[lag] =
+ std::inner_product(x.begin(), x.end() - lag, y.begin() + lag, 0.f);
+ }
+}
+
+// Applies denoising to the auto-correlation coefficients.
+void DenoiseAutoCorrelation(
+ rtc::ArrayView<float, kNumLpcCoefficients> auto_corr) {
+ // Assume -40 dB white noise floor.
+ auto_corr[0] *= 1.0001f;
+ for (size_t i = 1; i < kNumLpcCoefficients; ++i) {
+ auto_corr[i] -= auto_corr[i] * (0.008f * i) * (0.008f * i);
+ }
+}
+
+// Computes the initial inverse filter coefficients given the auto-correlation
+// coefficients of an input frame.
+void ComputeInitialInverseFilterCoefficients(
+ rtc::ArrayView<const float, kNumLpcCoefficients> auto_corr,
+ rtc::ArrayView<float, kNumLpcCoefficients - 1> lpc_coeffs) {
+ float error = auto_corr[0];
+ for (size_t i = 0; i < kNumLpcCoefficients - 1; ++i) {
+ float reflection_coeff = 0.f;
+ for (size_t j = 0; j < i; ++j) {
+ reflection_coeff += lpc_coeffs[j] * auto_corr[i - j];
+ }
+ reflection_coeff += auto_corr[i + 1];
+
+ // Avoid division by numbers close to zero.
+ constexpr float kMinErrorMagnitude = 1e-6f;
+ if (std::fabs(error) < kMinErrorMagnitude) {
+ error = std::copysign(kMinErrorMagnitude, error);
+ }
+
+ reflection_coeff /= -error;
+ // Update LPC coefficients and total error.
+ lpc_coeffs[i] = reflection_coeff;
+ for (size_t j = 0; j<(i + 1)>> 1; ++j) {
+ const float tmp1 = lpc_coeffs[j];
+ const float tmp2 = lpc_coeffs[i - 1 - j];
+ lpc_coeffs[j] = tmp1 + reflection_coeff * tmp2;
+ lpc_coeffs[i - 1 - j] = tmp2 + reflection_coeff * tmp1;
+ }
+ error -= reflection_coeff * reflection_coeff * error;
+ if (error < 0.001f * auto_corr[0]) {
+ break;
+ }
+ }
+}
+
+} // namespace
+
+void ComputeAndPostProcessLpcCoefficients(
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<float, kNumLpcCoefficients> lpc_coeffs) {
+ std::array<float, kNumLpcCoefficients> auto_corr;
+ ComputeCrossCorrelation(x, x, {auto_corr.data(), auto_corr.size()});
+ if (auto_corr[0] == 0.f) { // Empty frame.
+ std::fill(lpc_coeffs.begin(), lpc_coeffs.end(), 0);
+ return;
+ }
+ DenoiseAutoCorrelation({auto_corr.data(), auto_corr.size()});
+ std::array<float, kNumLpcCoefficients - 1> lpc_coeffs_pre{};
+ ComputeInitialInverseFilterCoefficients(auto_corr, lpc_coeffs_pre);
+ // LPC coefficients post-processing.
+ // TODO(bugs.webrtc.org/9076): Consider removing these steps.
+ float c1 = 1.f;
+ for (size_t i = 0; i < kNumLpcCoefficients - 1; ++i) {
+ c1 *= 0.9f;
+ lpc_coeffs_pre[i] *= c1;
+ }
+ const float c2 = 0.8f;
+ lpc_coeffs[0] = lpc_coeffs_pre[0] + c2;
+ lpc_coeffs[1] = lpc_coeffs_pre[1] + c2 * lpc_coeffs_pre[0];
+ lpc_coeffs[2] = lpc_coeffs_pre[2] + c2 * lpc_coeffs_pre[1];
+ lpc_coeffs[3] = lpc_coeffs_pre[3] + c2 * lpc_coeffs_pre[2];
+ lpc_coeffs[4] = c2 * lpc_coeffs_pre[3];
+}
+
+void ComputeLpResidual(
+ rtc::ArrayView<const float, kNumLpcCoefficients> lpc_coeffs,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> y) {
+ RTC_DCHECK_LT(kNumLpcCoefficients, x.size());
+ RTC_DCHECK_EQ(x.size(), y.size());
+ std::array<float, kNumLpcCoefficients> input_chunk;
+ input_chunk.fill(0.f);
+ for (size_t i = 0; i < y.size(); ++i) {
+ const float sum = std::inner_product(input_chunk.begin(), input_chunk.end(),
+ lpc_coeffs.begin(), x[i]);
+ // Circular shift and add a new sample.
+ for (size_t j = kNumLpcCoefficients - 1; j > 0; --j)
+ input_chunk[j] = input_chunk[j - 1];
+ input_chunk[0] = x[i];
+ // Copy result.
+ y[i] = sum;
+ }
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.h b/webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.h
new file mode 100644
index 0000000..cddedca
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/lp_residual.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_LP_RESIDUAL_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_LP_RESIDUAL_H_
+
+#include <stddef.h>
+
+#include "api/array_view.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// LPC inverse filter length.
+constexpr size_t kNumLpcCoefficients = 5;
+
+// Given a frame |x|, computes a post-processed version of LPC coefficients
+// tailored for pitch estimation.
+void ComputeAndPostProcessLpcCoefficients(
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<float, kNumLpcCoefficients> lpc_coeffs);
+
+// Computes the LP residual for the input frame |x| and the LPC coefficients
+// |lpc_coeffs|. |y| and |x| can point to the same array for in-place
+// computation.
+void ComputeLpResidual(
+ rtc::ArrayView<const float, kNumLpcCoefficients> lpc_coeffs,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> y);
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_LP_RESIDUAL_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_info.h b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_info.h
new file mode 100644
index 0000000..c9fdd18
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_info.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_INFO_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_INFO_H_
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Stores pitch period and gain information. The pitch gain measures the
+// strength of the pitch (the higher, the stronger).
+struct PitchInfo {
+ PitchInfo() : period(0), gain(0.f) {}
+ PitchInfo(int p, float g) : period(p), gain(g) {}
+ int period;
+ float gain;
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_INFO_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.cc
new file mode 100644
index 0000000..1b3b459
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/pitch_search.h"
+
+#include <array>
+#include <cstddef>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+PitchEstimator::PitchEstimator()
+ : pitch_buf_decimated_(kBufSize12kHz),
+ pitch_buf_decimated_view_(pitch_buf_decimated_.data(), kBufSize12kHz),
+ auto_corr_(kNumInvertedLags12kHz),
+ auto_corr_view_(auto_corr_.data(), kNumInvertedLags12kHz) {
+ RTC_DCHECK_EQ(kBufSize12kHz, pitch_buf_decimated_.size());
+ RTC_DCHECK_EQ(kNumInvertedLags12kHz, auto_corr_view_.size());
+}
+
+PitchEstimator::~PitchEstimator() = default;
+
+PitchInfo PitchEstimator::Estimate(
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf) {
+ // Perform the initial pitch search at 12 kHz.
+ Decimate2x(pitch_buf, pitch_buf_decimated_view_);
+ auto_corr_calculator_.ComputeOnPitchBuffer(pitch_buf_decimated_view_,
+ auto_corr_view_);
+ std::array<size_t, 2> pitch_candidates_inv_lags = FindBestPitchPeriods(
+ auto_corr_view_, pitch_buf_decimated_view_, kMaxPitch12kHz);
+ // Refine the pitch period estimation.
+ // The refinement is done using the pitch buffer that contains 24 kHz samples.
+ // Therefore, adapt the inverted lags in |pitch_candidates_inv_lags| from 12
+ // to 24 kHz.
+ pitch_candidates_inv_lags[0] *= 2;
+ pitch_candidates_inv_lags[1] *= 2;
+ size_t pitch_inv_lag_48kHz =
+ RefinePitchPeriod48kHz(pitch_buf, pitch_candidates_inv_lags);
+ // Look for stronger harmonics to find the final pitch period and its gain.
+ RTC_DCHECK_LT(pitch_inv_lag_48kHz, kMaxPitch48kHz);
+ last_pitch_48kHz_ = CheckLowerPitchPeriodsAndComputePitchGain(
+ pitch_buf, kMaxPitch48kHz - pitch_inv_lag_48kHz, last_pitch_48kHz_);
+ return last_pitch_48kHz_;
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.h b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.h
new file mode 100644
index 0000000..74133d0
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/auto_correlation.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_info.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Pitch estimator.
+class PitchEstimator {
+ public:
+ PitchEstimator();
+ PitchEstimator(const PitchEstimator&) = delete;
+ PitchEstimator& operator=(const PitchEstimator&) = delete;
+ ~PitchEstimator();
+ // Estimates the pitch period and gain. Returns the pitch estimation data for
+ // 48 kHz.
+ PitchInfo Estimate(rtc::ArrayView<const float, kBufSize24kHz> pitch_buf);
+
+ private:
+ PitchInfo last_pitch_48kHz_;
+ AutoCorrelationCalculator auto_corr_calculator_;
+ std::vector<float> pitch_buf_decimated_;
+ rtc::ArrayView<float, kBufSize12kHz> pitch_buf_decimated_view_;
+ std::vector<float> auto_corr_;
+ rtc::ArrayView<float, kNumInvertedLags12kHz> auto_corr_view_;
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc
new file mode 100644
index 0000000..f24a76f
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h"
+
+#include <stdlib.h>
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <numeric>
+
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+// Converts a lag to an inverted lag (only for 24kHz).
+size_t GetInvertedLag(size_t lag) {
+ RTC_DCHECK_LE(lag, kMaxPitch24kHz);
+ return kMaxPitch24kHz - lag;
+}
+
+float ComputeAutoCorrelationCoeff(rtc::ArrayView<const float> pitch_buf,
+ size_t inv_lag,
+ size_t max_pitch_period) {
+ RTC_DCHECK_LT(inv_lag, pitch_buf.size());
+ RTC_DCHECK_LT(max_pitch_period, pitch_buf.size());
+ RTC_DCHECK_LE(inv_lag, max_pitch_period);
+ // TODO(bugs.webrtc.org/9076): Maybe optimize using vectorization.
+ return std::inner_product(pitch_buf.begin() + max_pitch_period,
+ pitch_buf.end(), pitch_buf.begin() + inv_lag, 0.f);
+}
+
+// Computes a pseudo-interpolation offset for an estimated pitch period |lag| by
+// looking at the auto-correlation coefficients in the neighborhood of |lag|.
+// (namely, |prev_auto_corr|, |lag_auto_corr| and |next_auto_corr|). The output
+// is a lag in {-1, 0, +1}.
+// TODO(bugs.webrtc.org/9076): Consider removing pseudo-i since it
+// is relevant only if the spectral analysis works at a sample rate that is
+// twice as that of the pitch buffer (not so important instead for the estimated
+// pitch period feature fed into the RNN).
+int GetPitchPseudoInterpolationOffset(size_t lag,
+ float prev_auto_corr,
+ float lag_auto_corr,
+ float next_auto_corr) {
+ const float& a = prev_auto_corr;
+ const float& b = lag_auto_corr;
+ const float& c = next_auto_corr;
+
+ int offset = 0;
+ if ((c - a) > 0.7f * (b - a)) {
+ offset = 1; // |c| is the largest auto-correlation coefficient.
+ } else if ((a - c) > 0.7f * (b - c)) {
+ offset = -1; // |a| is the largest auto-correlation coefficient.
+ }
+ return offset;
+}
+
+// Refines a pitch period |lag| encoded as lag with pseudo-interpolation. The
+// output sample rate is twice as that of |lag|.
+size_t PitchPseudoInterpolationLagPitchBuf(
+ size_t lag,
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf) {
+ int offset = 0;
+ // Cannot apply pseudo-interpolation at the boundaries.
+ if (lag > 0 && lag < kMaxPitch24kHz) {
+ offset = GetPitchPseudoInterpolationOffset(
+ lag,
+ ComputeAutoCorrelationCoeff(pitch_buf, GetInvertedLag(lag - 1),
+ kMaxPitch24kHz),
+ ComputeAutoCorrelationCoeff(pitch_buf, GetInvertedLag(lag),
+ kMaxPitch24kHz),
+ ComputeAutoCorrelationCoeff(pitch_buf, GetInvertedLag(lag + 1),
+ kMaxPitch24kHz));
+ }
+ return 2 * lag + offset;
+}
+
+// Refines a pitch period |inv_lag| encoded as inverted lag with
+// pseudo-interpolation. The output sample rate is twice as that of
+// |inv_lag|.
+size_t PitchPseudoInterpolationInvLagAutoCorr(
+ size_t inv_lag,
+ rtc::ArrayView<const float> auto_corr) {
+ int offset = 0;
+ // Cannot apply pseudo-interpolation at the boundaries.
+ if (inv_lag > 0 && inv_lag < auto_corr.size() - 1) {
+ offset = GetPitchPseudoInterpolationOffset(inv_lag, auto_corr[inv_lag + 1],
+ auto_corr[inv_lag],
+ auto_corr[inv_lag - 1]);
+ }
+ // TODO(bugs.webrtc.org/9076): When retraining, check if |offset| below should
+ // be subtracted since |inv_lag| is an inverted lag but offset is a lag.
+ return 2 * inv_lag + offset;
+}
+
+// Integer multipliers used in CheckLowerPitchPeriodsAndComputePitchGain() when
+// looking for sub-harmonics.
+// The values have been chosen to serve the following algorithm. Given the
+// initial pitch period T, we examine whether one of its harmonics is the true
+// fundamental frequency. We consider T/k with k in {2, ..., 15}. For each of
+// these harmonics, in addition to the pitch gain of itself, we choose one
+// multiple of its pitch period, n*T/k, to validate it (by averaging their pitch
+// gains). The multiplier n is chosen so that n*T/k is used only one time over
+// all k. When for example k = 4, we should also expect a peak at 3*T/4. When
+// k = 8 instead we don't want to look at 2*T/8, since we have already checked
+// T/4 before. Instead, we look at T*3/8.
+// The array can be generate in Python as follows:
+// from fractions import Fraction
+// # Smallest positive integer not in X.
+// def mex(X):
+// for i in range(1, int(max(X)+2)):
+// if i not in X:
+// return i
+// # Visited multiples of the period.
+// S = {1}
+// for n in range(2, 16):
+// sn = mex({n * i for i in S} | {1})
+// S = S | {Fraction(1, n), Fraction(sn, n)}
+// print(sn, end=', ')
+constexpr std::array<int, 14> kSubHarmonicMultipliers = {
+ {3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}};
+
+// Initial pitch period candidate thresholds for ComputePitchGainThreshold() for
+// a sample rate of 24 kHz. Computed as [5*k*k for k in range(16)].
+constexpr std::array<int, 14> kInitialPitchPeriodThresholds = {
+ {20, 45, 80, 125, 180, 245, 320, 405, 500, 605, 720, 845, 980, 1125}};
+
+} // namespace
+
+void Decimate2x(rtc::ArrayView<const float, kBufSize24kHz> src,
+ rtc::ArrayView<float, kBufSize12kHz> dst) {
+ // TODO(bugs.webrtc.org/9076): Consider adding anti-aliasing filter.
+ static_assert(2 * dst.size() == src.size(), "");
+ for (size_t i = 0; i < dst.size(); ++i) {
+ dst[i] = src[2 * i];
+ }
+}
+
+float ComputePitchGainThreshold(int candidate_pitch_period,
+ int pitch_period_ratio,
+ int initial_pitch_period,
+ float initial_pitch_gain,
+ int prev_pitch_period,
+ float prev_pitch_gain) {
+ // Map arguments to more compact aliases.
+ const int& t1 = candidate_pitch_period;
+ const int& k = pitch_period_ratio;
+ const int& t0 = initial_pitch_period;
+ const float& g0 = initial_pitch_gain;
+ const int& t_prev = prev_pitch_period;
+ const float& g_prev = prev_pitch_gain;
+
+ // Validate input.
+ RTC_DCHECK_GE(t1, 0);
+ RTC_DCHECK_GE(k, 2);
+ RTC_DCHECK_GE(t0, 0);
+ RTC_DCHECK_GE(t_prev, 0);
+
+ // Compute a term that lowers the threshold when |t1| is close to the last
+ // estimated period |t_prev| - i.e., pitch tracking.
+ float lower_threshold_term = 0;
+ if (abs(t1 - t_prev) <= 1) {
+ // The candidate pitch period is within 1 sample from the previous one.
+ // Make the candidate at |t1| very easy to be accepted.
+ lower_threshold_term = g_prev;
+ } else if (abs(t1 - t_prev) == 2 &&
+ t0 > kInitialPitchPeriodThresholds[k - 2]) {
+ // The candidate pitch period is 2 samples far from the previous one and the
+ // period |t0| (from which |t1| has been derived) is greater than a
+ // threshold. Make |t1| easy to be accepted.
+ lower_threshold_term = 0.5f * g_prev;
+ }
+ // Set the threshold based on the gain of the initial estimate |t0|. Also
+ // reduce the chance of false positives caused by a bias towards high
+ // frequencies (originating from short-term correlations).
+ float threshold = std::max(0.3f, 0.7f * g0 - lower_threshold_term);
+ if (static_cast<size_t>(t1) < 3 * kMinPitch24kHz) {
+ // High frequency.
+ threshold = std::max(0.4f, 0.85f * g0 - lower_threshold_term);
+ } else if (static_cast<size_t>(t1) < 2 * kMinPitch24kHz) {
+ // Even higher frequency.
+ threshold = std::max(0.5f, 0.9f * g0 - lower_threshold_term);
+ }
+ return threshold;
+}
+
+void ComputeSlidingFrameSquareEnergies(
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
+ rtc::ArrayView<float, kMaxPitch24kHz + 1> yy_values) {
+ float yy =
+ ComputeAutoCorrelationCoeff(pitch_buf, kMaxPitch24kHz, kMaxPitch24kHz);
+ yy_values[0] = yy;
+ for (size_t i = 1; i < yy_values.size(); ++i) {
+ RTC_DCHECK_LE(i, kMaxPitch24kHz + kFrameSize20ms24kHz);
+ RTC_DCHECK_LE(i, kMaxPitch24kHz);
+ const float old_coeff = pitch_buf[kMaxPitch24kHz + kFrameSize20ms24kHz - i];
+ const float new_coeff = pitch_buf[kMaxPitch24kHz - i];
+ yy -= old_coeff * old_coeff;
+ yy += new_coeff * new_coeff;
+ yy = std::max(0.f, yy);
+ yy_values[i] = yy;
+ }
+}
+
+std::array<size_t, 2> FindBestPitchPeriods(
+ rtc::ArrayView<const float> auto_corr,
+ rtc::ArrayView<const float> pitch_buf,
+ size_t max_pitch_period) {
+ // Stores a pitch candidate period and strength information.
+ struct PitchCandidate {
+ // Pitch period encoded as inverted lag.
+ size_t period_inverted_lag = 0;
+ // Pitch strength encoded as a ratio.
+ float strength_numerator = -1.f;
+ float strength_denominator = 0.f;
+ // Compare the strength of two pitch candidates.
+ bool HasStrongerPitchThan(const PitchCandidate& b) const {
+ // Comparing the numerator/denominator ratios without using divisions.
+ return strength_numerator * b.strength_denominator >
+ b.strength_numerator * strength_denominator;
+ }
+ };
+
+ RTC_DCHECK_GT(max_pitch_period, auto_corr.size());
+ RTC_DCHECK_LT(max_pitch_period, pitch_buf.size());
+ const size_t frame_size = pitch_buf.size() - max_pitch_period;
+ // TODO(bugs.webrtc.org/9076): Maybe optimize using vectorization.
+ float yy =
+ std::inner_product(pitch_buf.begin(), pitch_buf.begin() + frame_size + 1,
+ pitch_buf.begin(), 1.f);
+ // Search best and second best pitches by looking at the scaled
+ // auto-correlation.
+ PitchCandidate candidate;
+ PitchCandidate best;
+ PitchCandidate second_best;
+ second_best.period_inverted_lag = 1;
+ for (size_t inv_lag = 0; inv_lag < auto_corr.size(); ++inv_lag) {
+ // A pitch candidate must have positive correlation.
+ if (auto_corr[inv_lag] > 0) {
+ candidate.period_inverted_lag = inv_lag;
+ candidate.strength_numerator = auto_corr[inv_lag] * auto_corr[inv_lag];
+ candidate.strength_denominator = yy;
+ if (candidate.HasStrongerPitchThan(second_best)) {
+ if (candidate.HasStrongerPitchThan(best)) {
+ second_best = best;
+ best = candidate;
+ } else {
+ second_best = candidate;
+ }
+ }
+ }
+ // Update |squared_energy_y| for the next inverted lag.
+ const float old_coeff = pitch_buf[inv_lag];
+ const float new_coeff = pitch_buf[inv_lag + frame_size];
+ yy -= old_coeff * old_coeff;
+ yy += new_coeff * new_coeff;
+ yy = std::max(0.f, yy);
+ }
+ return {{best.period_inverted_lag, second_best.period_inverted_lag}};
+}
+
+size_t RefinePitchPeriod48kHz(
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
+ rtc::ArrayView<const size_t, 2> inv_lags) {
+ // Compute the auto-correlation terms only for neighbors of the given pitch
+ // candidates (similar to what is done in ComputePitchAutoCorrelation(), but
+ // for a few lag values).
+ std::array<float, kNumInvertedLags24kHz> auto_corr;
+ auto_corr.fill(0.f); // Zeros become ignored lags in FindBestPitchPeriods().
+ auto is_neighbor = [](size_t i, size_t j) {
+ return ((i > j) ? (i - j) : (j - i)) <= 2;
+ };
+ for (size_t inv_lag = 0; inv_lag < auto_corr.size(); ++inv_lag) {
+ if (is_neighbor(inv_lag, inv_lags[0]) || is_neighbor(inv_lag, inv_lags[1]))
+ auto_corr[inv_lag] =
+ ComputeAutoCorrelationCoeff(pitch_buf, inv_lag, kMaxPitch24kHz);
+ }
+ // Find best pitch at 24 kHz.
+ const auto pitch_candidates_inv_lags = FindBestPitchPeriods(
+ {auto_corr.data(), auto_corr.size()},
+ {pitch_buf.data(), pitch_buf.size()}, kMaxPitch24kHz);
+ const auto inv_lag = pitch_candidates_inv_lags[0]; // Refine the best.
+ // Pseudo-interpolation.
+ return PitchPseudoInterpolationInvLagAutoCorr(inv_lag, auto_corr);
+}
+
+PitchInfo CheckLowerPitchPeriodsAndComputePitchGain(
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
+ int initial_pitch_period_48kHz,
+ PitchInfo prev_pitch_48kHz) {
+ RTC_DCHECK_LE(kMinPitch48kHz, initial_pitch_period_48kHz);
+ RTC_DCHECK_LE(initial_pitch_period_48kHz, kMaxPitch48kHz);
+ // Stores information for a refined pitch candidate.
+ struct RefinedPitchCandidate {
+ RefinedPitchCandidate() {}
+ RefinedPitchCandidate(int period_24kHz, float gain, float xy, float yy)
+ : period_24kHz(period_24kHz), gain(gain), xy(xy), yy(yy) {}
+ int period_24kHz;
+ // Pitch strength information.
+ float gain;
+ // Additional pitch strength information used for the final estimation of
+ // pitch gain.
+ float xy; // Cross-correlation.
+ float yy; // Auto-correlation.
+ };
+
+ // Initialize.
+ std::array<float, kMaxPitch24kHz + 1> yy_values;
+ ComputeSlidingFrameSquareEnergies(pitch_buf,
+ {yy_values.data(), yy_values.size()});
+ const float xx = yy_values[0];
+ // Helper lambdas.
+ const auto pitch_gain = [](float xy, float yy, float xx) {
+ RTC_DCHECK_LE(0.f, xx * yy);
+ return xy / std::sqrt(1.f + xx * yy);
+ };
+ // Initial pitch candidate gain.
+ RefinedPitchCandidate best_pitch;
+ best_pitch.period_24kHz = std::min(initial_pitch_period_48kHz / 2,
+ static_cast<int>(kMaxPitch24kHz - 1));
+ best_pitch.xy = ComputeAutoCorrelationCoeff(
+ pitch_buf, GetInvertedLag(best_pitch.period_24kHz), kMaxPitch24kHz);
+ best_pitch.yy = yy_values[best_pitch.period_24kHz];
+ best_pitch.gain = pitch_gain(best_pitch.xy, best_pitch.yy, xx);
+
+ // Store the initial pitch period information.
+ const size_t initial_pitch_period = best_pitch.period_24kHz;
+ const float initial_pitch_gain = best_pitch.gain;
+
+ // Given the initial pitch estimation, check lower periods (i.e., harmonics).
+ const auto alternative_period = [](int period, int k, int n) -> int {
+ RTC_DCHECK_GT(k, 0);
+ return (2 * n * period + k) / (2 * k); // Same as round(n*period/k).
+ };
+ for (int k = 2; k < static_cast<int>(kSubHarmonicMultipliers.size() + 2);
+ ++k) {
+ int candidate_pitch_period = alternative_period(initial_pitch_period, k, 1);
+ if (static_cast<size_t>(candidate_pitch_period) < kMinPitch24kHz) {
+ break;
+ }
+ // When looking at |candidate_pitch_period|, we also look at one of its
+ // sub-harmonics. |kSubHarmonicMultipliers| is used to know where to look.
+ // |k| == 2 is a special case since |candidate_pitch_secondary_period| might
+ // be greater than the maximum pitch period.
+ int candidate_pitch_secondary_period = alternative_period(
+ initial_pitch_period, k, kSubHarmonicMultipliers[k - 2]);
+ RTC_DCHECK_GT(candidate_pitch_secondary_period, 0);
+ if (k == 2 &&
+ candidate_pitch_secondary_period > static_cast<int>(kMaxPitch24kHz)) {
+ candidate_pitch_secondary_period = initial_pitch_period;
+ }
+ RTC_DCHECK_NE(candidate_pitch_period, candidate_pitch_secondary_period)
+ << "The lower pitch period and the additional sub-harmonic must not "
+ "coincide.";
+ // Compute an auto-correlation score for the primary pitch candidate
+ // |candidate_pitch_period| by also looking at its possible sub-harmonic
+ // |candidate_pitch_secondary_period|.
+ float xy_primary_period = ComputeAutoCorrelationCoeff(
+ pitch_buf, GetInvertedLag(candidate_pitch_period), kMaxPitch24kHz);
+ float xy_secondary_period = ComputeAutoCorrelationCoeff(
+ pitch_buf, GetInvertedLag(candidate_pitch_secondary_period),
+ kMaxPitch24kHz);
+ float xy = 0.5f * (xy_primary_period + xy_secondary_period);
+ float yy = 0.5f * (yy_values[candidate_pitch_period] +
+ yy_values[candidate_pitch_secondary_period]);
+ float candidate_pitch_gain = pitch_gain(xy, yy, xx);
+
+ // Maybe update best period.
+ float threshold = ComputePitchGainThreshold(
+ candidate_pitch_period, k, initial_pitch_period, initial_pitch_gain,
+ prev_pitch_48kHz.period / 2, prev_pitch_48kHz.gain);
+ if (candidate_pitch_gain > threshold) {
+ best_pitch = {candidate_pitch_period, candidate_pitch_gain, xy, yy};
+ }
+ }
+
+ // Final pitch gain and period.
+ best_pitch.xy = std::max(0.f, best_pitch.xy);
+ RTC_DCHECK_LE(0.f, best_pitch.yy);
+ float final_pitch_gain = (best_pitch.yy <= best_pitch.xy)
+ ? 1.f
+ : best_pitch.xy / (best_pitch.yy + 1.f);
+ final_pitch_gain = std::min(best_pitch.gain, final_pitch_gain);
+ int final_pitch_period_48kHz = std::max(
+ kMinPitch48kHz,
+ PitchPseudoInterpolationLagPitchBuf(best_pitch.period_24kHz, pitch_buf));
+
+ return {final_pitch_period_48kHz, final_pitch_gain};
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h
new file mode 100644
index 0000000..2cc5ce6
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_INTERNAL_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_INTERNAL_H_
+
+#include <stddef.h>
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/pitch_info.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Performs 2x decimation without any anti-aliasing filter.
+void Decimate2x(rtc::ArrayView<const float, kBufSize24kHz> src,
+ rtc::ArrayView<float, kBufSize12kHz> dst);
+
+// Computes a gain threshold for a candidate pitch period given the initial and
+// the previous pitch period and gain estimates and the pitch period ratio used
+// to derive the candidate pitch period from the initial period.
+float ComputePitchGainThreshold(int candidate_pitch_period,
+ int pitch_period_ratio,
+ int initial_pitch_period,
+ float initial_pitch_gain,
+ int prev_pitch_period,
+ float prev_pitch_gain);
+
+// Computes the sum of squared samples for every sliding frame in the pitch
+// buffer. |yy_values| indexes are lags.
+//
+// The pitch buffer is structured as depicted below:
+// |.........|...........|
+// a b
+// The part on the left, named "a" contains the oldest samples, whereas "b" the
+// most recent ones. The size of "a" corresponds to the maximum pitch period,
+// that of "b" to the frame size (e.g., 16 ms and 20 ms respectively).
+void ComputeSlidingFrameSquareEnergies(
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
+ rtc::ArrayView<float, kMaxPitch24kHz + 1> yy_values);
+
+// Given the auto-correlation coefficients stored according to
+// ComputePitchAutoCorrelation() (i.e., using inverted lags), returns the best
+// and the second best pitch periods.
+std::array<size_t, 2> FindBestPitchPeriods(
+ rtc::ArrayView<const float> auto_corr,
+ rtc::ArrayView<const float> pitch_buf,
+ size_t max_pitch_period);
+
+// Refines the pitch period estimation given the pitch buffer |pitch_buf| and
+// the initial pitch period estimation |inv_lags|. Returns an inverted lag at
+// 48 kHz.
+size_t RefinePitchPeriod48kHz(
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
+ rtc::ArrayView<const size_t, 2> inv_lags);
+
+// Refines the pitch period estimation and compute the pitch gain. Returns the
+// refined pitch estimation data at 48 kHz.
+PitchInfo CheckLowerPitchPeriodsAndComputePitchGain(
+ rtc::ArrayView<const float, kBufSize24kHz> pitch_buf,
+ int initial_pitch_period_48kHz,
+ PitchInfo prev_pitch_48kHz);
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_PITCH_SEARCH_INTERNAL_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/ring_buffer.h b/webrtc/modules/audio_processing/agc2/rnn_vad/ring_buffer.h
new file mode 100644
index 0000000..294b0c0
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/ring_buffer.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RING_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RING_BUFFER_H_
+
+#include <array>
+#include <cstring>
+#include <type_traits>
+
+#include "api/array_view.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Ring buffer for N arrays of type T each one with size S.
+template <typename T, size_t S, size_t N>
+class RingBuffer {
+ static_assert(S > 0, "");
+ static_assert(N > 0, "");
+ static_assert(std::is_arithmetic<T>::value,
+ "Integral or floating point required.");
+
+ public:
+ RingBuffer() : tail_(0) {}
+ RingBuffer(const RingBuffer&) = delete;
+ RingBuffer& operator=(const RingBuffer&) = delete;
+ ~RingBuffer() = default;
+ // Set the ring buffer values to zero.
+ void Reset() { buffer_.fill(0); }
+ // Replace the least recently pushed array in the buffer with |new_values|.
+ void Push(rtc::ArrayView<const T, S> new_values) {
+ std::memcpy(buffer_.data() + S * tail_, new_values.data(), S * sizeof(T));
+ tail_ += 1;
+ if (tail_ == N)
+ tail_ = 0;
+ }
+ // Return an array view onto the array with a given delay. A view on the last
+ // and least recently push array is returned when |delay| is 0 and N - 1
+ // respectively.
+ rtc::ArrayView<const T, S> GetArrayView(size_t delay) const {
+ const int delay_int = static_cast<int>(delay);
+ RTC_DCHECK_LE(0, delay_int);
+ RTC_DCHECK_LT(delay_int, N);
+ int offset = tail_ - 1 - delay_int;
+ if (offset < 0)
+ offset += N;
+ return {buffer_.data() + S * offset, S};
+ }
+
+ private:
+ int tail_; // Index of the least recently pushed sub-array.
+ std::array<T, S * N> buffer_{};
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RING_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/rnn.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/rnn.cc
new file mode 100644
index 0000000..55a51ff
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/rnn.cc
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/rnn.h"
+
+// Defines WEBRTC_ARCH_X86_FAMILY, used below.
+#include "rtc_base/system/arch.h"
+
+#if defined(WEBRTC_HAS_NEON)
+#include <arm_neon.h>
+#endif
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#include <emmintrin.h>
+#endif
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <numeric>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "third_party/rnnoise/src/rnn_activations.h"
+#include "third_party/rnnoise/src/rnn_vad_weights.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+using rnnoise::kWeightsScale;
+
+using rnnoise::kInputLayerInputSize;
+static_assert(kFeatureVectorSize == kInputLayerInputSize, "");
+using rnnoise::kInputDenseBias;
+using rnnoise::kInputDenseWeights;
+using rnnoise::kInputLayerOutputSize;
+static_assert(kInputLayerOutputSize <= kFullyConnectedLayersMaxUnits,
+ "Increase kFullyConnectedLayersMaxUnits.");
+
+using rnnoise::kHiddenGruBias;
+using rnnoise::kHiddenGruRecurrentWeights;
+using rnnoise::kHiddenGruWeights;
+using rnnoise::kHiddenLayerOutputSize;
+static_assert(kHiddenLayerOutputSize <= kRecurrentLayersMaxUnits,
+ "Increase kRecurrentLayersMaxUnits.");
+
+using rnnoise::kOutputDenseBias;
+using rnnoise::kOutputDenseWeights;
+using rnnoise::kOutputLayerOutputSize;
+static_assert(kOutputLayerOutputSize <= kFullyConnectedLayersMaxUnits,
+ "Increase kFullyConnectedLayersMaxUnits.");
+
+using rnnoise::SigmoidApproximated;
+using rnnoise::TansigApproximated;
+
+inline float RectifiedLinearUnit(float x) {
+ return x < 0.f ? 0.f : x;
+}
+
+std::vector<float> GetScaledParams(rtc::ArrayView<const int8_t> params) {
+ std::vector<float> scaled_params(params.size());
+ std::transform(params.begin(), params.end(), scaled_params.begin(),
+ [](int8_t x) -> float {
+ return rnnoise::kWeightsScale * static_cast<float>(x);
+ });
+ return scaled_params;
+}
+
+// TODO(bugs.chromium.org/10480): Hard-code optimized layout and remove this
+// function to improve setup time.
+// Casts and scales |weights| and re-arranges the layout.
+std::vector<float> GetPreprocessedFcWeights(
+ rtc::ArrayView<const int8_t> weights,
+ size_t output_size) {
+ if (output_size == 1) {
+ return GetScaledParams(weights);
+ }
+ // Transpose, scale and cast.
+ const size_t input_size = rtc::CheckedDivExact(weights.size(), output_size);
+ std::vector<float> w(weights.size());
+ for (size_t o = 0; o < output_size; ++o) {
+ for (size_t i = 0; i < input_size; ++i) {
+ w[o * input_size + i] = rnnoise::kWeightsScale *
+ static_cast<float>(weights[i * output_size + o]);
+ }
+ }
+ return w;
+}
+
+constexpr size_t kNumGruGates = 3; // Update, reset, output.
+
+// TODO(bugs.chromium.org/10480): Hard-coded optimized layout and remove this
+// function to improve setup time.
+// Casts and scales |tensor_src| for a GRU layer and re-arranges the layout.
+// It works both for weights, recurrent weights and bias.
+std::vector<float> GetPreprocessedGruTensor(
+ rtc::ArrayView<const int8_t> tensor_src,
+ size_t output_size) {
+ // Transpose, cast and scale.
+ // |n| is the size of the first dimension of the 3-dim tensor |weights|.
+ const size_t n =
+ rtc::CheckedDivExact(tensor_src.size(), output_size * kNumGruGates);
+ const size_t stride_src = kNumGruGates * output_size;
+ const size_t stride_dst = n * output_size;
+ std::vector<float> tensor_dst(tensor_src.size());
+ for (size_t g = 0; g < kNumGruGates; ++g) {
+ for (size_t o = 0; o < output_size; ++o) {
+ for (size_t i = 0; i < n; ++i) {
+ tensor_dst[g * stride_dst + o * n + i] =
+ rnnoise::kWeightsScale *
+ static_cast<float>(
+ tensor_src[i * stride_src + g * output_size + o]);
+ }
+ }
+ }
+ return tensor_dst;
+}
+
+void ComputeGruUpdateResetGates(size_t input_size,
+ size_t output_size,
+ rtc::ArrayView<const float> weights,
+ rtc::ArrayView<const float> recurrent_weights,
+ rtc::ArrayView<const float> bias,
+ rtc::ArrayView<const float> input,
+ rtc::ArrayView<const float> state,
+ rtc::ArrayView<float> gate) {
+ for (size_t o = 0; o < output_size; ++o) {
+ gate[o] = bias[o];
+ for (size_t i = 0; i < input_size; ++i) {
+ gate[o] += input[i] * weights[o * input_size + i];
+ }
+ for (size_t s = 0; s < output_size; ++s) {
+ gate[o] += state[s] * recurrent_weights[o * output_size + s];
+ }
+ gate[o] = SigmoidApproximated(gate[o]);
+ }
+}
+
+void ComputeGruOutputGate(size_t input_size,
+ size_t output_size,
+ rtc::ArrayView<const float> weights,
+ rtc::ArrayView<const float> recurrent_weights,
+ rtc::ArrayView<const float> bias,
+ rtc::ArrayView<const float> input,
+ rtc::ArrayView<const float> state,
+ rtc::ArrayView<const float> reset,
+ rtc::ArrayView<float> gate) {
+ for (size_t o = 0; o < output_size; ++o) {
+ gate[o] = bias[o];
+ for (size_t i = 0; i < input_size; ++i) {
+ gate[o] += input[i] * weights[o * input_size + i];
+ }
+ for (size_t s = 0; s < output_size; ++s) {
+ gate[o] += state[s] * recurrent_weights[o * output_size + s] * reset[s];
+ }
+ gate[o] = RectifiedLinearUnit(gate[o]);
+ }
+}
+
+// Gated recurrent unit (GRU) layer un-optimized implementation.
+void ComputeGruLayerOutput(size_t input_size,
+ size_t output_size,
+ rtc::ArrayView<const float> input,
+ rtc::ArrayView<const float> weights,
+ rtc::ArrayView<const float> recurrent_weights,
+ rtc::ArrayView<const float> bias,
+ rtc::ArrayView<float> state) {
+ RTC_DCHECK_EQ(input_size, input.size());
+ // Stride and offset used to read parameter arrays.
+ const size_t stride_in = input_size * output_size;
+ const size_t stride_out = output_size * output_size;
+
+ // Update gate.
+ std::array<float, kRecurrentLayersMaxUnits> update;
+ ComputeGruUpdateResetGates(
+ input_size, output_size, weights.subview(0, stride_in),
+ recurrent_weights.subview(0, stride_out), bias.subview(0, output_size),
+ input, state, update);
+
+ // Reset gate.
+ std::array<float, kRecurrentLayersMaxUnits> reset;
+ ComputeGruUpdateResetGates(
+ input_size, output_size, weights.subview(stride_in, stride_in),
+ recurrent_weights.subview(stride_out, stride_out),
+ bias.subview(output_size, output_size), input, state, reset);
+
+ // Output gate.
+ std::array<float, kRecurrentLayersMaxUnits> output;
+ ComputeGruOutputGate(
+ input_size, output_size, weights.subview(2 * stride_in, stride_in),
+ recurrent_weights.subview(2 * stride_out, stride_out),
+ bias.subview(2 * output_size, output_size), input, state, reset, output);
+
+ // Update output through the update gates and update the state.
+ for (size_t o = 0; o < output_size; ++o) {
+ output[o] = update[o] * state[o] + (1.f - update[o]) * output[o];
+ state[o] = output[o];
+ }
+}
+
+// Fully connected layer un-optimized implementation.
+void ComputeFullyConnectedLayerOutput(
+ size_t input_size,
+ size_t output_size,
+ rtc::ArrayView<const float> input,
+ rtc::ArrayView<const float> bias,
+ rtc::ArrayView<const float> weights,
+ rtc::FunctionView<float(float)> activation_function,
+ rtc::ArrayView<float> output) {
+ RTC_DCHECK_EQ(input.size(), input_size);
+ RTC_DCHECK_EQ(bias.size(), output_size);
+ RTC_DCHECK_EQ(weights.size(), input_size * output_size);
+ for (size_t o = 0; o < output_size; ++o) {
+ output[o] = bias[o];
+ // TODO(bugs.chromium.org/9076): Benchmark how different layouts for
+ // |weights_| change the performance across different platforms.
+ for (size_t i = 0; i < input_size; ++i) {
+ output[o] += input[i] * weights[o * input_size + i];
+ }
+ output[o] = activation_function(output[o]);
+ }
+}
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+// Fully connected layer SSE2 implementation.
+void ComputeFullyConnectedLayerOutputSse2(
+ size_t input_size,
+ size_t output_size,
+ rtc::ArrayView<const float> input,
+ rtc::ArrayView<const float> bias,
+ rtc::ArrayView<const float> weights,
+ rtc::FunctionView<float(float)> activation_function,
+ rtc::ArrayView<float> output) {
+ RTC_DCHECK_EQ(input.size(), input_size);
+ RTC_DCHECK_EQ(bias.size(), output_size);
+ RTC_DCHECK_EQ(weights.size(), input_size * output_size);
+ const size_t input_size_by_4 = input_size >> 2;
+ const size_t offset = input_size & ~3;
+ __m128 sum_wx_128;
+ const float* v = reinterpret_cast<const float*>(&sum_wx_128);
+ for (size_t o = 0; o < output_size; ++o) {
+ // Perform 128 bit vector operations.
+ sum_wx_128 = _mm_set1_ps(0);
+ const float* x_p = input.data();
+ const float* w_p = weights.data() + o * input_size;
+ for (size_t i = 0; i < input_size_by_4; ++i, x_p += 4, w_p += 4) {
+ sum_wx_128 = _mm_add_ps(sum_wx_128,
+ _mm_mul_ps(_mm_loadu_ps(x_p), _mm_loadu_ps(w_p)));
+ }
+ // Perform non-vector operations for any remaining items, sum up bias term
+ // and results from the vectorized code, and apply the activation function.
+ output[o] = activation_function(
+ std::inner_product(input.begin() + offset, input.end(),
+ weights.begin() + o * input_size + offset,
+ bias[o] + v[0] + v[1] + v[2] + v[3]));
+ }
+}
+#endif
+
+} // namespace
+
+FullyConnectedLayer::FullyConnectedLayer(
+ const size_t input_size,
+ const size_t output_size,
+ const rtc::ArrayView<const int8_t> bias,
+ const rtc::ArrayView<const int8_t> weights,
+ rtc::FunctionView<float(float)> activation_function,
+ Optimization optimization)
+ : input_size_(input_size),
+ output_size_(output_size),
+ bias_(GetScaledParams(bias)),
+ weights_(GetPreprocessedFcWeights(weights, output_size)),
+ activation_function_(activation_function),
+ optimization_(optimization) {
+ RTC_DCHECK_LE(output_size_, kFullyConnectedLayersMaxUnits)
+ << "Static over-allocation of fully-connected layers output vectors is "
+ "not sufficient.";
+ RTC_DCHECK_EQ(output_size_, bias_.size())
+ << "Mismatching output size and bias terms array size.";
+ RTC_DCHECK_EQ(input_size_ * output_size_, weights_.size())
+ << "Mismatching input-output size and weight coefficients array size.";
+}
+
+FullyConnectedLayer::~FullyConnectedLayer() = default;
+
+rtc::ArrayView<const float> FullyConnectedLayer::GetOutput() const {
+ return rtc::ArrayView<const float>(output_.data(), output_size_);
+}
+
+void FullyConnectedLayer::ComputeOutput(rtc::ArrayView<const float> input) {
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Optimization::kSse2:
+ ComputeFullyConnectedLayerOutputSse2(input_size_, output_size_, input,
+ bias_, weights_,
+ activation_function_, output_);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Optimization::kNeon:
+ // TODO(bugs.chromium.org/10480): Handle Optimization::kNeon.
+ ComputeFullyConnectedLayerOutput(input_size_, output_size_, input, bias_,
+ weights_, activation_function_, output_);
+ break;
+#endif
+ default:
+ ComputeFullyConnectedLayerOutput(input_size_, output_size_, input, bias_,
+ weights_, activation_function_, output_);
+ }
+}
+
+GatedRecurrentLayer::GatedRecurrentLayer(
+ const size_t input_size,
+ const size_t output_size,
+ const rtc::ArrayView<const int8_t> bias,
+ const rtc::ArrayView<const int8_t> weights,
+ const rtc::ArrayView<const int8_t> recurrent_weights,
+ Optimization optimization)
+ : input_size_(input_size),
+ output_size_(output_size),
+ bias_(GetPreprocessedGruTensor(bias, output_size)),
+ weights_(GetPreprocessedGruTensor(weights, output_size)),
+ recurrent_weights_(
+ GetPreprocessedGruTensor(recurrent_weights, output_size)),
+ optimization_(optimization) {
+ RTC_DCHECK_LE(output_size_, kRecurrentLayersMaxUnits)
+ << "Static over-allocation of recurrent layers state vectors is not "
+ "sufficient.";
+ RTC_DCHECK_EQ(kNumGruGates * output_size_, bias_.size())
+ << "Mismatching output size and bias terms array size.";
+ RTC_DCHECK_EQ(kNumGruGates * input_size_ * output_size_, weights_.size())
+ << "Mismatching input-output size and weight coefficients array size.";
+ RTC_DCHECK_EQ(kNumGruGates * output_size_ * output_size_,
+ recurrent_weights_.size())
+ << "Mismatching input-output size and recurrent weight coefficients array"
+ " size.";
+ Reset();
+}
+
+GatedRecurrentLayer::~GatedRecurrentLayer() = default;
+
+rtc::ArrayView<const float> GatedRecurrentLayer::GetOutput() const {
+ return rtc::ArrayView<const float>(state_.data(), output_size_);
+}
+
+void GatedRecurrentLayer::Reset() {
+ state_.fill(0.f);
+}
+
+void GatedRecurrentLayer::ComputeOutput(rtc::ArrayView<const float> input) {
+ switch (optimization_) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ case Optimization::kSse2:
+ // TODO(bugs.chromium.org/10480): Handle Optimization::kSse2.
+ ComputeGruLayerOutput(input_size_, output_size_, input, weights_,
+ recurrent_weights_, bias_, state_);
+ break;
+#endif
+#if defined(WEBRTC_HAS_NEON)
+ case Optimization::kNeon:
+ // TODO(bugs.chromium.org/10480): Handle Optimization::kNeon.
+ ComputeGruLayerOutput(input_size_, output_size_, input, weights_,
+ recurrent_weights_, bias_, state_);
+ break;
+#endif
+ default:
+ ComputeGruLayerOutput(input_size_, output_size_, input, weights_,
+ recurrent_weights_, bias_, state_);
+ }
+}
+
+RnnBasedVad::RnnBasedVad()
+ : input_layer_(kInputLayerInputSize,
+ kInputLayerOutputSize,
+ kInputDenseBias,
+ kInputDenseWeights,
+ TansigApproximated,
+ DetectOptimization()),
+ hidden_layer_(kInputLayerOutputSize,
+ kHiddenLayerOutputSize,
+ kHiddenGruBias,
+ kHiddenGruWeights,
+ kHiddenGruRecurrentWeights,
+ DetectOptimization()),
+ output_layer_(kHiddenLayerOutputSize,
+ kOutputLayerOutputSize,
+ kOutputDenseBias,
+ kOutputDenseWeights,
+ SigmoidApproximated,
+ DetectOptimization()) {
+ // Input-output chaining size checks.
+ RTC_DCHECK_EQ(input_layer_.output_size(), hidden_layer_.input_size())
+ << "The input and the hidden layers sizes do not match.";
+ RTC_DCHECK_EQ(hidden_layer_.output_size(), output_layer_.input_size())
+ << "The hidden and the output layers sizes do not match.";
+}
+
+RnnBasedVad::~RnnBasedVad() = default;
+
+void RnnBasedVad::Reset() {
+ hidden_layer_.Reset();
+}
+
+float RnnBasedVad::ComputeVadProbability(
+ rtc::ArrayView<const float, kFeatureVectorSize> feature_vector,
+ bool is_silence) {
+ if (is_silence) {
+ Reset();
+ return 0.f;
+ }
+ input_layer_.ComputeOutput(feature_vector);
+ hidden_layer_.ComputeOutput(input_layer_.GetOutput());
+ output_layer_.ComputeOutput(hidden_layer_.GetOutput());
+ const auto vad_output = output_layer_.GetOutput();
+ return vad_output[0];
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/rnn.h b/webrtc/modules/audio_processing/agc2/rnn_vad/rnn.h
new file mode 100644
index 0000000..58274b2
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/rnn.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <array>
+#include <vector>
+
+#include "api/array_view.h"
+#include "api/function_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Maximum number of units for a fully-connected layer. This value is used to
+// over-allocate space for fully-connected layers output vectors (implemented as
+// std::array). The value should equal the number of units of the largest
+// fully-connected layer.
+constexpr size_t kFullyConnectedLayersMaxUnits = 24;
+
+// Maximum number of units for a recurrent layer. This value is used to
+// over-allocate space for recurrent layers state vectors (implemented as
+// std::array). The value should equal the number of units of the largest
+// recurrent layer.
+constexpr size_t kRecurrentLayersMaxUnits = 24;
+
+// Fully-connected layer.
+class FullyConnectedLayer {
+ public:
+ FullyConnectedLayer(size_t input_size,
+ size_t output_size,
+ rtc::ArrayView<const int8_t> bias,
+ rtc::ArrayView<const int8_t> weights,
+ rtc::FunctionView<float(float)> activation_function,
+ Optimization optimization);
+ FullyConnectedLayer(const FullyConnectedLayer&) = delete;
+ FullyConnectedLayer& operator=(const FullyConnectedLayer&) = delete;
+ ~FullyConnectedLayer();
+ size_t input_size() const { return input_size_; }
+ size_t output_size() const { return output_size_; }
+ Optimization optimization() const { return optimization_; }
+ rtc::ArrayView<const float> GetOutput() const;
+ // Computes the fully-connected layer output.
+ void ComputeOutput(rtc::ArrayView<const float> input);
+
+ private:
+ const size_t input_size_;
+ const size_t output_size_;
+ const std::vector<float> bias_;
+ const std::vector<float> weights_;
+ rtc::FunctionView<float(float)> activation_function_;
+ // The output vector of a recurrent layer has length equal to |output_size_|.
+ // However, for efficiency, over-allocation is used.
+ std::array<float, kFullyConnectedLayersMaxUnits> output_;
+ const Optimization optimization_;
+};
+
+// Recurrent layer with gated recurrent units (GRUs) with sigmoid and ReLU as
+// activation functions for the update/reset and output gates respectively.
+class GatedRecurrentLayer {
+ public:
+ GatedRecurrentLayer(size_t input_size,
+ size_t output_size,
+ rtc::ArrayView<const int8_t> bias,
+ rtc::ArrayView<const int8_t> weights,
+ rtc::ArrayView<const int8_t> recurrent_weights,
+ Optimization optimization);
+ GatedRecurrentLayer(const GatedRecurrentLayer&) = delete;
+ GatedRecurrentLayer& operator=(const GatedRecurrentLayer&) = delete;
+ ~GatedRecurrentLayer();
+ size_t input_size() const { return input_size_; }
+ size_t output_size() const { return output_size_; }
+ Optimization optimization() const { return optimization_; }
+ rtc::ArrayView<const float> GetOutput() const;
+ void Reset();
+ // Computes the recurrent layer output and updates the status.
+ void ComputeOutput(rtc::ArrayView<const float> input);
+
+ private:
+ const size_t input_size_;
+ const size_t output_size_;
+ const std::vector<float> bias_;
+ const std::vector<float> weights_;
+ const std::vector<float> recurrent_weights_;
+ // The state vector of a recurrent layer has length equal to |output_size_|.
+ // However, to avoid dynamic allocation, over-allocation is used.
+ std::array<float, kRecurrentLayersMaxUnits> state_;
+ const Optimization optimization_;
+};
+
+// Recurrent network based VAD.
+class RnnBasedVad {
+ public:
+ RnnBasedVad();
+ RnnBasedVad(const RnnBasedVad&) = delete;
+ RnnBasedVad& operator=(const RnnBasedVad&) = delete;
+ ~RnnBasedVad();
+ void Reset();
+ // Compute and returns the probability of voice (range: [0.0, 1.0]).
+ float ComputeVadProbability(
+ rtc::ArrayView<const float, kFeatureVectorSize> feature_vector,
+ bool is_silence);
+
+ private:
+ FullyConnectedLayer input_layer_;
+ GatedRecurrentLayer hidden_layer_;
+ FullyConnectedLayer output_layer_;
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_RNN_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/rnn_vad_tool.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/rnn_vad_tool.cc
new file mode 100644
index 0000000..c5293be
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/rnn_vad_tool.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <array>
+#include <string>
+#include <vector>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "common_audio/resampler/push_sinc_resampler.h"
+#include "common_audio/wav_file.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/features_extraction.h"
+#include "modules/audio_processing/agc2/rnn_vad/rnn.h"
+#include "rtc_base/logging.h"
+
+ABSL_FLAG(std::string, i, "", "Path to the input wav file");
+ABSL_FLAG(std::string, f, "", "Path to the output features file");
+ABSL_FLAG(std::string, o, "", "Path to the output VAD probabilities file");
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+
+int main(int argc, char* argv[]) {
+ absl::ParseCommandLine(argc, argv);
+ rtc::LogMessage::LogToDebug(rtc::LS_INFO);
+
+ // Open wav input file and check properties.
+ const std::string input_wav_file = absl::GetFlag(FLAGS_i);
+ WavReader wav_reader(input_wav_file);
+ if (wav_reader.num_channels() != 1) {
+ RTC_LOG(LS_ERROR) << "Only mono wav files are supported";
+ return 1;
+ }
+ if (wav_reader.sample_rate() % 100 != 0) {
+ RTC_LOG(LS_ERROR) << "The sample rate rate must allow 10 ms frames.";
+ return 1;
+ }
+ RTC_LOG(LS_INFO) << "Input sample rate: " << wav_reader.sample_rate();
+
+ // Init output files.
+ const std::string output_vad_probs_file = absl::GetFlag(FLAGS_o);
+ FILE* vad_probs_file = fopen(output_vad_probs_file.c_str(), "wb");
+ FILE* features_file = nullptr;
+ const std::string output_feature_file = absl::GetFlag(FLAGS_f);
+ if (!output_feature_file.empty()) {
+ features_file = fopen(output_feature_file.c_str(), "wb");
+ }
+
+ // Initialize.
+ const size_t frame_size_10ms =
+ rtc::CheckedDivExact(wav_reader.sample_rate(), 100);
+ std::vector<float> samples_10ms;
+ samples_10ms.resize(frame_size_10ms);
+ std::array<float, kFrameSize10ms24kHz> samples_10ms_24kHz;
+ PushSincResampler resampler(frame_size_10ms, kFrameSize10ms24kHz);
+ FeaturesExtractor features_extractor;
+ std::array<float, kFeatureVectorSize> feature_vector;
+ RnnBasedVad rnn_vad;
+
+ // Compute VAD probabilities.
+ while (true) {
+ // Read frame at the input sample rate.
+ const auto read_samples =
+ wav_reader.ReadSamples(frame_size_10ms, samples_10ms.data());
+ if (read_samples < frame_size_10ms) {
+ break; // EOF.
+ }
+ // Resample input.
+ resampler.Resample(samples_10ms.data(), samples_10ms.size(),
+ samples_10ms_24kHz.data(), samples_10ms_24kHz.size());
+
+ // Extract features and feed the RNN.
+ bool is_silence = features_extractor.CheckSilenceComputeFeatures(
+ samples_10ms_24kHz, feature_vector);
+ float vad_probability =
+ rnn_vad.ComputeVadProbability(feature_vector, is_silence);
+ // Write voice probability.
+ RTC_DCHECK_GE(vad_probability, 0.f);
+ RTC_DCHECK_GE(1.f, vad_probability);
+ fwrite(&vad_probability, sizeof(float), 1, vad_probs_file);
+ // Write features.
+ if (features_file) {
+ const float float_is_silence = is_silence ? 1.f : 0.f;
+ fwrite(&float_is_silence, sizeof(float), 1, features_file);
+ if (is_silence) {
+ // Do not write uninitialized values.
+ feature_vector.fill(0.f);
+ }
+ fwrite(feature_vector.data(), sizeof(float), kFeatureVectorSize,
+ features_file);
+ }
+ }
+
+ // Close output file(s).
+ fclose(vad_probs_file);
+ RTC_LOG(LS_INFO) << "VAD probabilities written to " << output_vad_probs_file;
+ if (features_file) {
+ fclose(features_file);
+ RTC_LOG(LS_INFO) << "features written to " << output_feature_file;
+ }
+
+ return 0;
+}
+
+} // namespace test
+} // namespace rnn_vad
+} // namespace webrtc
+
+int main(int argc, char* argv[]) {
+ return webrtc::rnn_vad::test::main(argc, argv);
+}
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h b/webrtc/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h
new file mode 100644
index 0000000..75d3d9b
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SEQUENCE_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SEQUENCE_BUFFER_H_
+
+#include <algorithm>
+#include <cstring>
+#include <type_traits>
+#include <vector>
+
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Linear buffer implementation to (i) push fixed size chunks of sequential data
+// and (ii) view contiguous parts of the buffer. The buffer and the pushed
+// chunks have size S and N respectively. For instance, when S = 2N the first
+// half of the sequence buffer is replaced with its second half, and the new N
+// values are written at the end of the buffer.
+// The class also provides a view on the most recent M values, where 0 < M <= S
+// and by default M = N.
+template <typename T, size_t S, size_t N, size_t M = N>
+class SequenceBuffer {
+ static_assert(N <= S,
+ "The new chunk size cannot be larger than the sequence buffer "
+ "size.");
+ static_assert(std::is_arithmetic<T>::value,
+ "Integral or floating point required.");
+
+ public:
+ SequenceBuffer() : buffer_(S) {
+ RTC_DCHECK_EQ(S, buffer_.size());
+ Reset();
+ }
+ SequenceBuffer(const SequenceBuffer&) = delete;
+ SequenceBuffer& operator=(const SequenceBuffer&) = delete;
+ ~SequenceBuffer() = default;
+ size_t size() const { return S; }
+ size_t chunks_size() const { return N; }
+ // Sets the sequence buffer values to zero.
+ void Reset() { std::fill(buffer_.begin(), buffer_.end(), 0); }
+ // Returns a view on the whole buffer.
+ rtc::ArrayView<const T, S> GetBufferView() const {
+ return {buffer_.data(), S};
+ }
+ // Returns a view on the M most recent values of the buffer.
+ rtc::ArrayView<const T, M> GetMostRecentValuesView() const {
+ static_assert(M <= S,
+ "The number of most recent values cannot be larger than the "
+ "sequence buffer size.");
+ return {buffer_.data() + S - M, M};
+ }
+ // Shifts left the buffer by N items and add new N items at the end.
+ void Push(rtc::ArrayView<const T, N> new_values) {
+ // Make space for the new values.
+ if (S > N)
+ std::memmove(buffer_.data(), buffer_.data() + N, (S - N) * sizeof(T));
+ // Copy the new values at the end of the buffer.
+ std::memcpy(buffer_.data() + S - N, new_values.data(), N * sizeof(T));
+ }
+
+ private:
+ std::vector<T> buffer_;
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SEQUENCE_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.cc
new file mode 100644
index 0000000..81e3339
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.cc
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <numeric>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+constexpr float kSilenceThreshold = 0.04f;
+
+// Computes the new cepstral difference stats and pushes them into the passed
+// symmetric matrix buffer.
+void UpdateCepstralDifferenceStats(
+ rtc::ArrayView<const float, kNumBands> new_cepstral_coeffs,
+ const RingBuffer<float, kNumBands, kCepstralCoeffsHistorySize>& ring_buf,
+ SymmetricMatrixBuffer<float, kCepstralCoeffsHistorySize>* sym_matrix_buf) {
+ RTC_DCHECK(sym_matrix_buf);
+ // Compute the new cepstral distance stats.
+ std::array<float, kCepstralCoeffsHistorySize - 1> distances;
+ for (size_t i = 0; i < kCepstralCoeffsHistorySize - 1; ++i) {
+ const size_t delay = i + 1;
+ auto old_cepstral_coeffs = ring_buf.GetArrayView(delay);
+ distances[i] = 0.f;
+ for (size_t k = 0; k < kNumBands; ++k) {
+ const float c = new_cepstral_coeffs[k] - old_cepstral_coeffs[k];
+ distances[i] += c * c;
+ }
+ }
+ // Push the new spectral distance stats into the symmetric matrix buffer.
+ sym_matrix_buf->Push(distances);
+}
+
+// Computes the first half of the Vorbis window.
+std::array<float, kFrameSize20ms24kHz / 2> ComputeScaledHalfVorbisWindow(
+ float scaling = 1.f) {
+ constexpr size_t kHalfSize = kFrameSize20ms24kHz / 2;
+ std::array<float, kHalfSize> half_window{};
+ for (size_t i = 0; i < kHalfSize; ++i) {
+ half_window[i] =
+ scaling *
+ std::sin(0.5 * kPi * std::sin(0.5 * kPi * (i + 0.5) / kHalfSize) *
+ std::sin(0.5 * kPi * (i + 0.5) / kHalfSize));
+ }
+ return half_window;
+}
+
+// Computes the forward FFT on a 20 ms frame to which a given window function is
+// applied. The Fourier coefficient corresponding to the Nyquist frequency is
+// set to zero (it is never used and this allows to simplify the code).
+void ComputeWindowedForwardFft(
+ rtc::ArrayView<const float, kFrameSize20ms24kHz> frame,
+ const std::array<float, kFrameSize20ms24kHz / 2>& half_window,
+ Pffft::FloatBuffer* fft_input_buffer,
+ Pffft::FloatBuffer* fft_output_buffer,
+ Pffft* fft) {
+ RTC_DCHECK_EQ(frame.size(), 2 * half_window.size());
+ // Apply windowing.
+ auto in = fft_input_buffer->GetView();
+ for (size_t i = 0, j = kFrameSize20ms24kHz - 1; i < half_window.size();
+ ++i, --j) {
+ in[i] = frame[i] * half_window[i];
+ in[j] = frame[j] * half_window[i];
+ }
+ fft->ForwardTransform(*fft_input_buffer, fft_output_buffer, /*ordered=*/true);
+ // Set the Nyquist frequency coefficient to zero.
+ auto out = fft_output_buffer->GetView();
+ out[1] = 0.f;
+}
+
+} // namespace
+
+SpectralFeaturesExtractor::SpectralFeaturesExtractor()
+ : half_window_(ComputeScaledHalfVorbisWindow(
+ 1.f / static_cast<float>(kFrameSize20ms24kHz))),
+ fft_(kFrameSize20ms24kHz, Pffft::FftType::kReal),
+ fft_buffer_(fft_.CreateBuffer()),
+ reference_frame_fft_(fft_.CreateBuffer()),
+ lagged_frame_fft_(fft_.CreateBuffer()),
+ dct_table_(ComputeDctTable()) {}
+
+SpectralFeaturesExtractor::~SpectralFeaturesExtractor() = default;
+
+void SpectralFeaturesExtractor::Reset() {
+ cepstral_coeffs_ring_buf_.Reset();
+ cepstral_diffs_buf_.Reset();
+}
+
+bool SpectralFeaturesExtractor::CheckSilenceComputeFeatures(
+ rtc::ArrayView<const float, kFrameSize20ms24kHz> reference_frame,
+ rtc::ArrayView<const float, kFrameSize20ms24kHz> lagged_frame,
+ rtc::ArrayView<float, kNumBands - kNumLowerBands> higher_bands_cepstrum,
+ rtc::ArrayView<float, kNumLowerBands> average,
+ rtc::ArrayView<float, kNumLowerBands> first_derivative,
+ rtc::ArrayView<float, kNumLowerBands> second_derivative,
+ rtc::ArrayView<float, kNumLowerBands> bands_cross_corr,
+ float* variability) {
+ // Compute the Opus band energies for the reference frame.
+ ComputeWindowedForwardFft(reference_frame, half_window_, fft_buffer_.get(),
+ reference_frame_fft_.get(), &fft_);
+ spectral_correlator_.ComputeAutoCorrelation(
+ reference_frame_fft_->GetConstView(), reference_frame_bands_energy_);
+ // Check if the reference frame has silence.
+ const float tot_energy =
+ std::accumulate(reference_frame_bands_energy_.begin(),
+ reference_frame_bands_energy_.end(), 0.f);
+ if (tot_energy < kSilenceThreshold) {
+ return true;
+ }
+ // Compute the Opus band energies for the lagged frame.
+ ComputeWindowedForwardFft(lagged_frame, half_window_, fft_buffer_.get(),
+ lagged_frame_fft_.get(), &fft_);
+ spectral_correlator_.ComputeAutoCorrelation(lagged_frame_fft_->GetConstView(),
+ lagged_frame_bands_energy_);
+ // Log of the band energies for the reference frame.
+ std::array<float, kNumBands> log_bands_energy;
+ ComputeSmoothedLogMagnitudeSpectrum(reference_frame_bands_energy_,
+ log_bands_energy);
+ // Reference frame cepstrum.
+ std::array<float, kNumBands> cepstrum;
+ ComputeDct(log_bands_energy, dct_table_, cepstrum);
+ // Ad-hoc correction terms for the first two cepstral coefficients.
+ cepstrum[0] -= 12.f;
+ cepstrum[1] -= 4.f;
+ // Update the ring buffer and the cepstral difference stats.
+ cepstral_coeffs_ring_buf_.Push(cepstrum);
+ UpdateCepstralDifferenceStats(cepstrum, cepstral_coeffs_ring_buf_,
+ &cepstral_diffs_buf_);
+ // Write the higher bands cepstral coefficients.
+ RTC_DCHECK_EQ(cepstrum.size() - kNumLowerBands, higher_bands_cepstrum.size());
+ std::copy(cepstrum.begin() + kNumLowerBands, cepstrum.end(),
+ higher_bands_cepstrum.begin());
+ // Compute and write remaining features.
+ ComputeAvgAndDerivatives(average, first_derivative, second_derivative);
+ ComputeNormalizedCepstralCorrelation(bands_cross_corr);
+ RTC_DCHECK(variability);
+ *variability = ComputeVariability();
+ return false;
+}
+
+void SpectralFeaturesExtractor::ComputeAvgAndDerivatives(
+ rtc::ArrayView<float, kNumLowerBands> average,
+ rtc::ArrayView<float, kNumLowerBands> first_derivative,
+ rtc::ArrayView<float, kNumLowerBands> second_derivative) const {
+ auto curr = cepstral_coeffs_ring_buf_.GetArrayView(0);
+ auto prev1 = cepstral_coeffs_ring_buf_.GetArrayView(1);
+ auto prev2 = cepstral_coeffs_ring_buf_.GetArrayView(2);
+ RTC_DCHECK_EQ(average.size(), first_derivative.size());
+ RTC_DCHECK_EQ(first_derivative.size(), second_derivative.size());
+ RTC_DCHECK_LE(average.size(), curr.size());
+ for (size_t i = 0; i < average.size(); ++i) {
+ // Average, kernel: [1, 1, 1].
+ average[i] = curr[i] + prev1[i] + prev2[i];
+ // First derivative, kernel: [1, 0, - 1].
+ first_derivative[i] = curr[i] - prev2[i];
+ // Second derivative, Laplacian kernel: [1, -2, 1].
+ second_derivative[i] = curr[i] - 2 * prev1[i] + prev2[i];
+ }
+}
+
+void SpectralFeaturesExtractor::ComputeNormalizedCepstralCorrelation(
+ rtc::ArrayView<float, kNumLowerBands> bands_cross_corr) {
+ spectral_correlator_.ComputeCrossCorrelation(
+ reference_frame_fft_->GetConstView(), lagged_frame_fft_->GetConstView(),
+ bands_cross_corr_);
+ // Normalize.
+ for (size_t i = 0; i < bands_cross_corr_.size(); ++i) {
+ bands_cross_corr_[i] =
+ bands_cross_corr_[i] /
+ std::sqrt(0.001f + reference_frame_bands_energy_[i] *
+ lagged_frame_bands_energy_[i]);
+ }
+ // Cepstrum.
+ ComputeDct(bands_cross_corr_, dct_table_, bands_cross_corr);
+ // Ad-hoc correction terms for the first two cepstral coefficients.
+ bands_cross_corr[0] -= 1.3f;
+ bands_cross_corr[1] -= 0.9f;
+}
+
+float SpectralFeaturesExtractor::ComputeVariability() const {
+ // Compute cepstral variability score.
+ float variability = 0.f;
+ for (size_t delay1 = 0; delay1 < kCepstralCoeffsHistorySize; ++delay1) {
+ float min_dist = std::numeric_limits<float>::max();
+ for (size_t delay2 = 0; delay2 < kCepstralCoeffsHistorySize; ++delay2) {
+ if (delay1 == delay2) // The distance would be 0.
+ continue;
+ min_dist =
+ std::min(min_dist, cepstral_diffs_buf_.GetValue(delay1, delay2));
+ }
+ variability += min_dist;
+ }
+ // Normalize (based on training set stats).
+ // TODO(bugs.webrtc.org/10480): Isolate normalization from feature extraction.
+ return variability / kCepstralCoeffsHistorySize - 2.1f;
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.h b/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.h
new file mode 100644
index 0000000..d327ef8
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_
+
+#include <array>
+#include <cstddef>
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/ring_buffer.h"
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h"
+#include "modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h"
+#include "modules/audio_processing/utility/pffft_wrapper.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Class to compute spectral features.
+class SpectralFeaturesExtractor {
+ public:
+ SpectralFeaturesExtractor();
+ SpectralFeaturesExtractor(const SpectralFeaturesExtractor&) = delete;
+ SpectralFeaturesExtractor& operator=(const SpectralFeaturesExtractor&) =
+ delete;
+ ~SpectralFeaturesExtractor();
+ // Resets the internal state of the feature extractor.
+ void Reset();
+ // Analyzes a pair of reference and lagged frames from the pitch buffer,
+ // detects silence and computes features. If silence is detected, the output
+ // is neither computed nor written.
+ bool CheckSilenceComputeFeatures(
+ rtc::ArrayView<const float, kFrameSize20ms24kHz> reference_frame,
+ rtc::ArrayView<const float, kFrameSize20ms24kHz> lagged_frame,
+ rtc::ArrayView<float, kNumBands - kNumLowerBands> higher_bands_cepstrum,
+ rtc::ArrayView<float, kNumLowerBands> average,
+ rtc::ArrayView<float, kNumLowerBands> first_derivative,
+ rtc::ArrayView<float, kNumLowerBands> second_derivative,
+ rtc::ArrayView<float, kNumLowerBands> bands_cross_corr,
+ float* variability);
+
+ private:
+ void ComputeAvgAndDerivatives(
+ rtc::ArrayView<float, kNumLowerBands> average,
+ rtc::ArrayView<float, kNumLowerBands> first_derivative,
+ rtc::ArrayView<float, kNumLowerBands> second_derivative) const;
+ void ComputeNormalizedCepstralCorrelation(
+ rtc::ArrayView<float, kNumLowerBands> bands_cross_corr);
+ float ComputeVariability() const;
+
+ const std::array<float, kFrameSize20ms24kHz / 2> half_window_;
+ Pffft fft_;
+ std::unique_ptr<Pffft::FloatBuffer> fft_buffer_;
+ std::unique_ptr<Pffft::FloatBuffer> reference_frame_fft_;
+ std::unique_ptr<Pffft::FloatBuffer> lagged_frame_fft_;
+ SpectralCorrelator spectral_correlator_;
+ std::array<float, kOpusBands24kHz> reference_frame_bands_energy_;
+ std::array<float, kOpusBands24kHz> lagged_frame_bands_energy_;
+ std::array<float, kOpusBands24kHz> bands_cross_corr_;
+ const std::array<float, kNumBands * kNumBands> dct_table_;
+ RingBuffer<float, kNumBands, kCepstralCoeffsHistorySize>
+ cepstral_coeffs_ring_buf_;
+ SymmetricMatrixBuffer<float, kCepstralCoeffsHistorySize> cepstral_diffs_buf_;
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc
new file mode 100644
index 0000000..29192a0
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace {
+
+// Weights for each FFT coefficient for each Opus band (Nyquist frequency
+// excluded). The size of each band is specified in
+// |kOpusScaleNumBins24kHz20ms|.
+constexpr std::array<float, kFrameSize20ms24kHz / 2> kOpusBandWeights24kHz20ms =
+ {{
+ 0.f, 0.25f, 0.5f, 0.75f, // Band 0
+ 0.f, 0.25f, 0.5f, 0.75f, // Band 1
+ 0.f, 0.25f, 0.5f, 0.75f, // Band 2
+ 0.f, 0.25f, 0.5f, 0.75f, // Band 3
+ 0.f, 0.25f, 0.5f, 0.75f, // Band 4
+ 0.f, 0.25f, 0.5f, 0.75f, // Band 5
+ 0.f, 0.25f, 0.5f, 0.75f, // Band 6
+ 0.f, 0.25f, 0.5f, 0.75f, // Band 7
+ 0.f, 0.125f, 0.25f, 0.375f, 0.5f,
+ 0.625f, 0.75f, 0.875f, // Band 8
+ 0.f, 0.125f, 0.25f, 0.375f, 0.5f,
+ 0.625f, 0.75f, 0.875f, // Band 9
+ 0.f, 0.125f, 0.25f, 0.375f, 0.5f,
+ 0.625f, 0.75f, 0.875f, // Band 10
+ 0.f, 0.125f, 0.25f, 0.375f, 0.5f,
+ 0.625f, 0.75f, 0.875f, // Band 11
+ 0.f, 0.0625f, 0.125f, 0.1875f, 0.25f,
+ 0.3125f, 0.375f, 0.4375f, 0.5f, 0.5625f,
+ 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f,
+ 0.9375f, // Band 12
+ 0.f, 0.0625f, 0.125f, 0.1875f, 0.25f,
+ 0.3125f, 0.375f, 0.4375f, 0.5f, 0.5625f,
+ 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f,
+ 0.9375f, // Band 13
+ 0.f, 0.0625f, 0.125f, 0.1875f, 0.25f,
+ 0.3125f, 0.375f, 0.4375f, 0.5f, 0.5625f,
+ 0.625f, 0.6875f, 0.75f, 0.8125f, 0.875f,
+ 0.9375f, // Band 14
+ 0.f, 0.0416667f, 0.0833333f, 0.125f, 0.166667f,
+ 0.208333f, 0.25f, 0.291667f, 0.333333f, 0.375f,
+ 0.416667f, 0.458333f, 0.5f, 0.541667f, 0.583333f,
+ 0.625f, 0.666667f, 0.708333f, 0.75f, 0.791667f,
+ 0.833333f, 0.875f, 0.916667f, 0.958333f, // Band 15
+ 0.f, 0.0416667f, 0.0833333f, 0.125f, 0.166667f,
+ 0.208333f, 0.25f, 0.291667f, 0.333333f, 0.375f,
+ 0.416667f, 0.458333f, 0.5f, 0.541667f, 0.583333f,
+ 0.625f, 0.666667f, 0.708333f, 0.75f, 0.791667f,
+ 0.833333f, 0.875f, 0.916667f, 0.958333f, // Band 16
+ 0.f, 0.03125f, 0.0625f, 0.09375f, 0.125f,
+ 0.15625f, 0.1875f, 0.21875f, 0.25f, 0.28125f,
+ 0.3125f, 0.34375f, 0.375f, 0.40625f, 0.4375f,
+ 0.46875f, 0.5f, 0.53125f, 0.5625f, 0.59375f,
+ 0.625f, 0.65625f, 0.6875f, 0.71875f, 0.75f,
+ 0.78125f, 0.8125f, 0.84375f, 0.875f, 0.90625f,
+ 0.9375f, 0.96875f, // Band 17
+ 0.f, 0.0208333f, 0.0416667f, 0.0625f, 0.0833333f,
+ 0.104167f, 0.125f, 0.145833f, 0.166667f, 0.1875f,
+ 0.208333f, 0.229167f, 0.25f, 0.270833f, 0.291667f,
+ 0.3125f, 0.333333f, 0.354167f, 0.375f, 0.395833f,
+ 0.416667f, 0.4375f, 0.458333f, 0.479167f, 0.5f,
+ 0.520833f, 0.541667f, 0.5625f, 0.583333f, 0.604167f,
+ 0.625f, 0.645833f, 0.666667f, 0.6875f, 0.708333f,
+ 0.729167f, 0.75f, 0.770833f, 0.791667f, 0.8125f,
+ 0.833333f, 0.854167f, 0.875f, 0.895833f, 0.916667f,
+ 0.9375f, 0.958333f, 0.979167f // Band 18
+ }};
+
+} // namespace
+
+SpectralCorrelator::SpectralCorrelator()
+ : weights_(kOpusBandWeights24kHz20ms.begin(),
+ kOpusBandWeights24kHz20ms.end()) {}
+
+SpectralCorrelator::~SpectralCorrelator() = default;
+
+void SpectralCorrelator::ComputeAutoCorrelation(
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<float, kOpusBands24kHz> auto_corr) const {
+ ComputeCrossCorrelation(x, x, auto_corr);
+}
+
+void SpectralCorrelator::ComputeCrossCorrelation(
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float, kOpusBands24kHz> cross_corr) const {
+ RTC_DCHECK_EQ(x.size(), kFrameSize20ms24kHz);
+ RTC_DCHECK_EQ(x.size(), y.size());
+ RTC_DCHECK_EQ(x[1], 0.f) << "The Nyquist coefficient must be zeroed.";
+ RTC_DCHECK_EQ(y[1], 0.f) << "The Nyquist coefficient must be zeroed.";
+ constexpr auto kOpusScaleNumBins24kHz20ms = GetOpusScaleNumBins24kHz20ms();
+ size_t k = 0; // Next Fourier coefficient index.
+ cross_corr[0] = 0.f;
+ for (size_t i = 0; i < kOpusBands24kHz - 1; ++i) {
+ cross_corr[i + 1] = 0.f;
+ for (int j = 0; j < kOpusScaleNumBins24kHz20ms[i]; ++j) { // Band size.
+ const float v = x[2 * k] * y[2 * k] + x[2 * k + 1] * y[2 * k + 1];
+ const float tmp = weights_[k] * v;
+ cross_corr[i] += v - tmp;
+ cross_corr[i + 1] += tmp;
+ k++;
+ }
+ }
+ cross_corr[0] *= 2.f; // The first band only gets half contribution.
+ RTC_DCHECK_EQ(k, kFrameSize20ms24kHz / 2); // Nyquist coefficient never used.
+}
+
+void ComputeSmoothedLogMagnitudeSpectrum(
+ rtc::ArrayView<const float> bands_energy,
+ rtc::ArrayView<float, kNumBands> log_bands_energy) {
+ RTC_DCHECK_LE(bands_energy.size(), kNumBands);
+ constexpr float kOneByHundred = 1e-2f;
+ constexpr float kLogOneByHundred = -2.f;
+ // Init.
+ float log_max = kLogOneByHundred;
+ float follow = kLogOneByHundred;
+ const auto smooth = [&log_max, &follow](float x) {
+ x = std::max(log_max - 7.f, std::max(follow - 1.5f, x));
+ log_max = std::max(log_max, x);
+ follow = std::max(follow - 1.5f, x);
+ return x;
+ };
+ // Smoothing over the bands for which the band energy is defined.
+ for (size_t i = 0; i < bands_energy.size(); ++i) {
+ log_bands_energy[i] = smooth(std::log10(kOneByHundred + bands_energy[i]));
+ }
+ // Smoothing over the remaining bands (zero energy).
+ for (size_t i = bands_energy.size(); i < kNumBands; ++i) {
+ log_bands_energy[i] = smooth(kLogOneByHundred);
+ }
+}
+
+std::array<float, kNumBands * kNumBands> ComputeDctTable() {
+ std::array<float, kNumBands * kNumBands> dct_table;
+ const double k = std::sqrt(0.5);
+ for (size_t i = 0; i < kNumBands; ++i) {
+ for (size_t j = 0; j < kNumBands; ++j)
+ dct_table[i * kNumBands + j] = std::cos((i + 0.5) * j * kPi / kNumBands);
+ dct_table[i * kNumBands] *= k;
+ }
+ return dct_table;
+}
+
+void ComputeDct(rtc::ArrayView<const float> in,
+ rtc::ArrayView<const float, kNumBands * kNumBands> dct_table,
+ rtc::ArrayView<float> out) {
+ // DCT scaling factor - i.e., sqrt(2 / kNumBands).
+ constexpr float kDctScalingFactor = 0.301511345f;
+ constexpr float kDctScalingFactorError =
+ kDctScalingFactor * kDctScalingFactor -
+ 2.f / static_cast<float>(kNumBands);
+ static_assert(
+ (kDctScalingFactorError >= 0.f && kDctScalingFactorError < 1e-1f) ||
+ (kDctScalingFactorError < 0.f && kDctScalingFactorError > -1e-1f),
+ "kNumBands changed and kDctScalingFactor has not been updated.");
+ RTC_DCHECK_NE(in.data(), out.data()) << "In-place DCT is not supported.";
+ RTC_DCHECK_LE(in.size(), kNumBands);
+ RTC_DCHECK_LE(1, out.size());
+ RTC_DCHECK_LE(out.size(), in.size());
+ for (size_t i = 0; i < out.size(); ++i) {
+ out[i] = 0.f;
+ for (size_t j = 0; j < in.size(); ++j) {
+ out[i] += in[j] * dct_table[j * kNumBands + i];
+ }
+ // TODO(bugs.webrtc.org/10480): Scaling factor in the DCT table.
+ out[i] *= kDctScalingFactor;
+ }
+}
+
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h b/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h
new file mode 100644
index 0000000..ed4caad
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_
+
+#include <stddef.h>
+
+#include <array>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// At a sample rate of 24 kHz, the last 3 Opus bands are beyond the Nyquist
+// frequency. However, band #19 gets the contributions from band #18 because
+// of the symmetric triangular filter with peak response at 12 kHz.
+constexpr size_t kOpusBands24kHz = 20;
+static_assert(kOpusBands24kHz < kNumBands,
+ "The number of bands at 24 kHz must be less than those defined "
+ "in the Opus scale at 48 kHz.");
+
+// Number of FFT frequency bins covered by each band in the Opus scale at a
+// sample rate of 24 kHz for 20 ms frames.
+// Declared here for unit testing.
+constexpr std::array<int, kOpusBands24kHz - 1> GetOpusScaleNumBins24kHz20ms() {
+ return {4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 16, 16, 16, 24, 24, 32, 48};
+}
+
+// TODO(bugs.webrtc.org/10480): Move to a separate file.
+// Class to compute band-wise spectral features in the Opus perceptual scale
+// for 20 ms frames sampled at 24 kHz. The analysis methods apply triangular
+// filters with peak response at the each band boundary.
+class SpectralCorrelator {
+ public:
+ // Ctor.
+ SpectralCorrelator();
+ SpectralCorrelator(const SpectralCorrelator&) = delete;
+ SpectralCorrelator& operator=(const SpectralCorrelator&) = delete;
+ ~SpectralCorrelator();
+
+ // Computes the band-wise spectral auto-correlations.
+ // |x| must:
+ // - have size equal to |kFrameSize20ms24kHz|;
+ // - be encoded as vectors of interleaved real-complex FFT coefficients
+ // where x[1] = y[1] = 0 (the Nyquist frequency coefficient is omitted).
+ void ComputeAutoCorrelation(
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<float, kOpusBands24kHz> auto_corr) const;
+
+ // Computes the band-wise spectral cross-correlations.
+ // |x| and |y| must:
+ // - have size equal to |kFrameSize20ms24kHz|;
+ // - be encoded as vectors of interleaved real-complex FFT coefficients where
+ // x[1] = y[1] = 0 (the Nyquist frequency coefficient is omitted).
+ void ComputeCrossCorrelation(
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<const float> y,
+ rtc::ArrayView<float, kOpusBands24kHz> cross_corr) const;
+
+ private:
+ const std::vector<float> weights_; // Weights for each Fourier coefficient.
+};
+
+// TODO(bugs.webrtc.org/10480): Move to anonymous namespace in
+// spectral_features.cc. Given a vector of Opus-bands energy coefficients,
+// computes the log magnitude spectrum applying smoothing both over time and
+// over frequency. Declared here for unit testing.
+void ComputeSmoothedLogMagnitudeSpectrum(
+ rtc::ArrayView<const float> bands_energy,
+ rtc::ArrayView<float, kNumBands> log_bands_energy);
+
+// TODO(bugs.webrtc.org/10480): Move to anonymous namespace in
+// spectral_features.cc. Creates a DCT table for arrays having size equal to
+// |kNumBands|. Declared here for unit testing.
+std::array<float, kNumBands * kNumBands> ComputeDctTable();
+
+// TODO(bugs.webrtc.org/10480): Move to anonymous namespace in
+// spectral_features.cc. Computes DCT for |in| given a pre-computed DCT table.
+// In-place computation is not allowed and |out| can be smaller than |in| in
+// order to only compute the first DCT coefficients. Declared here for unit
+// testing.
+void ComputeDct(rtc::ArrayView<const float> in,
+ rtc::ArrayView<const float, kNumBands * kNumBands> dct_table,
+ rtc::ArrayView<float> out);
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SPECTRAL_FEATURES_INTERNAL_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h b/webrtc/modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h
new file mode 100644
index 0000000..f0282aa
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SYMMETRIC_MATRIX_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SYMMETRIC_MATRIX_BUFFER_H_
+
+#include <algorithm>
+#include <array>
+#include <cstring>
+#include <utility>
+
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+
+// Data structure to buffer the results of pair-wise comparisons between items
+// stored in a ring buffer. Every time that the oldest item is replaced in the
+// ring buffer, the new one is compared to the remaining items in the ring
+// buffer. The results of such comparisons need to be buffered and automatically
+// removed when one of the two corresponding items that have been compared is
+// removed from the ring buffer. It is assumed that the comparison is symmetric
+// and that comparing an item with itself is not needed.
+template <typename T, size_t S>
+class SymmetricMatrixBuffer {
+ static_assert(S > 2, "");
+
+ public:
+ SymmetricMatrixBuffer() = default;
+ SymmetricMatrixBuffer(const SymmetricMatrixBuffer&) = delete;
+ SymmetricMatrixBuffer& operator=(const SymmetricMatrixBuffer&) = delete;
+ ~SymmetricMatrixBuffer() = default;
+ // Sets the buffer values to zero.
+ void Reset() {
+ static_assert(std::is_arithmetic<T>::value,
+ "Integral or floating point required.");
+ buf_.fill(0);
+ }
+ // Pushes the results from the comparison between the most recent item and
+ // those that are still in the ring buffer. The first element in |values| must
+ // correspond to the comparison between the most recent item and the second
+ // most recent one in the ring buffer, whereas the last element in |values|
+ // must correspond to the comparison between the most recent item and the
+ // oldest one in the ring buffer.
+ void Push(rtc::ArrayView<T, S - 1> values) {
+ // Move the lower-right sub-matrix of size (S-2) x (S-2) one row up and one
+ // column left.
+ std::memmove(buf_.data(), buf_.data() + S, (buf_.size() - S) * sizeof(T));
+ // Copy new values in the last column in the right order.
+ for (size_t i = 0; i < values.size(); ++i) {
+ const size_t index = (S - 1 - i) * (S - 1) - 1;
+ RTC_DCHECK_LE(static_cast<size_t>(0), index);
+ RTC_DCHECK_LT(index, buf_.size());
+ buf_[index] = values[i];
+ }
+ }
+ // Reads the value that corresponds to comparison of two items in the ring
+ // buffer having delay |delay1| and |delay2|. The two arguments must not be
+ // equal and both must be in {0, ..., S - 1}.
+ T GetValue(size_t delay1, size_t delay2) const {
+ int row = S - 1 - static_cast<int>(delay1);
+ int col = S - 1 - static_cast<int>(delay2);
+ RTC_DCHECK_NE(row, col) << "The diagonal cannot be accessed.";
+ if (row > col)
+ std::swap(row, col); // Swap to access the upper-right triangular part.
+ RTC_DCHECK_LE(0, row);
+ RTC_DCHECK_LT(row, S - 1) << "Not enforcing row < col and row != col.";
+ RTC_DCHECK_LE(1, col) << "Not enforcing row < col and row != col.";
+ RTC_DCHECK_LT(col, S);
+ const int index = row * (S - 1) + (col - 1);
+ RTC_DCHECK_LE(0, index);
+ RTC_DCHECK_LT(index, buf_.size());
+ return buf_[index];
+ }
+
+ private:
+ // Encode an upper-right triangular matrix (excluding its diagonal) using a
+ // square matrix. This allows to move the data in Push() with one single
+ // operation.
+ std::array<T, (S - 1) * (S - 1)> buf_{};
+};
+
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_SYMMETRIC_MATRIX_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.cc b/webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.cc
new file mode 100644
index 0000000..c7bf02e
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
+
+#include <memory>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/system/arch.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+namespace {
+
+using ReaderPairType =
+ std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>;
+
+} // namespace
+
+using webrtc::test::ResourcePath;
+
+void ExpectEqualFloatArray(rtc::ArrayView<const float> expected,
+ rtc::ArrayView<const float> computed) {
+ ASSERT_EQ(expected.size(), computed.size());
+ for (size_t i = 0; i < expected.size(); ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_FLOAT_EQ(expected[i], computed[i]);
+ }
+}
+
+void ExpectNearAbsolute(rtc::ArrayView<const float> expected,
+ rtc::ArrayView<const float> computed,
+ float tolerance) {
+ ASSERT_EQ(expected.size(), computed.size());
+ for (size_t i = 0; i < expected.size(); ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_NEAR(expected[i], computed[i], tolerance);
+ }
+}
+
+std::pair<std::unique_ptr<BinaryFileReader<int16_t, float>>, const size_t>
+CreatePcmSamplesReader(const size_t frame_length) {
+ auto ptr = std::make_unique<BinaryFileReader<int16_t, float>>(
+ test::ResourcePath("audio_processing/agc2/rnn_vad/samples", "pcm"),
+ frame_length);
+ // The last incomplete frame is ignored.
+ return {std::move(ptr), ptr->data_length() / frame_length};
+}
+
+ReaderPairType CreatePitchBuffer24kHzReader() {
+ constexpr size_t cols = 864;
+ auto ptr = std::make_unique<BinaryFileReader<float>>(
+ ResourcePath("audio_processing/agc2/rnn_vad/pitch_buf_24k", "dat"), cols);
+ return {std::move(ptr), rtc::CheckedDivExact(ptr->data_length(), cols)};
+}
+
+ReaderPairType CreateLpResidualAndPitchPeriodGainReader() {
+ constexpr size_t num_lp_residual_coeffs = 864;
+ auto ptr = std::make_unique<BinaryFileReader<float>>(
+ ResourcePath("audio_processing/agc2/rnn_vad/pitch_lp_res", "dat"),
+ num_lp_residual_coeffs);
+ return {std::move(ptr),
+ rtc::CheckedDivExact(ptr->data_length(), 2 + num_lp_residual_coeffs)};
+}
+
+ReaderPairType CreateVadProbsReader() {
+ auto ptr = std::make_unique<BinaryFileReader<float>>(
+ test::ResourcePath("audio_processing/agc2/rnn_vad/vad_prob", "dat"));
+ return {std::move(ptr), ptr->data_length()};
+}
+
+PitchTestData::PitchTestData() {
+ BinaryFileReader<float> test_data_reader(
+ ResourcePath("audio_processing/agc2/rnn_vad/pitch_search_int", "dat"),
+ static_cast<size_t>(1396));
+ test_data_reader.ReadChunk(test_data_);
+}
+
+PitchTestData::~PitchTestData() = default;
+
+rtc::ArrayView<const float, kBufSize24kHz> PitchTestData::GetPitchBufView()
+ const {
+ return {test_data_.data(), kBufSize24kHz};
+}
+
+rtc::ArrayView<const float, kNumPitchBufSquareEnergies>
+PitchTestData::GetPitchBufSquareEnergiesView() const {
+ return {test_data_.data() + kBufSize24kHz, kNumPitchBufSquareEnergies};
+}
+
+rtc::ArrayView<const float, kNumPitchBufAutoCorrCoeffs>
+PitchTestData::GetPitchBufAutoCorrCoeffsView() const {
+ return {test_data_.data() + kBufSize24kHz + kNumPitchBufSquareEnergies,
+ kNumPitchBufAutoCorrCoeffs};
+}
+
+bool IsOptimizationAvailable(Optimization optimization) {
+ switch (optimization) {
+ case Optimization::kSse2:
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ return GetCPUInfo(kSSE2) != 0;
+#else
+ return false;
+#endif
+ case Optimization::kNeon:
+#if defined(WEBRTC_HAS_NEON)
+ return true;
+#else
+ return false;
+#endif
+ case Optimization::kNone:
+ return true;
+ }
+}
+
+} // namespace test
+} // namespace rnn_vad
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.h b/webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.h
new file mode 100644
index 0000000..db155e6
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/rnn_vad/test_utils.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_TEST_UTILS_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_TEST_UTILS_H_
+
+#include <algorithm>
+#include <array>
+#include <fstream>
+#include <limits>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace rnn_vad {
+namespace test {
+
+constexpr float kFloatMin = std::numeric_limits<float>::min();
+
+// Fails for every pair from two equally sized rtc::ArrayView<float> views such
+// that the values in the pair do not match.
+void ExpectEqualFloatArray(rtc::ArrayView<const float> expected,
+ rtc::ArrayView<const float> computed);
+
+// Fails for every pair from two equally sized rtc::ArrayView<float> views such
+// that their absolute error is above a given threshold.
+void ExpectNearAbsolute(rtc::ArrayView<const float> expected,
+ rtc::ArrayView<const float> computed,
+ float tolerance);
+
+// Reader for binary files consisting of an arbitrary long sequence of elements
+// having type T. It is possible to read and cast to another type D at once.
+template <typename T, typename D = T>
+class BinaryFileReader {
+ public:
+ explicit BinaryFileReader(const std::string& file_path, size_t chunk_size = 0)
+ : is_(file_path, std::ios::binary | std::ios::ate),
+ data_length_(is_.tellg() / sizeof(T)),
+ chunk_size_(chunk_size) {
+ RTC_CHECK(is_);
+ SeekBeginning();
+ buf_.resize(chunk_size_);
+ }
+ BinaryFileReader(const BinaryFileReader&) = delete;
+ BinaryFileReader& operator=(const BinaryFileReader&) = delete;
+ ~BinaryFileReader() = default;
+ size_t data_length() const { return data_length_; }
+ bool ReadValue(D* dst) {
+ if (std::is_same<T, D>::value) {
+ is_.read(reinterpret_cast<char*>(dst), sizeof(T));
+ } else {
+ T v;
+ is_.read(reinterpret_cast<char*>(&v), sizeof(T));
+ *dst = static_cast<D>(v);
+ }
+ return is_.gcount() == sizeof(T);
+ }
+ // If |chunk_size| was specified in the ctor, it will check that the size of
+ // |dst| equals |chunk_size|.
+ bool ReadChunk(rtc::ArrayView<D> dst) {
+ RTC_DCHECK((chunk_size_ == 0) || (chunk_size_ == dst.size()));
+ const std::streamsize bytes_to_read = dst.size() * sizeof(T);
+ if (std::is_same<T, D>::value) {
+ is_.read(reinterpret_cast<char*>(dst.data()), bytes_to_read);
+ } else {
+ is_.read(reinterpret_cast<char*>(buf_.data()), bytes_to_read);
+ std::transform(buf_.begin(), buf_.end(), dst.begin(),
+ [](const T& v) -> D { return static_cast<D>(v); });
+ }
+ return is_.gcount() == bytes_to_read;
+ }
+ void SeekForward(size_t items) { is_.seekg(items * sizeof(T), is_.cur); }
+ void SeekBeginning() { is_.seekg(0, is_.beg); }
+
+ private:
+ std::ifstream is_;
+ const size_t data_length_;
+ const size_t chunk_size_;
+ std::vector<T> buf_;
+};
+
+// Writer for binary files.
+template <typename T>
+class BinaryFileWriter {
+ public:
+ explicit BinaryFileWriter(const std::string& file_path)
+ : os_(file_path, std::ios::binary) {}
+ BinaryFileWriter(const BinaryFileWriter&) = delete;
+ BinaryFileWriter& operator=(const BinaryFileWriter&) = delete;
+ ~BinaryFileWriter() = default;
+ static_assert(std::is_arithmetic<T>::value, "");
+ void WriteChunk(rtc::ArrayView<const T> value) {
+ const std::streamsize bytes_to_write = value.size() * sizeof(T);
+ os_.write(reinterpret_cast<const char*>(value.data()), bytes_to_write);
+ }
+
+ private:
+ std::ofstream os_;
+};
+
+// Factories for resource file readers.
+// The functions below return a pair where the first item is a reader unique
+// pointer and the second the number of chunks that can be read from the file.
+// Creates a reader for the PCM samples that casts from S16 to float and reads
+// chunks with length |frame_length|.
+std::pair<std::unique_ptr<BinaryFileReader<int16_t, float>>, const size_t>
+CreatePcmSamplesReader(const size_t frame_length);
+// Creates a reader for the pitch buffer content at 24 kHz.
+std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
+CreatePitchBuffer24kHzReader();
+// Creates a reader for the the LP residual coefficients and the pitch period
+// and gain values.
+std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
+CreateLpResidualAndPitchPeriodGainReader();
+// Creates a reader for the VAD probabilities.
+std::pair<std::unique_ptr<BinaryFileReader<float>>, const size_t>
+CreateVadProbsReader();
+
+constexpr size_t kNumPitchBufAutoCorrCoeffs = 147;
+constexpr size_t kNumPitchBufSquareEnergies = 385;
+constexpr size_t kPitchTestDataSize =
+ kBufSize24kHz + kNumPitchBufSquareEnergies + kNumPitchBufAutoCorrCoeffs;
+
+// Class to retrieve a test pitch buffer content and the expected output for the
+// analysis steps.
+class PitchTestData {
+ public:
+ PitchTestData();
+ ~PitchTestData();
+ rtc::ArrayView<const float, kBufSize24kHz> GetPitchBufView() const;
+ rtc::ArrayView<const float, kNumPitchBufSquareEnergies>
+ GetPitchBufSquareEnergiesView() const;
+ rtc::ArrayView<const float, kNumPitchBufAutoCorrCoeffs>
+ GetPitchBufAutoCorrCoeffsView() const;
+
+ private:
+ std::array<float, kPitchTestDataSize> test_data_;
+};
+
+// Returns true if the given optimization is available.
+bool IsOptimizationAvailable(Optimization optimization);
+
+} // namespace test
+} // namespace rnn_vad
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_RNN_VAD_TEST_UTILS_H_
diff --git a/webrtc/modules/audio_processing/agc2/saturation_protector.cc b/webrtc/modules/audio_processing/agc2/saturation_protector.cc
new file mode 100644
index 0000000..b64fcdb
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/saturation_protector.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/saturation_protector.h"
+
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+namespace {
+
+constexpr float kMinLevelDbfs = -90.f;
+
+// Min/max margins are based on speech crest-factor.
+constexpr float kMinMarginDb = 12.f;
+constexpr float kMaxMarginDb = 25.f;
+
+using saturation_protector_impl::RingBuffer;
+
+} // namespace
+
+bool RingBuffer::operator==(const RingBuffer& b) const {
+ RTC_DCHECK_LE(size_, buffer_.size());
+ RTC_DCHECK_LE(b.size_, b.buffer_.size());
+ if (size_ != b.size_) {
+ return false;
+ }
+ for (int i = 0, i0 = FrontIndex(), i1 = b.FrontIndex(); i < size_;
+ ++i, ++i0, ++i1) {
+ if (buffer_[i0 % buffer_.size()] != b.buffer_[i1 % b.buffer_.size()]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void RingBuffer::Reset() {
+ next_ = 0;
+ size_ = 0;
+}
+
+void RingBuffer::PushBack(float v) {
+ RTC_DCHECK_GE(next_, 0);
+ RTC_DCHECK_GE(size_, 0);
+ RTC_DCHECK_LT(next_, buffer_.size());
+ RTC_DCHECK_LE(size_, buffer_.size());
+ buffer_[next_++] = v;
+ if (rtc::SafeEq(next_, buffer_.size())) {
+ next_ = 0;
+ }
+ if (rtc::SafeLt(size_, buffer_.size())) {
+ size_++;
+ }
+}
+
+absl::optional<float> RingBuffer::Front() const {
+ if (size_ == 0) {
+ return absl::nullopt;
+ }
+ RTC_DCHECK_LT(FrontIndex(), buffer_.size());
+ return buffer_[FrontIndex()];
+}
+
+bool SaturationProtectorState::operator==(
+ const SaturationProtectorState& b) const {
+ return margin_db == b.margin_db && peak_delay_buffer == b.peak_delay_buffer &&
+ max_peaks_dbfs == b.max_peaks_dbfs &&
+ time_since_push_ms == b.time_since_push_ms;
+}
+
+void ResetSaturationProtectorState(float initial_margin_db,
+ SaturationProtectorState& state) {
+ state.margin_db = initial_margin_db;
+ state.peak_delay_buffer.Reset();
+ state.max_peaks_dbfs = kMinLevelDbfs;
+ state.time_since_push_ms = 0;
+}
+
+void UpdateSaturationProtectorState(float speech_peak_dbfs,
+ float speech_level_dbfs,
+ SaturationProtectorState& state) {
+ // Get the max peak over `kPeakEnveloperSuperFrameLengthMs` ms.
+ state.max_peaks_dbfs = std::max(state.max_peaks_dbfs, speech_peak_dbfs);
+ state.time_since_push_ms += kFrameDurationMs;
+ if (rtc::SafeGt(state.time_since_push_ms, kPeakEnveloperSuperFrameLengthMs)) {
+ // Push `max_peaks_dbfs` back into the ring buffer.
+ state.peak_delay_buffer.PushBack(state.max_peaks_dbfs);
+ // Reset.
+ state.max_peaks_dbfs = kMinLevelDbfs;
+ state.time_since_push_ms = 0;
+ }
+
+ // Update margin by comparing the estimated speech level and the delayed max
+ // speech peak power.
+ // TODO(alessiob): Check with aleloi@ why we use a delay and how to tune it.
+ const float delayed_peak_dbfs =
+ state.peak_delay_buffer.Front().value_or(state.max_peaks_dbfs);
+ const float difference_db = delayed_peak_dbfs - speech_level_dbfs;
+ if (difference_db > state.margin_db) {
+ // Attack.
+ state.margin_db =
+ state.margin_db * kSaturationProtectorAttackConstant +
+ difference_db * (1.f - kSaturationProtectorAttackConstant);
+ } else {
+ // Decay.
+ state.margin_db = state.margin_db * kSaturationProtectorDecayConstant +
+ difference_db * (1.f - kSaturationProtectorDecayConstant);
+ }
+
+ state.margin_db =
+ rtc::SafeClamp<float>(state.margin_db, kMinMarginDb, kMaxMarginDb);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/saturation_protector.h b/webrtc/modules/audio_processing/agc2/saturation_protector.h
new file mode 100644
index 0000000..88be91a
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/saturation_protector.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_SATURATION_PROTECTOR_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_SATURATION_PROTECTOR_H_
+
+#include <array>
+
+#include "absl/types/optional.h"
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "rtc_base/numerics/safe_compare.h"
+
+namespace webrtc {
+namespace saturation_protector_impl {
+
+// Ring buffer which only supports (i) push back and (ii) read oldest item.
+class RingBuffer {
+ public:
+ bool operator==(const RingBuffer& b) const;
+ inline bool operator!=(const RingBuffer& b) const { return !(*this == b); }
+
+ // Maximum number of values that the buffer can contain.
+ int Capacity() const { return buffer_.size(); }
+ // Number of values in the buffer.
+ int Size() const { return size_; }
+
+ void Reset();
+ // Pushes back `v`. If the buffer is full, the oldest value is replaced.
+ void PushBack(float v);
+ // Returns the oldest item in the buffer. Returns an empty value if the
+ // buffer is empty.
+ absl::optional<float> Front() const;
+
+ private:
+ inline int FrontIndex() const {
+ return rtc::SafeEq(size_, buffer_.size()) ? next_ : 0;
+ }
+ // `buffer_` has `size_` elements (up to the size of `buffer_`) and `next_` is
+ // the position where the next new value is written in `buffer_`.
+ std::array<float, kPeakEnveloperBufferSize> buffer_;
+ int next_ = 0;
+ int size_ = 0;
+};
+
+} // namespace saturation_protector_impl
+
+// Saturation protector state. Exposed publicly for check-pointing and restore
+// ops.
+struct SaturationProtectorState {
+ bool operator==(const SaturationProtectorState& s) const;
+ inline bool operator!=(const SaturationProtectorState& s) const {
+ return !(*this == s);
+ }
+
+ float margin_db; // Recommended margin.
+ saturation_protector_impl::RingBuffer peak_delay_buffer;
+ float max_peaks_dbfs;
+ int time_since_push_ms; // Time since the last ring buffer push operation.
+};
+
+// Resets the saturation protector state.
+void ResetSaturationProtectorState(float initial_margin_db,
+ SaturationProtectorState& state);
+
+// Updates `state` by analyzing the estimated speech level `speech_level_dbfs`
+// and the peak power `speech_peak_dbfs` for an observed frame which is
+// reliably classified as "speech". `state` must not be modified without calling
+// this function.
+void UpdateSaturationProtectorState(float speech_peak_dbfs,
+ float speech_level_dbfs,
+ SaturationProtectorState& state);
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_SATURATION_PROTECTOR_H_
diff --git a/webrtc/modules/audio_processing/agc2/signal_classifier.cc b/webrtc/modules/audio_processing/agc2/signal_classifier.cc
new file mode 100644
index 0000000..a06413d
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/signal_classifier.cc
@@ -0,0 +1,177 @@
+/*
+ * 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/audio_processing/agc2/signal_classifier.h"
+
+#include <algorithm>
+#include <numeric>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/agc2/down_sampler.h"
+#include "modules/audio_processing/agc2/noise_spectrum_estimator.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+
+namespace webrtc {
+namespace {
+
+bool IsSse2Available() {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ return GetCPUInfo(kSSE2) != 0;
+#else
+ return false;
+#endif
+}
+
+void RemoveDcLevel(rtc::ArrayView<float> x) {
+ RTC_DCHECK_LT(0, x.size());
+ float mean = std::accumulate(x.data(), x.data() + x.size(), 0.f);
+ mean /= x.size();
+
+ for (float& v : x) {
+ v -= mean;
+ }
+}
+
+void PowerSpectrum(const OouraFft* ooura_fft,
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> spectrum) {
+ RTC_DCHECK_EQ(65, spectrum.size());
+ RTC_DCHECK_EQ(128, x.size());
+ float X[128];
+ std::copy(x.data(), x.data() + x.size(), X);
+ ooura_fft->Fft(X);
+
+ float* X_p = X;
+ RTC_DCHECK_EQ(X_p, &X[0]);
+ spectrum[0] = (*X_p) * (*X_p);
+ ++X_p;
+ RTC_DCHECK_EQ(X_p, &X[1]);
+ spectrum[64] = (*X_p) * (*X_p);
+ for (int k = 1; k < 64; ++k) {
+ ++X_p;
+ RTC_DCHECK_EQ(X_p, &X[2 * k]);
+ spectrum[k] = (*X_p) * (*X_p);
+ ++X_p;
+ RTC_DCHECK_EQ(X_p, &X[2 * k + 1]);
+ spectrum[k] += (*X_p) * (*X_p);
+ }
+}
+
+webrtc::SignalClassifier::SignalType ClassifySignal(
+ rtc::ArrayView<const float> signal_spectrum,
+ rtc::ArrayView<const float> noise_spectrum,
+ ApmDataDumper* data_dumper) {
+ int num_stationary_bands = 0;
+ int num_highly_nonstationary_bands = 0;
+
+ // Detect stationary and highly nonstationary bands.
+ for (size_t k = 1; k < 40; k++) {
+ if (signal_spectrum[k] < 3 * noise_spectrum[k] &&
+ signal_spectrum[k] * 3 > noise_spectrum[k]) {
+ ++num_stationary_bands;
+ } else if (signal_spectrum[k] > 9 * noise_spectrum[k]) {
+ ++num_highly_nonstationary_bands;
+ }
+ }
+
+ data_dumper->DumpRaw("lc_num_stationary_bands", 1, &num_stationary_bands);
+ data_dumper->DumpRaw("lc_num_highly_nonstationary_bands", 1,
+ &num_highly_nonstationary_bands);
+
+ // Use the detected number of bands to classify the overall signal
+ // stationarity.
+ if (num_stationary_bands > 15) {
+ return SignalClassifier::SignalType::kStationary;
+ } else {
+ return SignalClassifier::SignalType::kNonStationary;
+ }
+}
+
+} // namespace
+
+SignalClassifier::FrameExtender::FrameExtender(size_t frame_size,
+ size_t extended_frame_size)
+ : x_old_(extended_frame_size - frame_size, 0.f) {}
+
+SignalClassifier::FrameExtender::~FrameExtender() = default;
+
+void SignalClassifier::FrameExtender::ExtendFrame(
+ rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> x_extended) {
+ RTC_DCHECK_EQ(x_old_.size() + x.size(), x_extended.size());
+ std::copy(x_old_.data(), x_old_.data() + x_old_.size(), x_extended.data());
+ std::copy(x.data(), x.data() + x.size(), x_extended.data() + x_old_.size());
+ std::copy(x_extended.data() + x_extended.size() - x_old_.size(),
+ x_extended.data() + x_extended.size(), x_old_.data());
+}
+
+SignalClassifier::SignalClassifier(ApmDataDumper* data_dumper)
+ : data_dumper_(data_dumper),
+ down_sampler_(data_dumper_),
+ noise_spectrum_estimator_(data_dumper_),
+ ooura_fft_(IsSse2Available()) {
+ Initialize(48000);
+}
+SignalClassifier::~SignalClassifier() {}
+
+void SignalClassifier::Initialize(int sample_rate_hz) {
+ down_sampler_.Initialize(sample_rate_hz);
+ noise_spectrum_estimator_.Initialize();
+ frame_extender_.reset(new FrameExtender(80, 128));
+ sample_rate_hz_ = sample_rate_hz;
+ initialization_frames_left_ = 2;
+ consistent_classification_counter_ = 3;
+ last_signal_type_ = SignalClassifier::SignalType::kNonStationary;
+}
+
+SignalClassifier::SignalType SignalClassifier::Analyze(
+ rtc::ArrayView<const float> signal) {
+ RTC_DCHECK_EQ(signal.size(), sample_rate_hz_ / 100);
+
+ // Compute the signal power spectrum.
+ float downsampled_frame[80];
+ down_sampler_.DownSample(signal, downsampled_frame);
+ float extended_frame[128];
+ frame_extender_->ExtendFrame(downsampled_frame, extended_frame);
+ RemoveDcLevel(extended_frame);
+ float signal_spectrum[65];
+ PowerSpectrum(&ooura_fft_, extended_frame, signal_spectrum);
+
+ // Classify the signal based on the estimate of the noise spectrum and the
+ // signal spectrum estimate.
+ const SignalType signal_type = ClassifySignal(
+ signal_spectrum, noise_spectrum_estimator_.GetNoiseSpectrum(),
+ data_dumper_);
+
+ // Update the noise spectrum based on the signal spectrum.
+ noise_spectrum_estimator_.Update(signal_spectrum,
+ initialization_frames_left_ > 0);
+
+ // Update the number of frames until a reliable signal spectrum is achieved.
+ initialization_frames_left_ = std::max(0, initialization_frames_left_ - 1);
+
+ if (last_signal_type_ == signal_type) {
+ consistent_classification_counter_ =
+ std::max(0, consistent_classification_counter_ - 1);
+ } else {
+ last_signal_type_ = signal_type;
+ consistent_classification_counter_ = 3;
+ }
+
+ if (consistent_classification_counter_ > 0) {
+ return SignalClassifier::SignalType::kNonStationary;
+ }
+ return signal_type;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/signal_classifier.h b/webrtc/modules/audio_processing/agc2/signal_classifier.h
new file mode 100644
index 0000000..20cce92
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/signal_classifier.h
@@ -0,0 +1,73 @@
+/*
+ * 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_AUDIO_PROCESSING_AGC2_SIGNAL_CLASSIFIER_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_SIGNAL_CLASSIFIER_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
+#include "modules/audio_processing/agc2/down_sampler.h"
+#include "modules/audio_processing/agc2/noise_spectrum_estimator.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+class AudioBuffer;
+
+class SignalClassifier {
+ public:
+ enum class SignalType { kNonStationary, kStationary };
+
+ explicit SignalClassifier(ApmDataDumper* data_dumper);
+
+ SignalClassifier() = delete;
+ SignalClassifier(const SignalClassifier&) = delete;
+ SignalClassifier& operator=(const SignalClassifier&) = delete;
+
+ ~SignalClassifier();
+
+ void Initialize(int sample_rate_hz);
+ SignalType Analyze(rtc::ArrayView<const float> signal);
+
+ private:
+ class FrameExtender {
+ public:
+ FrameExtender(size_t frame_size, size_t extended_frame_size);
+
+ FrameExtender() = delete;
+ FrameExtender(const FrameExtender&) = delete;
+ FrameExtender& operator=(const FrameExtender&) = delete;
+
+ ~FrameExtender();
+
+ void ExtendFrame(rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> x_extended);
+
+ private:
+ std::vector<float> x_old_;
+ };
+
+ ApmDataDumper* const data_dumper_;
+ DownSampler down_sampler_;
+ std::unique_ptr<FrameExtender> frame_extender_;
+ NoiseSpectrumEstimator noise_spectrum_estimator_;
+ int sample_rate_hz_;
+ int initialization_frames_left_;
+ int consistent_classification_counter_;
+ SignalType last_signal_type_;
+ const OouraFft ooura_fft_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_SIGNAL_CLASSIFIER_H_
diff --git a/webrtc/modules/audio_processing/agc2/vad_with_level.cc b/webrtc/modules/audio_processing/agc2/vad_with_level.cc
new file mode 100644
index 0000000..3dbb557
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/vad_with_level.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/vad_with_level.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+
+#include "api/array_view.h"
+#include "common_audio/include/audio_util.h"
+#include "common_audio/resampler/include/push_resampler.h"
+#include "modules/audio_processing/agc2/agc2_common.h"
+#include "modules/audio_processing/agc2/rnn_vad/common.h"
+#include "modules/audio_processing/agc2/rnn_vad/features_extraction.h"
+#include "modules/audio_processing/agc2/rnn_vad/rnn.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+using VoiceActivityDetector = VadLevelAnalyzer::VoiceActivityDetector;
+
+// Default VAD that combines a resampler and the RNN VAD.
+// Computes the speech probability on the first channel.
+class Vad : public VoiceActivityDetector {
+ public:
+ Vad() = default;
+ Vad(const Vad&) = delete;
+ Vad& operator=(const Vad&) = delete;
+ ~Vad() = default;
+
+ float ComputeProbability(AudioFrameView<const float> frame) override {
+ // The source number of channels is 1, because we always use the 1st
+ // channel.
+ resampler_.InitializeIfNeeded(
+ /*sample_rate_hz=*/static_cast<int>(frame.samples_per_channel() * 100),
+ rnn_vad::kSampleRate24kHz,
+ /*num_channels=*/1);
+
+ std::array<float, rnn_vad::kFrameSize10ms24kHz> work_frame;
+ // Feed the 1st channel to the resampler.
+ resampler_.Resample(frame.channel(0).data(), frame.samples_per_channel(),
+ work_frame.data(), rnn_vad::kFrameSize10ms24kHz);
+
+ std::array<float, rnn_vad::kFeatureVectorSize> feature_vector;
+ const bool is_silence = features_extractor_.CheckSilenceComputeFeatures(
+ work_frame, feature_vector);
+ return rnn_vad_.ComputeVadProbability(feature_vector, is_silence);
+ }
+
+ private:
+ PushResampler<float> resampler_;
+ rnn_vad::FeaturesExtractor features_extractor_;
+ rnn_vad::RnnBasedVad rnn_vad_;
+};
+
+// Returns an updated version of `p_old` by using instant decay and the given
+// `attack` on a new VAD probability value `p_new`.
+float SmoothedVadProbability(float p_old, float p_new, float attack) {
+ RTC_DCHECK_GT(attack, 0.f);
+ RTC_DCHECK_LE(attack, 1.f);
+ if (p_new < p_old || attack == 1.f) {
+ // Instant decay (or no smoothing).
+ return p_new;
+ } else {
+ // Attack phase.
+ return attack * p_new + (1.f - attack) * p_old;
+ }
+}
+
+} // namespace
+
+VadLevelAnalyzer::VadLevelAnalyzer()
+ : VadLevelAnalyzer(kDefaultSmoothedVadProbabilityAttack,
+ std::make_unique<Vad>()) {}
+
+VadLevelAnalyzer::VadLevelAnalyzer(float vad_probability_attack)
+ : VadLevelAnalyzer(vad_probability_attack, std::make_unique<Vad>()) {}
+
+VadLevelAnalyzer::VadLevelAnalyzer(float vad_probability_attack,
+ std::unique_ptr<VoiceActivityDetector> vad)
+ : vad_(std::move(vad)), vad_probability_attack_(vad_probability_attack) {
+ RTC_DCHECK(vad_);
+}
+
+VadLevelAnalyzer::~VadLevelAnalyzer() = default;
+
+VadLevelAnalyzer::Result VadLevelAnalyzer::AnalyzeFrame(
+ AudioFrameView<const float> frame) {
+ // Compute levels.
+ float peak = 0.f;
+ float rms = 0.f;
+ for (const auto& x : frame.channel(0)) {
+ peak = std::max(std::fabs(x), peak);
+ rms += x * x;
+ }
+ // Compute smoothed speech probability.
+ vad_probability_ = SmoothedVadProbability(
+ /*p_old=*/vad_probability_, /*p_new=*/vad_->ComputeProbability(frame),
+ vad_probability_attack_);
+ return {vad_probability_,
+ FloatS16ToDbfs(std::sqrt(rms / frame.samples_per_channel())),
+ FloatS16ToDbfs(peak)};
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/vad_with_level.h b/webrtc/modules/audio_processing/agc2/vad_with_level.h
new file mode 100644
index 0000000..ce72cdc
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/vad_with_level.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_
+
+#include <memory>
+
+#include "modules/audio_processing/include/audio_frame_view.h"
+
+namespace webrtc {
+
+// Class to analyze voice activity and audio levels.
+class VadLevelAnalyzer {
+ public:
+ struct Result {
+ float speech_probability; // Range: [0, 1].
+ float rms_dbfs; // Root mean square power (dBFS).
+ float peak_dbfs; // Peak power (dBFS).
+ };
+
+ // Voice Activity Detector (VAD) interface.
+ class VoiceActivityDetector {
+ public:
+ virtual ~VoiceActivityDetector() = default;
+ // Analyzes an audio frame and returns the speech probability.
+ virtual float ComputeProbability(AudioFrameView<const float> frame) = 0;
+ };
+
+ // Ctor. Uses the default VAD.
+ VadLevelAnalyzer();
+ explicit VadLevelAnalyzer(float vad_probability_attack);
+ // Ctor. Uses a custom `vad`.
+ VadLevelAnalyzer(float vad_probability_attack,
+ std::unique_ptr<VoiceActivityDetector> vad);
+ VadLevelAnalyzer(const VadLevelAnalyzer&) = delete;
+ VadLevelAnalyzer& operator=(const VadLevelAnalyzer&) = delete;
+ ~VadLevelAnalyzer();
+
+ // Computes the speech probability and the level for `frame`.
+ Result AnalyzeFrame(AudioFrameView<const float> frame);
+
+ private:
+ std::unique_ptr<VoiceActivityDetector> vad_;
+ const float vad_probability_attack_;
+ float vad_probability_ = 0.f;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_VAD_WITH_LEVEL_H_
diff --git a/webrtc/modules/audio_processing/agc2/vector_float_frame.cc b/webrtc/modules/audio_processing/agc2/vector_float_frame.cc
new file mode 100644
index 0000000..a70d815
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/vector_float_frame.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/agc2/vector_float_frame.h"
+
+namespace webrtc {
+
+namespace {
+
+std::vector<float*> ConstructChannelPointers(
+ std::vector<std::vector<float>>* x) {
+ std::vector<float*> channel_ptrs;
+ for (auto& v : *x) {
+ channel_ptrs.push_back(v.data());
+ }
+ return channel_ptrs;
+}
+} // namespace
+
+VectorFloatFrame::VectorFloatFrame(int num_channels,
+ int samples_per_channel,
+ float start_value)
+ : channels_(num_channels,
+ std::vector<float>(samples_per_channel, start_value)),
+ channel_ptrs_(ConstructChannelPointers(&channels_)),
+ float_frame_view_(channel_ptrs_.data(),
+ channels_.size(),
+ samples_per_channel) {}
+
+VectorFloatFrame::~VectorFloatFrame() = default;
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/agc2/vector_float_frame.h b/webrtc/modules/audio_processing/agc2/vector_float_frame.h
new file mode 100644
index 0000000..b521f34
--- /dev/null
+++ b/webrtc/modules/audio_processing/agc2/vector_float_frame.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_AGC2_VECTOR_FLOAT_FRAME_H_
+#define MODULES_AUDIO_PROCESSING_AGC2_VECTOR_FLOAT_FRAME_H_
+
+#include <vector>
+
+#include "modules/audio_processing/include/audio_frame_view.h"
+
+namespace webrtc {
+
+// A construct consisting of a multi-channel audio frame, and a FloatFrame view
+// of it.
+class VectorFloatFrame {
+ public:
+ VectorFloatFrame(int num_channels,
+ int samples_per_channel,
+ float start_value);
+ const AudioFrameView<float>& float_frame_view() { return float_frame_view_; }
+ AudioFrameView<const float> float_frame_view() const {
+ return float_frame_view_;
+ }
+
+ ~VectorFloatFrame();
+
+ private:
+ std::vector<std::vector<float>> channels_;
+ std::vector<float*> channel_ptrs_;
+ AudioFrameView<float> float_frame_view_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_AGC2_VECTOR_FLOAT_FRAME_H_
diff --git a/webrtc/modules/audio_processing/audio_buffer.cc b/webrtc/modules/audio_processing/audio_buffer.cc
index 81790a1..ff6636d 100644
--- a/webrtc/modules/audio_processing/audio_buffer.cc
+++ b/webrtc/modules/audio_processing/audio_buffer.cc
@@ -8,455 +8,400 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/audio_buffer.h"
-#include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/channel_buffer.h"
-#include "webrtc/modules/audio_processing/common.h"
+#include <string.h>
+
+#include <cstdint>
+
+#include "common_audio/channel_buffer.h"
+#include "common_audio/include/audio_util.h"
+#include "common_audio/resampler/push_sinc_resampler.h"
+#include "modules/audio_processing/splitting_filter.h"
+#include "rtc_base/checks.h"
namespace webrtc {
namespace {
-const size_t kSamplesPer16kHzChannel = 160;
-const size_t kSamplesPer32kHzChannel = 320;
-const size_t kSamplesPer48kHzChannel = 480;
+constexpr size_t kSamplesPer32kHzChannel = 320;
+constexpr size_t kSamplesPer48kHzChannel = 480;
+constexpr size_t kMaxSamplesPerChannel = AudioBuffer::kMaxSampleRate / 100;
-int KeyboardChannelIndex(const StreamConfig& stream_config) {
- if (!stream_config.has_keyboard()) {
- assert(false);
- return -1;
+size_t NumBandsFromFramesPerChannel(size_t num_frames) {
+ if (num_frames == kSamplesPer32kHzChannel) {
+ return 2;
}
-
- return stream_config.num_channels();
-}
-
-size_t NumBandsFromSamplesPerChannel(size_t num_frames) {
- size_t num_bands = 1;
- if (num_frames == kSamplesPer32kHzChannel ||
- num_frames == kSamplesPer48kHzChannel) {
- num_bands = rtc::CheckedDivExact(num_frames, kSamplesPer16kHzChannel);
+ if (num_frames == kSamplesPer48kHzChannel) {
+ return 3;
}
- return num_bands;
+ return 1;
}
} // namespace
+AudioBuffer::AudioBuffer(size_t input_rate,
+ size_t input_num_channels,
+ size_t buffer_rate,
+ size_t buffer_num_channels,
+ size_t output_rate,
+ size_t output_num_channels)
+ : AudioBuffer(static_cast<int>(input_rate) / 100,
+ input_num_channels,
+ static_cast<int>(buffer_rate) / 100,
+ buffer_num_channels,
+ static_cast<int>(output_rate) / 100) {}
+
AudioBuffer::AudioBuffer(size_t input_num_frames,
- int num_input_channels,
- size_t process_num_frames,
- int num_process_channels,
+ size_t input_num_channels,
+ size_t buffer_num_frames,
+ size_t buffer_num_channels,
size_t output_num_frames)
- : input_num_frames_(input_num_frames),
- num_input_channels_(num_input_channels),
- proc_num_frames_(process_num_frames),
- num_proc_channels_(num_process_channels),
- output_num_frames_(output_num_frames),
- num_channels_(num_process_channels),
- num_bands_(NumBandsFromSamplesPerChannel(proc_num_frames_)),
- num_split_frames_(rtc::CheckedDivExact(proc_num_frames_, num_bands_)),
- mixed_low_pass_valid_(false),
- reference_copied_(false),
- activity_(AudioFrame::kVadUnknown),
- keyboard_data_(NULL),
- data_(new IFChannelBuffer(proc_num_frames_, num_proc_channels_)) {
- assert(input_num_frames_ > 0);
- assert(proc_num_frames_ > 0);
- assert(output_num_frames_ > 0);
- assert(num_input_channels_ > 0);
- assert(num_proc_channels_ > 0 && num_proc_channels_ <= num_input_channels_);
-
- if (input_num_frames_ != proc_num_frames_ ||
- output_num_frames_ != proc_num_frames_) {
- // Create an intermediate buffer for resampling.
- process_buffer_.reset(new ChannelBuffer<float>(proc_num_frames_,
- num_proc_channels_));
-
- if (input_num_frames_ != proc_num_frames_) {
- for (int i = 0; i < num_proc_channels_; ++i) {
- input_resamplers_.push_back(
- new PushSincResampler(input_num_frames_,
- proc_num_frames_));
- }
+ : input_num_frames_(input_num_frames),
+ input_num_channels_(input_num_channels),
+ buffer_num_frames_(buffer_num_frames),
+ buffer_num_channels_(buffer_num_channels),
+ output_num_frames_(output_num_frames),
+ output_num_channels_(0),
+ num_channels_(buffer_num_channels),
+ num_bands_(NumBandsFromFramesPerChannel(buffer_num_frames_)),
+ num_split_frames_(rtc::CheckedDivExact(buffer_num_frames_, num_bands_)),
+ data_(
+ new ChannelBuffer<float>(buffer_num_frames_, buffer_num_channels_)) {
+ RTC_DCHECK_GT(input_num_frames_, 0);
+ RTC_DCHECK_GT(buffer_num_frames_, 0);
+ RTC_DCHECK_GT(output_num_frames_, 0);
+ RTC_DCHECK_GT(input_num_channels_, 0);
+ RTC_DCHECK_GT(buffer_num_channels_, 0);
+ RTC_DCHECK_LE(buffer_num_channels_, input_num_channels_);
+
+ const bool input_resampling_needed = input_num_frames_ != buffer_num_frames_;
+ const bool output_resampling_needed =
+ output_num_frames_ != buffer_num_frames_;
+ if (input_resampling_needed) {
+ for (size_t i = 0; i < buffer_num_channels_; ++i) {
+ input_resamplers_.push_back(std::unique_ptr<PushSincResampler>(
+ new PushSincResampler(input_num_frames_, buffer_num_frames_)));
}
+ }
- if (output_num_frames_ != proc_num_frames_) {
- for (int i = 0; i < num_proc_channels_; ++i) {
- output_resamplers_.push_back(
- new PushSincResampler(proc_num_frames_,
- output_num_frames_));
- }
+ if (output_resampling_needed) {
+ for (size_t i = 0; i < buffer_num_channels_; ++i) {
+ output_resamplers_.push_back(std::unique_ptr<PushSincResampler>(
+ new PushSincResampler(buffer_num_frames_, output_num_frames_)));
}
}
if (num_bands_ > 1) {
- split_data_.reset(new IFChannelBuffer(proc_num_frames_,
- num_proc_channels_,
- num_bands_));
- splitting_filter_.reset(new SplittingFilter(num_proc_channels_,
- num_bands_,
- proc_num_frames_));
+ split_data_.reset(new ChannelBuffer<float>(
+ buffer_num_frames_, buffer_num_channels_, num_bands_));
+ splitting_filter_.reset(new SplittingFilter(
+ buffer_num_channels_, num_bands_, buffer_num_frames_));
}
}
AudioBuffer::~AudioBuffer() {}
-void AudioBuffer::CopyFrom(const float* const* data,
- const StreamConfig& stream_config) {
- assert(stream_config.num_frames() == input_num_frames_);
- assert(stream_config.num_channels() == num_input_channels_);
- InitForNewData();
- // Initialized lazily because there's a different condition in
- // DeinterleaveFrom.
- const bool need_to_downmix =
- num_input_channels_ > 1 && num_proc_channels_ == 1;
- if (need_to_downmix && !input_buffer_) {
- input_buffer_.reset(
- new IFChannelBuffer(input_num_frames_, num_proc_channels_));
- }
-
- if (stream_config.has_keyboard()) {
- keyboard_data_ = data[KeyboardChannelIndex(stream_config)];
- }
+void AudioBuffer::set_downmixing_to_specific_channel(size_t channel) {
+ downmix_by_averaging_ = false;
+ RTC_DCHECK_GT(input_num_channels_, channel);
+ channel_for_downmixing_ = std::min(channel, input_num_channels_ - 1);
+}
- // Downmix.
- const float* const* data_ptr = data;
- if (need_to_downmix) {
- DownmixToMono<float, float>(data, input_num_frames_, num_input_channels_,
- input_buffer_->fbuf()->channels()[0]);
- data_ptr = input_buffer_->fbuf_const()->channels();
- }
+void AudioBuffer::set_downmixing_by_averaging() {
+ downmix_by_averaging_ = true;
+}
- // Resample.
- if (input_num_frames_ != proc_num_frames_) {
- for (int i = 0; i < num_proc_channels_; ++i) {
- input_resamplers_[i]->Resample(data_ptr[i],
- input_num_frames_,
- process_buffer_->channels()[i],
- proc_num_frames_);
+void AudioBuffer::CopyFrom(const float* const* stacked_data,
+ const StreamConfig& stream_config) {
+ RTC_DCHECK_EQ(stream_config.num_frames(), input_num_frames_);
+ RTC_DCHECK_EQ(stream_config.num_channels(), input_num_channels_);
+ RestoreNumChannels();
+ const bool downmix_needed = input_num_channels_ > 1 && num_channels_ == 1;
+
+ const bool resampling_needed = input_num_frames_ != buffer_num_frames_;
+
+ if (downmix_needed) {
+ RTC_DCHECK_GE(kMaxSamplesPerChannel, input_num_frames_);
+
+ std::array<float, kMaxSamplesPerChannel> downmix;
+ if (downmix_by_averaging_) {
+ const float kOneByNumChannels = 1.f / input_num_channels_;
+ for (size_t i = 0; i < input_num_frames_; ++i) {
+ float value = stacked_data[0][i];
+ for (size_t j = 1; j < input_num_channels_; ++j) {
+ value += stacked_data[j][i];
+ }
+ downmix[i] = value * kOneByNumChannels;
+ }
}
- data_ptr = process_buffer_->channels();
- }
+ const float* downmixed_data = downmix_by_averaging_
+ ? downmix.data()
+ : stacked_data[channel_for_downmixing_];
- // Convert to the S16 range.
- for (int i = 0; i < num_proc_channels_; ++i) {
- FloatToFloatS16(data_ptr[i],
- proc_num_frames_,
- data_->fbuf()->channels()[i]);
+ if (resampling_needed) {
+ input_resamplers_[0]->Resample(downmixed_data, input_num_frames_,
+ data_->channels()[0], buffer_num_frames_);
+ }
+ const float* data_to_convert =
+ resampling_needed ? data_->channels()[0] : downmixed_data;
+ FloatToFloatS16(data_to_convert, buffer_num_frames_, data_->channels()[0]);
+ } else {
+ if (resampling_needed) {
+ for (size_t i = 0; i < num_channels_; ++i) {
+ input_resamplers_[i]->Resample(stacked_data[i], input_num_frames_,
+ data_->channels()[i],
+ buffer_num_frames_);
+ FloatToFloatS16(data_->channels()[i], buffer_num_frames_,
+ data_->channels()[i]);
+ }
+ } else {
+ for (size_t i = 0; i < num_channels_; ++i) {
+ FloatToFloatS16(stacked_data[i], buffer_num_frames_,
+ data_->channels()[i]);
+ }
+ }
}
}
void AudioBuffer::CopyTo(const StreamConfig& stream_config,
- float* const* data) {
- assert(stream_config.num_frames() == output_num_frames_);
- assert(stream_config.num_channels() == num_channels_);
-
- // Convert to the float range.
- float* const* data_ptr = data;
- if (output_num_frames_ != proc_num_frames_) {
- // Convert to an intermediate buffer for subsequent resampling.
- data_ptr = process_buffer_->channels();
- }
- for (int i = 0; i < num_channels_; ++i) {
- FloatS16ToFloat(data_->fbuf()->channels()[i],
- proc_num_frames_,
- data_ptr[i]);
- }
-
- // Resample.
- if (output_num_frames_ != proc_num_frames_) {
- for (int i = 0; i < num_channels_; ++i) {
- output_resamplers_[i]->Resample(data_ptr[i],
- proc_num_frames_,
- data[i],
- output_num_frames_);
+ float* const* stacked_data) {
+ RTC_DCHECK_EQ(stream_config.num_frames(), output_num_frames_);
+
+ const bool resampling_needed = output_num_frames_ != buffer_num_frames_;
+ if (resampling_needed) {
+ for (size_t i = 0; i < num_channels_; ++i) {
+ FloatS16ToFloat(data_->channels()[i], buffer_num_frames_,
+ data_->channels()[i]);
+ output_resamplers_[i]->Resample(data_->channels()[i], buffer_num_frames_,
+ stacked_data[i], output_num_frames_);
+ }
+ } else {
+ for (size_t i = 0; i < num_channels_; ++i) {
+ FloatS16ToFloat(data_->channels()[i], buffer_num_frames_,
+ stacked_data[i]);
}
}
-}
-
-void AudioBuffer::InitForNewData() {
- keyboard_data_ = NULL;
- mixed_low_pass_valid_ = false;
- reference_copied_ = false;
- activity_ = AudioFrame::kVadUnknown;
- num_channels_ = num_proc_channels_;
-}
-
-const int16_t* const* AudioBuffer::channels_const() const {
- return data_->ibuf_const()->channels();
-}
-int16_t* const* AudioBuffer::channels() {
- mixed_low_pass_valid_ = false;
- return data_->ibuf()->channels();
-}
-
-const int16_t* const* AudioBuffer::split_bands_const(int channel) const {
- return split_data_.get() ?
- split_data_->ibuf_const()->bands(channel) :
- data_->ibuf_const()->bands(channel);
+ for (size_t i = num_channels_; i < stream_config.num_channels(); ++i) {
+ memcpy(stacked_data[i], stacked_data[0],
+ output_num_frames_ * sizeof(**stacked_data));
+ }
}
-int16_t* const* AudioBuffer::split_bands(int channel) {
- mixed_low_pass_valid_ = false;
- return split_data_.get() ?
- split_data_->ibuf()->bands(channel) :
- data_->ibuf()->bands(channel);
-}
+void AudioBuffer::CopyTo(AudioBuffer* buffer) const {
+ RTC_DCHECK_EQ(buffer->num_frames(), output_num_frames_);
-const int16_t* const* AudioBuffer::split_channels_const(Band band) const {
- if (split_data_.get()) {
- return split_data_->ibuf_const()->channels(band);
+ const bool resampling_needed = output_num_frames_ != buffer_num_frames_;
+ if (resampling_needed) {
+ for (size_t i = 0; i < num_channels_; ++i) {
+ output_resamplers_[i]->Resample(data_->channels()[i], buffer_num_frames_,
+ buffer->channels()[i],
+ buffer->num_frames());
+ }
} else {
- return band == kBand0To8kHz ? data_->ibuf_const()->channels() : nullptr;
+ for (size_t i = 0; i < num_channels_; ++i) {
+ memcpy(buffer->channels()[i], data_->channels()[i],
+ buffer_num_frames_ * sizeof(**buffer->channels()));
+ }
}
-}
-int16_t* const* AudioBuffer::split_channels(Band band) {
- mixed_low_pass_valid_ = false;
- if (split_data_.get()) {
- return split_data_->ibuf()->channels(band);
- } else {
- return band == kBand0To8kHz ? data_->ibuf()->channels() : nullptr;
+ for (size_t i = num_channels_; i < buffer->num_channels(); ++i) {
+ memcpy(buffer->channels()[i], buffer->channels()[0],
+ output_num_frames_ * sizeof(**buffer->channels()));
}
}
-ChannelBuffer<int16_t>* AudioBuffer::data() {
- mixed_low_pass_valid_ = false;
- return data_->ibuf();
-}
-
-const ChannelBuffer<int16_t>* AudioBuffer::data() const {
- return data_->ibuf_const();
-}
-
-ChannelBuffer<int16_t>* AudioBuffer::split_data() {
- mixed_low_pass_valid_ = false;
- return split_data_.get() ? split_data_->ibuf() : data_->ibuf();
-}
-
-const ChannelBuffer<int16_t>* AudioBuffer::split_data() const {
- return split_data_.get() ? split_data_->ibuf_const() : data_->ibuf_const();
-}
-
-const float* const* AudioBuffer::channels_const_f() const {
- return data_->fbuf_const()->channels();
-}
-
-float* const* AudioBuffer::channels_f() {
- mixed_low_pass_valid_ = false;
- return data_->fbuf()->channels();
-}
-
-const float* const* AudioBuffer::split_bands_const_f(int channel) const {
- return split_data_.get() ?
- split_data_->fbuf_const()->bands(channel) :
- data_->fbuf_const()->bands(channel);
-}
-
-float* const* AudioBuffer::split_bands_f(int channel) {
- mixed_low_pass_valid_ = false;
- return split_data_.get() ?
- split_data_->fbuf()->bands(channel) :
- data_->fbuf()->bands(channel);
-}
-
-const float* const* AudioBuffer::split_channels_const_f(Band band) const {
+void AudioBuffer::RestoreNumChannels() {
+ num_channels_ = buffer_num_channels_;
+ data_->set_num_channels(buffer_num_channels_);
if (split_data_.get()) {
- return split_data_->fbuf_const()->channels(band);
- } else {
- return band == kBand0To8kHz ? data_->fbuf_const()->channels() : nullptr;
+ split_data_->set_num_channels(buffer_num_channels_);
}
}
-float* const* AudioBuffer::split_channels_f(Band band) {
- mixed_low_pass_valid_ = false;
+void AudioBuffer::set_num_channels(size_t num_channels) {
+ RTC_DCHECK_GE(buffer_num_channels_, num_channels);
+ num_channels_ = num_channels;
+ data_->set_num_channels(num_channels);
if (split_data_.get()) {
- return split_data_->fbuf()->channels(band);
- } else {
- return band == kBand0To8kHz ? data_->fbuf()->channels() : nullptr;
+ split_data_->set_num_channels(num_channels);
}
}
-ChannelBuffer<float>* AudioBuffer::data_f() {
- mixed_low_pass_valid_ = false;
- return data_->fbuf();
-}
-
-const ChannelBuffer<float>* AudioBuffer::data_f() const {
- return data_->fbuf_const();
-}
-
-ChannelBuffer<float>* AudioBuffer::split_data_f() {
- mixed_low_pass_valid_ = false;
- return split_data_.get() ? split_data_->fbuf() : data_->fbuf();
-}
-
-const ChannelBuffer<float>* AudioBuffer::split_data_f() const {
- return split_data_.get() ? split_data_->fbuf_const() : data_->fbuf_const();
-}
-
-const int16_t* AudioBuffer::mixed_low_pass_data() {
- if (num_proc_channels_ == 1) {
- return split_bands_const(0)[kBand0To8kHz];
- }
+// The resampler is only for supporting 48kHz to 16kHz in the reverse stream.
+void AudioBuffer::CopyFrom(const int16_t* const interleaved_data,
+ const StreamConfig& stream_config) {
+ RTC_DCHECK_EQ(stream_config.num_channels(), input_num_channels_);
+ RTC_DCHECK_EQ(stream_config.num_frames(), input_num_frames_);
+ RestoreNumChannels();
+
+ const bool resampling_required = input_num_frames_ != buffer_num_frames_;
+
+ const int16_t* interleaved = interleaved_data;
+ if (num_channels_ == 1) {
+ if (input_num_channels_ == 1) {
+ if (resampling_required) {
+ std::array<float, kMaxSamplesPerChannel> float_buffer;
+ S16ToFloatS16(interleaved, input_num_frames_, float_buffer.data());
+ input_resamplers_[0]->Resample(float_buffer.data(), input_num_frames_,
+ data_->channels()[0],
+ buffer_num_frames_);
+ } else {
+ S16ToFloatS16(interleaved, input_num_frames_, data_->channels()[0]);
+ }
+ } else {
+ std::array<float, kMaxSamplesPerChannel> float_buffer;
+ float* downmixed_data =
+ resampling_required ? float_buffer.data() : data_->channels()[0];
+ if (downmix_by_averaging_) {
+ for (size_t j = 0, k = 0; j < input_num_frames_; ++j) {
+ int32_t sum = 0;
+ for (size_t i = 0; i < input_num_channels_; ++i, ++k) {
+ sum += interleaved[k];
+ }
+ downmixed_data[j] = sum / static_cast<int16_t>(input_num_channels_);
+ }
+ } else {
+ for (size_t j = 0, k = channel_for_downmixing_; j < input_num_frames_;
+ ++j, k += input_num_channels_) {
+ downmixed_data[j] = interleaved[k];
+ }
+ }
- if (!mixed_low_pass_valid_) {
- if (!mixed_low_pass_channels_.get()) {
- mixed_low_pass_channels_.reset(
- new ChannelBuffer<int16_t>(num_split_frames_, 1));
+ if (resampling_required) {
+ input_resamplers_[0]->Resample(downmixed_data, input_num_frames_,
+ data_->channels()[0],
+ buffer_num_frames_);
+ }
+ }
+ } else {
+ auto deinterleave_channel = [](size_t channel, size_t num_channels,
+ size_t samples_per_channel, const int16_t* x,
+ float* y) {
+ for (size_t j = 0, k = channel; j < samples_per_channel;
+ ++j, k += num_channels) {
+ y[j] = x[k];
+ }
+ };
+
+ if (resampling_required) {
+ std::array<float, kMaxSamplesPerChannel> float_buffer;
+ for (size_t i = 0; i < num_channels_; ++i) {
+ deinterleave_channel(i, num_channels_, input_num_frames_, interleaved,
+ float_buffer.data());
+ input_resamplers_[i]->Resample(float_buffer.data(), input_num_frames_,
+ data_->channels()[i],
+ buffer_num_frames_);
+ }
+ } else {
+ for (size_t i = 0; i < num_channels_; ++i) {
+ deinterleave_channel(i, num_channels_, input_num_frames_, interleaved,
+ data_->channels()[i]);
+ }
}
-
- DownmixToMono<int16_t, int32_t>(split_channels_const(kBand0To8kHz),
- num_split_frames_, num_channels_,
- mixed_low_pass_channels_->channels()[0]);
- mixed_low_pass_valid_ = true;
- }
- return mixed_low_pass_channels_->channels()[0];
-}
-
-const int16_t* AudioBuffer::low_pass_reference(int channel) const {
- if (!reference_copied_) {
- return NULL;
}
-
- return low_pass_reference_channels_->channels()[channel];
}
-const float* AudioBuffer::keyboard_data() const {
- return keyboard_data_;
-}
+void AudioBuffer::CopyTo(const StreamConfig& stream_config,
+ int16_t* const interleaved_data) {
+ const size_t config_num_channels = stream_config.num_channels();
-void AudioBuffer::set_activity(AudioFrame::VADActivity activity) {
- activity_ = activity;
-}
+ RTC_DCHECK(config_num_channels == num_channels_ || num_channels_ == 1);
+ RTC_DCHECK_EQ(stream_config.num_frames(), output_num_frames_);
-AudioFrame::VADActivity AudioBuffer::activity() const {
- return activity_;
-}
+ const bool resampling_required = buffer_num_frames_ != output_num_frames_;
-int AudioBuffer::num_channels() const {
- return num_channels_;
-}
+ int16_t* interleaved = interleaved_data;
+ if (num_channels_ == 1) {
+ std::array<float, kMaxSamplesPerChannel> float_buffer;
-void AudioBuffer::set_num_channels(int num_channels) {
- num_channels_ = num_channels;
-}
+ if (resampling_required) {
+ output_resamplers_[0]->Resample(data_->channels()[0], buffer_num_frames_,
+ float_buffer.data(), output_num_frames_);
+ }
+ const float* deinterleaved =
+ resampling_required ? float_buffer.data() : data_->channels()[0];
-size_t AudioBuffer::num_frames() const {
- return proc_num_frames_;
-}
+ if (config_num_channels == 1) {
+ for (size_t j = 0; j < output_num_frames_; ++j) {
+ interleaved[j] = FloatS16ToS16(deinterleaved[j]);
+ }
+ } else {
+ for (size_t i = 0, k = 0; i < output_num_frames_; ++i) {
+ float tmp = FloatS16ToS16(deinterleaved[i]);
+ for (size_t j = 0; j < config_num_channels; ++j, ++k) {
+ interleaved[k] = tmp;
+ }
+ }
+ }
+ } else {
+ auto interleave_channel = [](size_t channel, size_t num_channels,
+ size_t samples_per_channel, const float* x,
+ int16_t* y) {
+ for (size_t k = 0, j = channel; k < samples_per_channel;
+ ++k, j += num_channels) {
+ y[j] = FloatS16ToS16(x[k]);
+ }
+ };
+
+ if (resampling_required) {
+ for (size_t i = 0; i < num_channels_; ++i) {
+ std::array<float, kMaxSamplesPerChannel> float_buffer;
+ output_resamplers_[i]->Resample(data_->channels()[i],
+ buffer_num_frames_, float_buffer.data(),
+ output_num_frames_);
+ interleave_channel(i, config_num_channels, output_num_frames_,
+ float_buffer.data(), interleaved);
+ }
+ } else {
+ for (size_t i = 0; i < num_channels_; ++i) {
+ interleave_channel(i, config_num_channels, output_num_frames_,
+ data_->channels()[i], interleaved);
+ }
+ }
-size_t AudioBuffer::num_frames_per_band() const {
- return num_split_frames_;
+ for (size_t i = num_channels_; i < config_num_channels; ++i) {
+ for (size_t j = 0, k = i, n = num_channels_; j < output_num_frames_;
+ ++j, k += config_num_channels, n += config_num_channels) {
+ interleaved[k] = interleaved[n];
+ }
+ }
+ }
}
-size_t AudioBuffer::num_keyboard_frames() const {
- // We don't resample the keyboard channel.
- return input_num_frames_;
+void AudioBuffer::SplitIntoFrequencyBands() {
+ splitting_filter_->Analysis(data_.get(), split_data_.get());
}
-size_t AudioBuffer::num_bands() const {
- return num_bands_;
+void AudioBuffer::MergeFrequencyBands() {
+ splitting_filter_->Synthesis(split_data_.get(), data_.get());
}
-// The resampler is only for supporting 48kHz to 16kHz in the reverse stream.
-void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) {
- assert(frame->num_channels_ == num_input_channels_);
- assert(frame->samples_per_channel_ == input_num_frames_);
- InitForNewData();
- // Initialized lazily because there's a different condition in CopyFrom.
- if ((input_num_frames_ != proc_num_frames_) && !input_buffer_) {
- input_buffer_.reset(
- new IFChannelBuffer(input_num_frames_, num_proc_channels_));
- }
- activity_ = frame->vad_activity_;
-
- int16_t* const* deinterleaved;
- if (input_num_frames_ == proc_num_frames_) {
- deinterleaved = data_->ibuf()->channels();
- } else {
- deinterleaved = input_buffer_->ibuf()->channels();
- }
- if (num_proc_channels_ == 1) {
- // Downmix and deinterleave simultaneously.
- DownmixInterleavedToMono(frame->data_, input_num_frames_,
- num_input_channels_, deinterleaved[0]);
- } else {
- assert(num_proc_channels_ == num_input_channels_);
- Deinterleave(frame->data_,
- input_num_frames_,
- num_proc_channels_,
- deinterleaved);
- }
+void AudioBuffer::ExportSplitChannelData(
+ size_t channel,
+ int16_t* const* split_band_data) const {
+ for (size_t k = 0; k < num_bands(); ++k) {
+ const float* band_data = split_bands_const(channel)[k];
- // Resample.
- if (input_num_frames_ != proc_num_frames_) {
- for (int i = 0; i < num_proc_channels_; ++i) {
- input_resamplers_[i]->Resample(input_buffer_->fbuf_const()->channels()[i],
- input_num_frames_,
- data_->fbuf()->channels()[i],
- proc_num_frames_);
+ RTC_DCHECK(split_band_data[k]);
+ RTC_DCHECK(band_data);
+ for (size_t i = 0; i < num_frames_per_band(); ++i) {
+ split_band_data[k][i] = FloatS16ToS16(band_data[i]);
}
}
}
-void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) {
- frame->vad_activity_ = activity_;
- if (!data_changed) {
- return;
- }
-
- assert(frame->num_channels_ == num_channels_ || num_channels_ == 1);
- assert(frame->samples_per_channel_ == output_num_frames_);
-
- // Resample if necessary.
- IFChannelBuffer* data_ptr = data_.get();
- if (proc_num_frames_ != output_num_frames_) {
- if (!output_buffer_) {
- output_buffer_.reset(
- new IFChannelBuffer(output_num_frames_, num_channels_));
- }
- for (int i = 0; i < num_channels_; ++i) {
- output_resamplers_[i]->Resample(
- data_->fbuf()->channels()[i], proc_num_frames_,
- output_buffer_->fbuf()->channels()[i], output_num_frames_);
+void AudioBuffer::ImportSplitChannelData(
+ size_t channel,
+ const int16_t* const* split_band_data) {
+ for (size_t k = 0; k < num_bands(); ++k) {
+ float* band_data = split_bands(channel)[k];
+ RTC_DCHECK(split_band_data[k]);
+ RTC_DCHECK(band_data);
+ for (size_t i = 0; i < num_frames_per_band(); ++i) {
+ band_data[i] = split_band_data[k][i];
}
- data_ptr = output_buffer_.get();
- }
-
- if (frame->num_channels_ == num_channels_) {
- Interleave(data_ptr->ibuf()->channels(), proc_num_frames_, num_channels_,
- frame->data_);
- } else {
- UpmixMonoToInterleaved(data_ptr->ibuf()->channels()[0], proc_num_frames_,
- frame->num_channels_, frame->data_);
- }
-}
-
-void AudioBuffer::CopyLowPassToReference() {
- reference_copied_ = true;
- if (!low_pass_reference_channels_.get() ||
- low_pass_reference_channels_->num_channels() != num_channels_) {
- low_pass_reference_channels_.reset(
- new ChannelBuffer<int16_t>(num_split_frames_,
- num_proc_channels_));
- }
- for (int i = 0; i < num_proc_channels_; i++) {
- memcpy(low_pass_reference_channels_->channels()[i],
- split_bands_const(i)[kBand0To8kHz],
- low_pass_reference_channels_->num_frames_per_band() *
- sizeof(split_bands_const(i)[kBand0To8kHz][0]));
}
}
-void AudioBuffer::SplitIntoFrequencyBands() {
- splitting_filter_->Analysis(data_.get(), split_data_.get());
-}
-
-void AudioBuffer::MergeFrequencyBands() {
- splitting_filter_->Synthesis(split_data_.get(), data_.get());
-}
-
} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/audio_buffer.h b/webrtc/modules/audio_processing/audio_buffer.h
index 864633f..3eecf0d 100644
--- a/webrtc/modules/audio_processing/audio_buffer.h
+++ b/webrtc/modules/audio_processing/audio_buffer.h
@@ -8,156 +8,171 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
+#ifndef MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/channel_buffer.h"
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/splitting_filter.h"
-#include "webrtc/modules/interface/module_common_types.h"
-#include "webrtc/system_wrappers/include/scoped_vector.h"
-#include "webrtc/typedefs.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "common_audio/channel_buffer.h"
+#include "modules/audio_processing/include/audio_processing.h"
namespace webrtc {
class PushSincResampler;
-class IFChannelBuffer;
+class SplittingFilter;
-enum Band {
- kBand0To8kHz = 0,
- kBand8To16kHz = 1,
- kBand16To24kHz = 2
-};
+enum Band { kBand0To8kHz = 0, kBand8To16kHz = 1, kBand16To24kHz = 2 };
+// Stores any audio data in a way that allows the audio processing module to
+// operate on it in a controlled manner.
class AudioBuffer {
public:
- // TODO(ajm): Switch to take ChannelLayouts.
+ static const int kSplitBandSize = 160;
+ static const size_t kMaxSampleRate = 384000;
+ AudioBuffer(size_t input_rate,
+ size_t input_num_channels,
+ size_t buffer_rate,
+ size_t buffer_num_channels,
+ size_t output_rate,
+ size_t output_num_channels);
+
+ // The constructor below will be deprecated.
AudioBuffer(size_t input_num_frames,
- int num_input_channels,
- size_t process_num_frames,
- int num_process_channels,
+ size_t input_num_channels,
+ size_t buffer_num_frames,
+ size_t buffer_num_channels,
size_t output_num_frames);
virtual ~AudioBuffer();
- int num_channels() const;
- void set_num_channels(int num_channels);
- size_t num_frames() const;
- size_t num_frames_per_band() const;
- size_t num_keyboard_frames() const;
- size_t num_bands() const;
+ AudioBuffer(const AudioBuffer&) = delete;
+ AudioBuffer& operator=(const AudioBuffer&) = delete;
+
+ // Specify that downmixing should be done by selecting a single channel.
+ void set_downmixing_to_specific_channel(size_t channel);
- // Returns a pointer array to the full-band channels.
+ // Specify that downmixing should be done by averaging all channels,.
+ void set_downmixing_by_averaging();
+
+ // Set the number of channels in the buffer. The specified number of channels
+ // cannot be larger than the specified buffer_num_channels. The number is also
+ // reset at each call to CopyFrom or InterleaveFrom.
+ void set_num_channels(size_t num_channels);
+
+ size_t num_channels() const { return num_channels_; }
+ size_t num_frames() const { return buffer_num_frames_; }
+ size_t num_frames_per_band() const { return num_split_frames_; }
+ size_t num_bands() const { return num_bands_; }
+
+ // Returns pointer arrays to the full-band channels.
// Usage:
// channels()[channel][sample].
// Where:
- // 0 <= channel < |num_proc_channels_|
- // 0 <= sample < |proc_num_frames_|
- int16_t* const* channels();
- const int16_t* const* channels_const() const;
- float* const* channels_f();
- const float* const* channels_const_f() const;
-
- // Returns a pointer array to the bands for a specific channel.
+ // 0 <= channel < |buffer_num_channels_|
+ // 0 <= sample < |buffer_num_frames_|
+ float* const* channels() { return data_->channels(); }
+ const float* const* channels_const() const { return data_->channels(); }
+
+ // Returns pointer arrays to the bands for a specific channel.
// Usage:
// split_bands(channel)[band][sample].
// Where:
- // 0 <= channel < |num_proc_channels_|
+ // 0 <= channel < |buffer_num_channels_|
// 0 <= band < |num_bands_|
// 0 <= sample < |num_split_frames_|
- int16_t* const* split_bands(int channel);
- const int16_t* const* split_bands_const(int channel) const;
- float* const* split_bands_f(int channel);
- const float* const* split_bands_const_f(int channel) const;
+ const float* const* split_bands_const(size_t channel) const {
+ return split_data_.get() ? split_data_->bands(channel)
+ : data_->bands(channel);
+ }
+ float* const* split_bands(size_t channel) {
+ return split_data_.get() ? split_data_->bands(channel)
+ : data_->bands(channel);
+ }
// Returns a pointer array to the channels for a specific band.
// Usage:
// split_channels(band)[channel][sample].
// Where:
// 0 <= band < |num_bands_|
- // 0 <= channel < |num_proc_channels_|
+ // 0 <= channel < |buffer_num_channels_|
// 0 <= sample < |num_split_frames_|
- int16_t* const* split_channels(Band band);
- const int16_t* const* split_channels_const(Band band) const;
- float* const* split_channels_f(Band band);
- const float* const* split_channels_const_f(Band band) const;
-
- // Returns a pointer to the ChannelBuffer that encapsulates the full-band
- // data.
- ChannelBuffer<int16_t>* data();
- const ChannelBuffer<int16_t>* data() const;
- ChannelBuffer<float>* data_f();
- const ChannelBuffer<float>* data_f() const;
-
- // Returns a pointer to the ChannelBuffer that encapsulates the split data.
- ChannelBuffer<int16_t>* split_data();
- const ChannelBuffer<int16_t>* split_data() const;
- ChannelBuffer<float>* split_data_f();
- const ChannelBuffer<float>* split_data_f() const;
-
- // Returns a pointer to the low-pass data downmixed to mono. If this data
- // isn't already available it re-calculates it.
- const int16_t* mixed_low_pass_data();
- const int16_t* low_pass_reference(int channel) const;
-
- const float* keyboard_data() const;
-
- void set_activity(AudioFrame::VADActivity activity);
- AudioFrame::VADActivity activity() const;
-
- // Use for int16 interleaved data.
- void DeinterleaveFrom(AudioFrame* audioFrame);
- // If |data_changed| is false, only the non-audio data members will be copied
- // to |frame|.
- void InterleaveTo(AudioFrame* frame, bool data_changed);
-
- // Use for float deinterleaved data.
- void CopyFrom(const float* const* data, const StreamConfig& stream_config);
- void CopyTo(const StreamConfig& stream_config, float* const* data);
- void CopyLowPassToReference();
-
- // Splits the signal into different bands.
+ const float* const* split_channels_const(Band band) const {
+ if (split_data_.get()) {
+ return split_data_->channels(band);
+ } else {
+ return band == kBand0To8kHz ? data_->channels() : nullptr;
+ }
+ }
+
+ // Copies data into the buffer.
+ void CopyFrom(const int16_t* const interleaved_data,
+ const StreamConfig& stream_config);
+ void CopyFrom(const float* const* stacked_data,
+ const StreamConfig& stream_config);
+
+ // Copies data from the buffer.
+ void CopyTo(const StreamConfig& stream_config,
+ int16_t* const interleaved_data);
+ void CopyTo(const StreamConfig& stream_config, float* const* stacked_data);
+ void CopyTo(AudioBuffer* buffer) const;
+
+ // Splits the buffer data into frequency bands.
void SplitIntoFrequencyBands();
- // Recombine the different bands into one signal.
+
+ // Recombines the frequency bands into a full-band signal.
void MergeFrequencyBands();
+ // Copies the split bands data into the integer two-dimensional array.
+ void ExportSplitChannelData(size_t channel,
+ int16_t* const* split_band_data) const;
+
+ // Copies the data in the integer two-dimensional array into the split_bands
+ // data.
+ void ImportSplitChannelData(size_t channel,
+ const int16_t* const* split_band_data);
+
+ static const size_t kMaxSplitFrameLength = 160;
+ static const size_t kMaxNumBands = 3;
+
+ // Deprecated methods, will be removed soon.
+ float* const* channels_f() { return channels(); }
+ const float* const* channels_const_f() const { return channels_const(); }
+ const float* const* split_bands_const_f(size_t channel) const {
+ return split_bands_const(channel);
+ }
+ float* const* split_bands_f(size_t channel) { return split_bands(channel); }
+ const float* const* split_channels_const_f(Band band) const {
+ return split_channels_const(band);
+ }
+
private:
- // Called from DeinterleaveFrom() and CopyFrom().
- void InitForNewData();
+ FRIEND_TEST_ALL_PREFIXES(AudioBufferTest,
+ SetNumChannelsSetsChannelBuffersNumChannels);
+ void RestoreNumChannels();
- // The audio is passed into DeinterleaveFrom() or CopyFrom() with input
- // format (samples per channel and number of channels).
const size_t input_num_frames_;
- const int num_input_channels_;
- // The audio is stored by DeinterleaveFrom() or CopyFrom() with processing
- // format.
- const size_t proc_num_frames_;
- const int num_proc_channels_;
- // The audio is returned by InterleaveTo() and CopyTo() with output samples
- // per channels and the current number of channels. This last one can be
- // changed at any time using set_num_channels().
+ const size_t input_num_channels_;
+ const size_t buffer_num_frames_;
+ const size_t buffer_num_channels_;
const size_t output_num_frames_;
- int num_channels_;
+ const size_t output_num_channels_;
+ size_t num_channels_;
size_t num_bands_;
size_t num_split_frames_;
- bool mixed_low_pass_valid_;
- bool reference_copied_;
- AudioFrame::VADActivity activity_;
-
- const float* keyboard_data_;
- rtc::scoped_ptr<IFChannelBuffer> data_;
- rtc::scoped_ptr<IFChannelBuffer> split_data_;
- rtc::scoped_ptr<SplittingFilter> splitting_filter_;
- rtc::scoped_ptr<ChannelBuffer<int16_t> > mixed_low_pass_channels_;
- rtc::scoped_ptr<ChannelBuffer<int16_t> > low_pass_reference_channels_;
- rtc::scoped_ptr<IFChannelBuffer> input_buffer_;
- rtc::scoped_ptr<IFChannelBuffer> output_buffer_;
- rtc::scoped_ptr<ChannelBuffer<float> > process_buffer_;
- ScopedVector<PushSincResampler> input_resamplers_;
- ScopedVector<PushSincResampler> output_resamplers_;
+
+ std::unique_ptr<ChannelBuffer<float>> data_;
+ std::unique_ptr<ChannelBuffer<float>> split_data_;
+ std::unique_ptr<SplittingFilter> splitting_filter_;
+ std::vector<std::unique_ptr<PushSincResampler>> input_resamplers_;
+ std::vector<std::unique_ptr<PushSincResampler>> output_resamplers_;
+ bool downmix_by_averaging_ = true;
+ size_t channel_for_downmixing_ = 0;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
+#endif // MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/audio_processing_builder_impl.cc b/webrtc/modules/audio_processing/audio_processing_builder_impl.cc
new file mode 100644
index 0000000..f55c915
--- /dev/null
+++ b/webrtc/modules/audio_processing/audio_processing_builder_impl.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/include/audio_processing.h"
+
+#include <memory>
+
+#include "modules/audio_processing/audio_processing_impl.h"
+#include "rtc_base/ref_counted_object.h"
+
+namespace webrtc {
+
+AudioProcessingBuilder::AudioProcessingBuilder() = default;
+AudioProcessingBuilder::~AudioProcessingBuilder() = default;
+
+AudioProcessing* AudioProcessingBuilder::Create() {
+ webrtc::Config config;
+ return Create(config);
+}
+
+AudioProcessing* AudioProcessingBuilder::Create(const webrtc::Config& config) {
+#ifdef WEBRTC_EXCLUDE_AUDIO_PROCESSING_MODULE
+
+ // Implementation returning a null pointer for using when the APM is excluded
+ // from the build..
+ return nullptr;
+
+#else
+
+ // Standard implementation.
+ return new rtc::RefCountedObject<AudioProcessingImpl>(
+ config, std::move(capture_post_processing_),
+ std::move(render_pre_processing_), std::move(echo_control_factory_),
+ std::move(echo_detector_), std::move(capture_analyzer_));
+#endif
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc
index c657415..67208df 100644
--- a/webrtc/modules/audio_processing/audio_processing_impl.cc
+++ b/webrtc/modules/audio_processing/audio_processing_impl.cc
@@ -8,48 +8,36 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/audio_processing_impl.h"
+#include "modules/audio_processing/audio_processing_impl.h"
-#include <assert.h>
#include <algorithm>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/platform_file.h"
-#include "webrtc/common_audio/audio_converter.h"
-#include "webrtc/common_audio/channel_buffer.h"
-#include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-extern "C" {
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-}
-#include "webrtc/modules/audio_processing/agc/agc_manager_direct.h"
-#include "webrtc/modules/audio_processing/audio_buffer.h"
-#include "webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h"
-#include "webrtc/modules/audio_processing/common.h"
-#include "webrtc/modules/audio_processing/echo_cancellation_impl.h"
-#include "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
-#include "webrtc/modules/audio_processing/gain_control_impl.h"
-#include "webrtc/modules/audio_processing/high_pass_filter_impl.h"
-#include "webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h"
-#include "webrtc/modules/audio_processing/level_estimator_impl.h"
-#include "webrtc/modules/audio_processing/noise_suppression_impl.h"
-#include "webrtc/modules/audio_processing/processing_component.h"
-#include "webrtc/modules/audio_processing/transient/transient_suppressor.h"
-#include "webrtc/modules/audio_processing/voice_detection_impl.h"
-#include "webrtc/modules/interface/module_common_types.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/include/file_wrapper.h"
-#include "webrtc/system_wrappers/include/logging.h"
-#include "webrtc/system_wrappers/include/metrics.h"
-
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
-// Files generated at build-time by the protobuf compiler.
-#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
-#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
-#else
-#include "webrtc/audio_processing/debug.pb.h"
-#endif
-#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/audio_frame.h"
+#include "common_audio/audio_converter.h"
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/aec_dump/aec_dump_factory.h"
+#include "modules/audio_processing/agc2/gain_applier.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/common.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "modules/audio_processing/optionally_built_submodule_creators.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/time_utils.h"
+#include "rtc_base/trace_event.h"
+#include "system_wrappers/include/field_trial.h"
+#include "system_wrappers/include/metrics.h"
#define RETURN_ON_ERR(expr) \
do { \
@@ -60,6 +48,9 @@ extern "C" {
} while (0)
namespace webrtc {
+
+constexpr int kRuntimeSettingQueueSize = 100;
+
namespace {
static bool LayoutHasKeyboard(AudioProcessing::ChannelLayout layout) {
@@ -72,316 +63,384 @@ static bool LayoutHasKeyboard(AudioProcessing::ChannelLayout layout) {
return true;
}
- assert(false);
+ RTC_NOTREACHED();
return false;
}
+bool SampleRateSupportsMultiBand(int sample_rate_hz) {
+ return sample_rate_hz == AudioProcessing::kSampleRate32kHz ||
+ sample_rate_hz == AudioProcessing::kSampleRate48kHz;
+}
+
+// Checks whether the high-pass filter should be done in the full-band.
+bool EnforceSplitBandHpf() {
+ return field_trial::IsEnabled("WebRTC-FullBandHpfKillSwitch");
+}
+
+// Checks whether AEC3 should be allowed to decide what the default
+// configuration should be based on the render and capture channel configuration
+// at hand.
+bool UseSetupSpecificDefaultAec3Congfig() {
+ return !field_trial::IsEnabled(
+ "WebRTC-Aec3SetupSpecificDefaultConfigDefaultsKillSwitch");
+}
+
+// Identify the native processing rate that best handles a sample rate.
+int SuitableProcessRate(int minimum_rate,
+ int max_splitting_rate,
+ bool band_splitting_required) {
+ const int uppermost_native_rate =
+ band_splitting_required ? max_splitting_rate : 48000;
+ for (auto rate : {16000, 32000, 48000}) {
+ if (rate >= uppermost_native_rate) {
+ return uppermost_native_rate;
+ }
+ if (rate >= minimum_rate) {
+ return rate;
+ }
+ }
+ RTC_NOTREACHED();
+ return uppermost_native_rate;
+}
+
+GainControl::Mode Agc1ConfigModeToInterfaceMode(
+ AudioProcessing::Config::GainController1::Mode mode) {
+ using Agc1Config = AudioProcessing::Config::GainController1;
+ switch (mode) {
+ case Agc1Config::kAdaptiveAnalog:
+ return GainControl::kAdaptiveAnalog;
+ case Agc1Config::kAdaptiveDigital:
+ return GainControl::kAdaptiveDigital;
+ case Agc1Config::kFixedDigital:
+ return GainControl::kFixedDigital;
+ }
+}
+
+// Maximum lengths that frame of samples being passed from the render side to
+// the capture side can have (does not apply to AEC3).
+static const size_t kMaxAllowedValuesOfSamplesPerBand = 160;
+static const size_t kMaxAllowedValuesOfSamplesPerFrame = 480;
+
+// Maximum number of frames to buffer in the render queue.
+// TODO(peah): Decrease this once we properly handle hugely unbalanced
+// reverse and forward call numbers.
+static const size_t kMaxNumFramesToBuffer = 100;
} // namespace
// Throughout webrtc, it's assumed that success is represented by zero.
static_assert(AudioProcessing::kNoError == 0, "kNoError must be zero");
-// This class has two main functionalities:
-//
-// 1) It is returned instead of the real GainControl after the new AGC has been
-// enabled in order to prevent an outside user from overriding compression
-// settings. It doesn't do anything in its implementation, except for
-// delegating the const methods and Enable calls to the real GainControl, so
-// AGC can still be disabled.
-//
-// 2) It is injected into AgcManagerDirect and implements volume callbacks for
-// getting and setting the volume level. It just caches this value to be used
-// in VoiceEngine later.
-class GainControlForNewAgc : public GainControl, public VolumeCallbacks {
- public:
- explicit GainControlForNewAgc(GainControlImpl* gain_control)
- : real_gain_control_(gain_control), volume_(0) {}
-
- // GainControl implementation.
- int Enable(bool enable) override {
- return real_gain_control_->Enable(enable);
- }
- bool is_enabled() const override { return real_gain_control_->is_enabled(); }
- int set_stream_analog_level(int level) override {
- volume_ = level;
- return AudioProcessing::kNoError;
- }
- int stream_analog_level() override { return volume_; }
- int set_mode(Mode mode) override { return AudioProcessing::kNoError; }
- Mode mode() const override { return GainControl::kAdaptiveAnalog; }
- int set_target_level_dbfs(int level) override {
- return AudioProcessing::kNoError;
- }
- int target_level_dbfs() const override {
- return real_gain_control_->target_level_dbfs();
- }
- int set_compression_gain_db(int gain) override {
- return AudioProcessing::kNoError;
- }
- int compression_gain_db() const override {
- return real_gain_control_->compression_gain_db();
- }
- int enable_limiter(bool enable) override { return AudioProcessing::kNoError; }
- bool is_limiter_enabled() const override {
- return real_gain_control_->is_limiter_enabled();
- }
- int set_analog_level_limits(int minimum, int maximum) override {
- return AudioProcessing::kNoError;
- }
- int analog_level_minimum() const override {
- return real_gain_control_->analog_level_minimum();
- }
- int analog_level_maximum() const override {
- return real_gain_control_->analog_level_maximum();
- }
- bool stream_is_saturated() const override {
- return real_gain_control_->stream_is_saturated();
- }
-
- // VolumeCallbacks implementation.
- void SetMicVolume(int volume) override { volume_ = volume; }
- int GetMicVolume() override { return volume_; }
-
- private:
- GainControl* real_gain_control_;
- int volume_;
-};
-
-const int AudioProcessing::kNativeSampleRatesHz[] = {
- AudioProcessing::kSampleRate8kHz,
- AudioProcessing::kSampleRate16kHz,
- AudioProcessing::kSampleRate32kHz,
- AudioProcessing::kSampleRate48kHz};
-const size_t AudioProcessing::kNumNativeSampleRates =
- arraysize(AudioProcessing::kNativeSampleRatesHz);
-const int AudioProcessing::kMaxNativeSampleRateHz = AudioProcessing::
- kNativeSampleRatesHz[AudioProcessing::kNumNativeSampleRates - 1];
-const int AudioProcessing::kMaxAECMSampleRateHz = kSampleRate16kHz;
-
-AudioProcessing* AudioProcessing::Create() {
- Config config;
- return Create(config, nullptr);
-}
-
-AudioProcessing* AudioProcessing::Create(const Config& config) {
- return Create(config, nullptr);
-}
-
-AudioProcessing* AudioProcessing::Create(const Config& config,
- Beamformer<float>* beamformer) {
- AudioProcessingImpl* apm = new AudioProcessingImpl(config, beamformer);
- if (apm->Initialize() != kNoError) {
- delete apm;
- apm = NULL;
- }
-
- return apm;
-}
-
-AudioProcessingImpl::AudioProcessingImpl(const Config& config)
- : AudioProcessingImpl(config, nullptr) {}
-
-AudioProcessingImpl::AudioProcessingImpl(const Config& config,
- Beamformer<float>* beamformer)
- : echo_cancellation_(NULL),
- echo_control_mobile_(NULL),
- gain_control_(NULL),
- high_pass_filter_(NULL),
- level_estimator_(NULL),
- noise_suppression_(NULL),
- voice_detection_(NULL),
- crit_(CriticalSectionWrapper::CreateCriticalSection()),
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- debug_file_(FileWrapper::Create()),
- event_msg_(new audioproc::Event()),
-#endif
- api_format_({{{kSampleRate16kHz, 1, false},
- {kSampleRate16kHz, 1, false},
- {kSampleRate16kHz, 1, false},
- {kSampleRate16kHz, 1, false}}}),
- fwd_proc_format_(kSampleRate16kHz),
- rev_proc_format_(kSampleRate16kHz, 1),
- split_rate_(kSampleRate16kHz),
- stream_delay_ms_(0),
- delay_offset_ms_(0),
- was_stream_delay_set_(false),
- last_stream_delay_ms_(0),
- last_aec_system_delay_ms_(0),
- stream_delay_jumps_(-1),
- aec_system_delay_jumps_(-1),
- output_will_be_muted_(false),
- key_pressed_(false),
-#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
- use_new_agc_(false),
-#else
- use_new_agc_(config.Get<ExperimentalAgc>().enabled),
-#endif
- agc_startup_min_volume_(config.Get<ExperimentalAgc>().startup_min_volume),
-#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
- transient_suppressor_enabled_(false),
-#else
- transient_suppressor_enabled_(config.Get<ExperimentalNs>().enabled),
-#endif
- beamformer_enabled_(config.Get<Beamforming>().enabled),
- beamformer_(beamformer),
- array_geometry_(config.Get<Beamforming>().array_geometry),
- target_direction_(config.Get<Beamforming>().target_direction),
- intelligibility_enabled_(config.Get<Intelligibility>().enabled) {
- echo_cancellation_ = new EchoCancellationImpl(this, crit_);
- component_list_.push_back(echo_cancellation_);
+AudioProcessingImpl::SubmoduleStates::SubmoduleStates(
+ bool capture_post_processor_enabled,
+ bool render_pre_processor_enabled,
+ bool capture_analyzer_enabled)
+ : capture_post_processor_enabled_(capture_post_processor_enabled),
+ render_pre_processor_enabled_(render_pre_processor_enabled),
+ capture_analyzer_enabled_(capture_analyzer_enabled) {}
+
+bool AudioProcessingImpl::SubmoduleStates::Update(
+ bool high_pass_filter_enabled,
+ bool mobile_echo_controller_enabled,
+ bool residual_echo_detector_enabled,
+ bool noise_suppressor_enabled,
+ bool adaptive_gain_controller_enabled,
+ bool gain_controller2_enabled,
+ bool pre_amplifier_enabled,
+ bool echo_controller_enabled,
+ bool voice_detector_enabled,
+ bool transient_suppressor_enabled) {
+ bool changed = false;
+ changed |= (high_pass_filter_enabled != high_pass_filter_enabled_);
+ changed |=
+ (mobile_echo_controller_enabled != mobile_echo_controller_enabled_);
+ changed |=
+ (residual_echo_detector_enabled != residual_echo_detector_enabled_);
+ changed |= (noise_suppressor_enabled != noise_suppressor_enabled_);
+ changed |=
+ (adaptive_gain_controller_enabled != adaptive_gain_controller_enabled_);
+ changed |= (gain_controller2_enabled != gain_controller2_enabled_);
+ changed |= (pre_amplifier_enabled_ != pre_amplifier_enabled);
+ changed |= (echo_controller_enabled != echo_controller_enabled_);
+ changed |= (voice_detector_enabled != voice_detector_enabled_);
+ changed |= (transient_suppressor_enabled != transient_suppressor_enabled_);
+ if (changed) {
+ high_pass_filter_enabled_ = high_pass_filter_enabled;
+ mobile_echo_controller_enabled_ = mobile_echo_controller_enabled;
+ residual_echo_detector_enabled_ = residual_echo_detector_enabled;
+ noise_suppressor_enabled_ = noise_suppressor_enabled;
+ adaptive_gain_controller_enabled_ = adaptive_gain_controller_enabled;
+ gain_controller2_enabled_ = gain_controller2_enabled;
+ pre_amplifier_enabled_ = pre_amplifier_enabled;
+ echo_controller_enabled_ = echo_controller_enabled;
+ voice_detector_enabled_ = voice_detector_enabled;
+ transient_suppressor_enabled_ = transient_suppressor_enabled;
+ }
+
+ changed |= first_update_;
+ first_update_ = false;
+ return changed;
+}
- echo_control_mobile_ = new EchoControlMobileImpl(this, crit_);
- component_list_.push_back(echo_control_mobile_);
+bool AudioProcessingImpl::SubmoduleStates::CaptureMultiBandSubModulesActive()
+ const {
+ return CaptureMultiBandProcessingPresent() || voice_detector_enabled_;
+}
- gain_control_ = new GainControlImpl(this, crit_);
- component_list_.push_back(gain_control_);
+bool AudioProcessingImpl::SubmoduleStates::CaptureMultiBandProcessingPresent()
+ const {
+ // If echo controller is present, assume it performs active processing.
+ return CaptureMultiBandProcessingActive(/*ec_processing_active=*/true);
+}
- high_pass_filter_ = new HighPassFilterImpl(this, crit_);
- component_list_.push_back(high_pass_filter_);
+bool AudioProcessingImpl::SubmoduleStates::CaptureMultiBandProcessingActive(
+ bool ec_processing_active) const {
+ return high_pass_filter_enabled_ || mobile_echo_controller_enabled_ ||
+ noise_suppressor_enabled_ || adaptive_gain_controller_enabled_ ||
+ (echo_controller_enabled_ && ec_processing_active);
+}
- level_estimator_ = new LevelEstimatorImpl(this, crit_);
- component_list_.push_back(level_estimator_);
+bool AudioProcessingImpl::SubmoduleStates::CaptureFullBandProcessingActive()
+ const {
+ return gain_controller2_enabled_ || capture_post_processor_enabled_ ||
+ pre_amplifier_enabled_;
+}
- noise_suppression_ = new NoiseSuppressionImpl(this, crit_);
- component_list_.push_back(noise_suppression_);
+bool AudioProcessingImpl::SubmoduleStates::CaptureAnalyzerActive() const {
+ return capture_analyzer_enabled_;
+}
- voice_detection_ = new VoiceDetectionImpl(this, crit_);
- component_list_.push_back(voice_detection_);
+bool AudioProcessingImpl::SubmoduleStates::RenderMultiBandSubModulesActive()
+ const {
+ return RenderMultiBandProcessingActive() || mobile_echo_controller_enabled_ ||
+ adaptive_gain_controller_enabled_ || echo_controller_enabled_;
+}
- gain_control_for_new_agc_.reset(new GainControlForNewAgc(gain_control_));
+bool AudioProcessingImpl::SubmoduleStates::RenderFullBandProcessingActive()
+ const {
+ return render_pre_processor_enabled_;
+}
- SetExtraOptions(config);
+bool AudioProcessingImpl::SubmoduleStates::RenderMultiBandProcessingActive()
+ const {
+ return false;
}
-AudioProcessingImpl::~AudioProcessingImpl() {
- {
- CriticalSectionScoped crit_scoped(crit_);
- // Depends on gain_control_ and gain_control_for_new_agc_.
- agc_manager_.reset();
- // Depends on gain_control_.
- gain_control_for_new_agc_.reset();
- while (!component_list_.empty()) {
- ProcessingComponent* component = component_list_.front();
- component->Destroy();
- delete component;
- component_list_.pop_front();
- }
+bool AudioProcessingImpl::SubmoduleStates::HighPassFilteringRequired() const {
+ return high_pass_filter_enabled_ || mobile_echo_controller_enabled_ ||
+ noise_suppressor_enabled_;
+}
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- debug_file_->CloseFile();
- }
+AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config)
+ : AudioProcessingImpl(config,
+ /*capture_post_processor=*/nullptr,
+ /*render_pre_processor=*/nullptr,
+ /*echo_control_factory=*/nullptr,
+ /*echo_detector=*/nullptr,
+ /*capture_analyzer=*/nullptr) {}
+
+int AudioProcessingImpl::instance_count_ = 0;
+
+AudioProcessingImpl::AudioProcessingImpl(
+ const webrtc::Config& config,
+ std::unique_ptr<CustomProcessing> capture_post_processor,
+ std::unique_ptr<CustomProcessing> render_pre_processor,
+ std::unique_ptr<EchoControlFactory> echo_control_factory,
+ rtc::scoped_refptr<EchoDetector> echo_detector,
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer)
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ use_setup_specific_default_aec3_config_(
+ UseSetupSpecificDefaultAec3Congfig()),
+ capture_runtime_settings_(kRuntimeSettingQueueSize),
+ render_runtime_settings_(kRuntimeSettingQueueSize),
+ capture_runtime_settings_enqueuer_(&capture_runtime_settings_),
+ render_runtime_settings_enqueuer_(&render_runtime_settings_),
+ echo_control_factory_(std::move(echo_control_factory)),
+ submodule_states_(!!capture_post_processor,
+ !!render_pre_processor,
+ !!capture_analyzer),
+ submodules_(std::move(capture_post_processor),
+ std::move(render_pre_processor),
+ std::move(echo_detector),
+ std::move(capture_analyzer)),
+ constants_(!field_trial::IsEnabled(
+ "WebRTC-ApmExperimentalMultiChannelRenderKillSwitch"),
+ !field_trial::IsEnabled(
+ "WebRTC-ApmExperimentalMultiChannelCaptureKillSwitch"),
+ EnforceSplitBandHpf()),
+ capture_nonlocked_() {
+ RTC_LOG(LS_INFO) << "Injected APM submodules:"
+ "\nEcho control factory: "
+ << !!echo_control_factory_
+ << "\nEcho detector: " << !!submodules_.echo_detector
+ << "\nCapture analyzer: " << !!submodules_.capture_analyzer
+ << "\nCapture post processor: "
+ << !!submodules_.capture_post_processor
+ << "\nRender pre processor: "
+ << !!submodules_.render_pre_processor;
+
+ // Mark Echo Controller enabled if a factory is injected.
+ capture_nonlocked_.echo_controller_enabled =
+ static_cast<bool>(echo_control_factory_);
+
+ // If no echo detector is injected, use the ResidualEchoDetector.
+ if (!submodules_.echo_detector) {
+ submodules_.echo_detector =
+ new rtc::RefCountedObject<ResidualEchoDetector>();
+ }
+
+#if !(defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS))
+ // TODO(webrtc:5298): Remove once the use of ExperimentalNs has been
+ // deprecated.
+ config_.transient_suppression.enabled = config.Get<ExperimentalNs>().enabled;
+
+ // TODO(webrtc:5298): Remove once the use of ExperimentalAgc has been
+ // deprecated.
+ config_.gain_controller1.analog_gain_controller.enabled =
+ config.Get<ExperimentalAgc>().enabled;
+ config_.gain_controller1.analog_gain_controller.startup_min_volume =
+ config.Get<ExperimentalAgc>().startup_min_volume;
+ config_.gain_controller1.analog_gain_controller.clipped_level_min =
+ config.Get<ExperimentalAgc>().clipped_level_min;
+ config_.gain_controller1.analog_gain_controller.enable_agc2_level_estimator =
+ config.Get<ExperimentalAgc>().enabled_agc2_level_estimator;
+ config_.gain_controller1.analog_gain_controller.enable_digital_adaptive =
+ !config.Get<ExperimentalAgc>().digital_adaptive_disabled;
#endif
- }
- delete crit_;
- crit_ = NULL;
+
+ Initialize();
}
+AudioProcessingImpl::~AudioProcessingImpl() = default;
+
int AudioProcessingImpl::Initialize() {
- CriticalSectionScoped crit_scoped(crit_);
- return InitializeLocked();
+ // Run in a single-threaded manner during initialization.
+ MutexLock lock_render(&mutex_render_);
+ MutexLock lock_capture(&mutex_capture_);
+ InitializeLocked();
+ return kNoError;
}
-int AudioProcessingImpl::Initialize(int input_sample_rate_hz,
- int output_sample_rate_hz,
- int reverse_sample_rate_hz,
- ChannelLayout input_layout,
- ChannelLayout output_layout,
- ChannelLayout reverse_layout) {
+int AudioProcessingImpl::Initialize(int capture_input_sample_rate_hz,
+ int capture_output_sample_rate_hz,
+ int render_input_sample_rate_hz,
+ ChannelLayout capture_input_layout,
+ ChannelLayout capture_output_layout,
+ ChannelLayout render_input_layout) {
const ProcessingConfig processing_config = {
- {{input_sample_rate_hz,
- ChannelsFromLayout(input_layout),
- LayoutHasKeyboard(input_layout)},
- {output_sample_rate_hz,
- ChannelsFromLayout(output_layout),
- LayoutHasKeyboard(output_layout)},
- {reverse_sample_rate_hz,
- ChannelsFromLayout(reverse_layout),
- LayoutHasKeyboard(reverse_layout)},
- {reverse_sample_rate_hz,
- ChannelsFromLayout(reverse_layout),
- LayoutHasKeyboard(reverse_layout)}}};
+ {{capture_input_sample_rate_hz, ChannelsFromLayout(capture_input_layout),
+ LayoutHasKeyboard(capture_input_layout)},
+ {capture_output_sample_rate_hz,
+ ChannelsFromLayout(capture_output_layout),
+ LayoutHasKeyboard(capture_output_layout)},
+ {render_input_sample_rate_hz, ChannelsFromLayout(render_input_layout),
+ LayoutHasKeyboard(render_input_layout)},
+ {render_input_sample_rate_hz, ChannelsFromLayout(render_input_layout),
+ LayoutHasKeyboard(render_input_layout)}}};
return Initialize(processing_config);
}
int AudioProcessingImpl::Initialize(const ProcessingConfig& processing_config) {
- CriticalSectionScoped crit_scoped(crit_);
+ // Run in a single-threaded manner during initialization.
+ MutexLock lock_render(&mutex_render_);
+ MutexLock lock_capture(&mutex_capture_);
return InitializeLocked(processing_config);
}
-int AudioProcessingImpl::InitializeLocked() {
- const int fwd_audio_buffer_channels =
- beamformer_enabled_ ? api_format_.input_stream().num_channels()
- : api_format_.output_stream().num_channels();
- const int rev_audio_buffer_out_num_frames =
- api_format_.reverse_output_stream().num_frames() == 0
- ? rev_proc_format_.num_frames()
- : api_format_.reverse_output_stream().num_frames();
- if (api_format_.reverse_input_stream().num_channels() > 0) {
- render_audio_.reset(new AudioBuffer(
- api_format_.reverse_input_stream().num_frames(),
- api_format_.reverse_input_stream().num_channels(),
- rev_proc_format_.num_frames(), rev_proc_format_.num_channels(),
- rev_audio_buffer_out_num_frames));
- if (rev_conversion_needed()) {
- render_converter_ = AudioConverter::Create(
- api_format_.reverse_input_stream().num_channels(),
- api_format_.reverse_input_stream().num_frames(),
- api_format_.reverse_output_stream().num_channels(),
- api_format_.reverse_output_stream().num_frames());
+int AudioProcessingImpl::MaybeInitializeRender(
+ const ProcessingConfig& processing_config) {
+ // Called from both threads. Thread check is therefore not possible.
+ if (processing_config == formats_.api_format) {
+ return kNoError;
+ }
+
+ MutexLock lock_capture(&mutex_capture_);
+ return InitializeLocked(processing_config);
+}
+
+void AudioProcessingImpl::InitializeLocked() {
+ UpdateActiveSubmoduleStates();
+
+ const int render_audiobuffer_sample_rate_hz =
+ formats_.api_format.reverse_output_stream().num_frames() == 0
+ ? formats_.render_processing_format.sample_rate_hz()
+ : formats_.api_format.reverse_output_stream().sample_rate_hz();
+ if (formats_.api_format.reverse_input_stream().num_channels() > 0) {
+ render_.render_audio.reset(new AudioBuffer(
+ formats_.api_format.reverse_input_stream().sample_rate_hz(),
+ formats_.api_format.reverse_input_stream().num_channels(),
+ formats_.render_processing_format.sample_rate_hz(),
+ formats_.render_processing_format.num_channels(),
+ render_audiobuffer_sample_rate_hz,
+ formats_.render_processing_format.num_channels()));
+ if (formats_.api_format.reverse_input_stream() !=
+ formats_.api_format.reverse_output_stream()) {
+ render_.render_converter = AudioConverter::Create(
+ formats_.api_format.reverse_input_stream().num_channels(),
+ formats_.api_format.reverse_input_stream().num_frames(),
+ formats_.api_format.reverse_output_stream().num_channels(),
+ formats_.api_format.reverse_output_stream().num_frames());
} else {
- render_converter_.reset(nullptr);
+ render_.render_converter.reset(nullptr);
}
} else {
- render_audio_.reset(nullptr);
- render_converter_.reset(nullptr);
- }
- capture_audio_.reset(new AudioBuffer(
- api_format_.input_stream().num_frames(),
- api_format_.input_stream().num_channels(), fwd_proc_format_.num_frames(),
- fwd_audio_buffer_channels, api_format_.output_stream().num_frames()));
-
- // Initialize all components.
- for (auto item : component_list_) {
- int err = item->Initialize();
- if (err != kNoError) {
- return err;
- }
+ render_.render_audio.reset(nullptr);
+ render_.render_converter.reset(nullptr);
+ }
+
+ capture_.capture_audio.reset(new AudioBuffer(
+ formats_.api_format.input_stream().sample_rate_hz(),
+ formats_.api_format.input_stream().num_channels(),
+ capture_nonlocked_.capture_processing_format.sample_rate_hz(),
+ formats_.api_format.output_stream().num_channels(),
+ formats_.api_format.output_stream().sample_rate_hz(),
+ formats_.api_format.output_stream().num_channels()));
+
+ if (capture_nonlocked_.capture_processing_format.sample_rate_hz() <
+ formats_.api_format.output_stream().sample_rate_hz() &&
+ formats_.api_format.output_stream().sample_rate_hz() == 48000) {
+ capture_.capture_fullband_audio.reset(
+ new AudioBuffer(formats_.api_format.input_stream().sample_rate_hz(),
+ formats_.api_format.input_stream().num_channels(),
+ formats_.api_format.output_stream().sample_rate_hz(),
+ formats_.api_format.output_stream().num_channels(),
+ formats_.api_format.output_stream().sample_rate_hz(),
+ formats_.api_format.output_stream().num_channels()));
+ } else {
+ capture_.capture_fullband_audio.reset();
}
- InitializeExperimentalAgc();
-
- InitializeTransient();
-
- InitializeBeamformer();
+ AllocateRenderQueue();
- InitializeIntelligibility();
+ InitializeGainController1();
+ InitializeTransientSuppressor();
+ InitializeHighPassFilter(true);
+ InitializeVoiceDetector();
+ InitializeResidualEchoDetector();
+ InitializeEchoController();
+ InitializeGainController2();
+ InitializeNoiseSuppressor();
+ InitializeAnalyzer();
+ InitializePostProcessor();
+ InitializePreProcessor();
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- int err = WriteInitMessage();
- if (err != kNoError) {
- return err;
- }
+ if (aec_dump_) {
+ aec_dump_->WriteInitMessage(formats_.api_format, rtc::TimeUTCMillis());
}
-#endif
-
- return kNoError;
}
int AudioProcessingImpl::InitializeLocked(const ProcessingConfig& config) {
+ UpdateActiveSubmoduleStates();
+
for (const auto& stream : config.streams) {
- if (stream.num_channels() < 0) {
- return kBadNumberChannelsError;
- }
if (stream.num_channels() > 0 && stream.sample_rate_hz() <= 0) {
return kBadSampleRateError;
}
}
- const int num_in_channels = config.input_stream().num_channels();
- const int num_out_channels = config.output_stream().num_channels();
+ const size_t num_in_channels = config.input_stream().num_channels();
+ const size_t num_out_channels = config.output_stream().num_channels();
// Need at least one input channel.
// Need either one output channel or as many outputs as there are inputs.
@@ -390,480 +449,1023 @@ int AudioProcessingImpl::InitializeLocked(const ProcessingConfig& config) {
return kBadNumberChannelsError;
}
- if (beamformer_enabled_ &&
- (static_cast<size_t>(num_in_channels) != array_geometry_.size() ||
- num_out_channels > 1)) {
- return kBadNumberChannelsError;
- }
-
- api_format_ = config;
+ formats_.api_format = config;
- // We process at the closest native rate >= min(input rate, output rate)...
- const int min_proc_rate =
- std::min(api_format_.input_stream().sample_rate_hz(),
- api_format_.output_stream().sample_rate_hz());
- int fwd_proc_rate;
- for (size_t i = 0; i < kNumNativeSampleRates; ++i) {
- fwd_proc_rate = kNativeSampleRatesHz[i];
- if (fwd_proc_rate >= min_proc_rate) {
- break;
- }
- }
- // ...with one exception.
- if (echo_control_mobile_->is_enabled() &&
- min_proc_rate > kMaxAECMSampleRateHz) {
- fwd_proc_rate = kMaxAECMSampleRateHz;
+ // Choose maximum rate to use for the split filtering.
+ RTC_DCHECK(config_.pipeline.maximum_internal_processing_rate == 48000 ||
+ config_.pipeline.maximum_internal_processing_rate == 32000);
+ int max_splitting_rate = 48000;
+ if (config_.pipeline.maximum_internal_processing_rate == 32000) {
+ max_splitting_rate = config_.pipeline.maximum_internal_processing_rate;
}
- fwd_proc_format_ = StreamConfig(fwd_proc_rate);
+ int capture_processing_rate = SuitableProcessRate(
+ std::min(formats_.api_format.input_stream().sample_rate_hz(),
+ formats_.api_format.output_stream().sample_rate_hz()),
+ max_splitting_rate,
+ submodule_states_.CaptureMultiBandSubModulesActive() ||
+ submodule_states_.RenderMultiBandSubModulesActive());
+ RTC_DCHECK_NE(8000, capture_processing_rate);
+
+ capture_nonlocked_.capture_processing_format =
+ StreamConfig(capture_processing_rate);
- // We normally process the reverse stream at 16 kHz. Unless...
- int rev_proc_rate = kSampleRate16kHz;
- if (fwd_proc_format_.sample_rate_hz() == kSampleRate8kHz) {
- // ...the forward stream is at 8 kHz.
- rev_proc_rate = kSampleRate8kHz;
+ int render_processing_rate;
+ if (!capture_nonlocked_.echo_controller_enabled) {
+ render_processing_rate = SuitableProcessRate(
+ std::min(formats_.api_format.reverse_input_stream().sample_rate_hz(),
+ formats_.api_format.reverse_output_stream().sample_rate_hz()),
+ max_splitting_rate,
+ submodule_states_.CaptureMultiBandSubModulesActive() ||
+ submodule_states_.RenderMultiBandSubModulesActive());
} else {
- if (api_format_.reverse_input_stream().sample_rate_hz() ==
- kSampleRate32kHz) {
- // ...or the input is at 32 kHz, in which case we use the splitting
- // filter rather than the resampler.
- rev_proc_rate = kSampleRate32kHz;
- }
+ render_processing_rate = capture_processing_rate;
}
- // Always downmix the reverse stream to mono for analysis. This has been
- // demonstrated to work well for AEC in most practical scenarios.
- rev_proc_format_ = StreamConfig(rev_proc_rate, 1);
+ // If the forward sample rate is 8 kHz, the render stream is also processed
+ // at this rate.
+ if (capture_nonlocked_.capture_processing_format.sample_rate_hz() ==
+ kSampleRate8kHz) {
+ render_processing_rate = kSampleRate8kHz;
+ } else {
+ render_processing_rate =
+ std::max(render_processing_rate, static_cast<int>(kSampleRate16kHz));
+ }
+
+ RTC_DCHECK_NE(8000, render_processing_rate);
+
+ if (submodule_states_.RenderMultiBandSubModulesActive()) {
+ // By default, downmix the render stream to mono for analysis. This has been
+ // demonstrated to work well for AEC in most practical scenarios.
+ const bool multi_channel_render = config_.pipeline.multi_channel_render &&
+ constants_.multi_channel_render_support;
+ int render_processing_num_channels =
+ multi_channel_render
+ ? formats_.api_format.reverse_input_stream().num_channels()
+ : 1;
+ formats_.render_processing_format =
+ StreamConfig(render_processing_rate, render_processing_num_channels);
+ } else {
+ formats_.render_processing_format = StreamConfig(
+ formats_.api_format.reverse_input_stream().sample_rate_hz(),
+ formats_.api_format.reverse_input_stream().num_channels());
+ }
- if (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
- fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz) {
- split_rate_ = kSampleRate16kHz;
+ if (capture_nonlocked_.capture_processing_format.sample_rate_hz() ==
+ kSampleRate32kHz ||
+ capture_nonlocked_.capture_processing_format.sample_rate_hz() ==
+ kSampleRate48kHz) {
+ capture_nonlocked_.split_rate = kSampleRate16kHz;
} else {
- split_rate_ = fwd_proc_format_.sample_rate_hz();
+ capture_nonlocked_.split_rate =
+ capture_nonlocked_.capture_processing_format.sample_rate_hz();
}
- return InitializeLocked();
+ InitializeLocked();
+ return kNoError;
}
-// Calls InitializeLocked() if any of the audio parameters have changed from
-// their current values.
-int AudioProcessingImpl::MaybeInitializeLocked(
- const ProcessingConfig& processing_config) {
- if (processing_config == api_format_) {
- return kNoError;
+void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) {
+ RTC_LOG(LS_INFO) << "AudioProcessing::ApplyConfig: " << config.ToString();
+
+ // Run in a single-threaded manner when applying the settings.
+ MutexLock lock_render(&mutex_render_);
+ MutexLock lock_capture(&mutex_capture_);
+
+ const bool pipeline_config_changed =
+ config_.pipeline.multi_channel_render !=
+ config.pipeline.multi_channel_render ||
+ config_.pipeline.multi_channel_capture !=
+ config.pipeline.multi_channel_capture ||
+ config_.pipeline.maximum_internal_processing_rate !=
+ config.pipeline.maximum_internal_processing_rate;
+
+ const bool aec_config_changed =
+ config_.echo_canceller.enabled != config.echo_canceller.enabled ||
+ config_.echo_canceller.mobile_mode != config.echo_canceller.mobile_mode;
+
+ const bool agc1_config_changed =
+ config_.gain_controller1.enabled != config.gain_controller1.enabled ||
+ config_.gain_controller1.mode != config.gain_controller1.mode ||
+ config_.gain_controller1.target_level_dbfs !=
+ config.gain_controller1.target_level_dbfs ||
+ config_.gain_controller1.compression_gain_db !=
+ config.gain_controller1.compression_gain_db ||
+ config_.gain_controller1.enable_limiter !=
+ config.gain_controller1.enable_limiter ||
+ config_.gain_controller1.analog_level_minimum !=
+ config.gain_controller1.analog_level_minimum ||
+ config_.gain_controller1.analog_level_maximum !=
+ config.gain_controller1.analog_level_maximum ||
+ config_.gain_controller1.analog_gain_controller.enabled !=
+ config.gain_controller1.analog_gain_controller.enabled ||
+ config_.gain_controller1.analog_gain_controller.startup_min_volume !=
+ config.gain_controller1.analog_gain_controller.startup_min_volume ||
+ config_.gain_controller1.analog_gain_controller.clipped_level_min !=
+ config.gain_controller1.analog_gain_controller.clipped_level_min ||
+ config_.gain_controller1.analog_gain_controller
+ .enable_agc2_level_estimator !=
+ config.gain_controller1.analog_gain_controller
+ .enable_agc2_level_estimator ||
+ config_.gain_controller1.analog_gain_controller.enable_digital_adaptive !=
+ config.gain_controller1.analog_gain_controller
+ .enable_digital_adaptive;
+
+ const bool agc2_config_changed =
+ config_.gain_controller2.enabled != config.gain_controller2.enabled;
+
+ const bool voice_detection_config_changed =
+ config_.voice_detection.enabled != config.voice_detection.enabled;
+
+ const bool ns_config_changed =
+ config_.noise_suppression.enabled != config.noise_suppression.enabled ||
+ config_.noise_suppression.level != config.noise_suppression.level;
+
+ const bool ts_config_changed = config_.transient_suppression.enabled !=
+ config.transient_suppression.enabled;
+
+ const bool pre_amplifier_config_changed =
+ config_.pre_amplifier.enabled != config.pre_amplifier.enabled ||
+ config_.pre_amplifier.fixed_gain_factor !=
+ config.pre_amplifier.fixed_gain_factor;
+
+ config_ = config;
+
+ if (aec_config_changed) {
+ InitializeEchoController();
+ }
+
+ if (ns_config_changed) {
+ InitializeNoiseSuppressor();
+ }
+
+ if (ts_config_changed) {
+ InitializeTransientSuppressor();
+ }
+
+ InitializeHighPassFilter(false);
+
+ if (agc1_config_changed) {
+ InitializeGainController1();
+ }
+
+ const bool config_ok = GainController2::Validate(config_.gain_controller2);
+ if (!config_ok) {
+ RTC_LOG(LS_ERROR) << "AudioProcessing module config error\n"
+ "Gain Controller 2: "
+ << GainController2::ToString(config_.gain_controller2)
+ << "\nReverting to default parameter set";
+ config_.gain_controller2 = AudioProcessing::Config::GainController2();
+ }
+
+ if (agc2_config_changed) {
+ InitializeGainController2();
+ }
+
+ if (pre_amplifier_config_changed) {
+ InitializePreAmplifier();
+ }
+
+ if (config_.level_estimation.enabled && !submodules_.output_level_estimator) {
+ submodules_.output_level_estimator = std::make_unique<LevelEstimator>();
}
- return InitializeLocked(processing_config);
-}
-void AudioProcessingImpl::SetExtraOptions(const Config& config) {
- CriticalSectionScoped crit_scoped(crit_);
- for (auto item : component_list_) {
- item->SetExtraOptions(config);
+ if (voice_detection_config_changed) {
+ InitializeVoiceDetector();
}
- if (transient_suppressor_enabled_ != config.Get<ExperimentalNs>().enabled) {
- transient_suppressor_enabled_ = config.Get<ExperimentalNs>().enabled;
- InitializeTransient();
+ // Reinitialization must happen after all submodule configuration to avoid
+ // additional reinitializations on the next capture / render processing call.
+ if (pipeline_config_changed) {
+ InitializeLocked(formats_.api_format);
}
}
+void AudioProcessingImpl::OverrideSubmoduleCreationForTesting(
+ const ApmSubmoduleCreationOverrides& overrides) {
+ MutexLock lock(&mutex_capture_);
+ submodule_creation_overrides_ = overrides;
+}
int AudioProcessingImpl::proc_sample_rate_hz() const {
- return fwd_proc_format_.sample_rate_hz();
+ // Used as callback from submodules, hence locking is not allowed.
+ return capture_nonlocked_.capture_processing_format.sample_rate_hz();
+}
+
+int AudioProcessingImpl::proc_fullband_sample_rate_hz() const {
+ return capture_.capture_fullband_audio
+ ? capture_.capture_fullband_audio->num_frames() * 100
+ : capture_nonlocked_.capture_processing_format.sample_rate_hz();
}
int AudioProcessingImpl::proc_split_sample_rate_hz() const {
- return split_rate_;
+ // Used as callback from submodules, hence locking is not allowed.
+ return capture_nonlocked_.split_rate;
}
-int AudioProcessingImpl::num_reverse_channels() const {
- return rev_proc_format_.num_channels();
+size_t AudioProcessingImpl::num_reverse_channels() const {
+ // Used as callback from submodules, hence locking is not allowed.
+ return formats_.render_processing_format.num_channels();
}
-int AudioProcessingImpl::num_input_channels() const {
- return api_format_.input_stream().num_channels();
+size_t AudioProcessingImpl::num_input_channels() const {
+ // Used as callback from submodules, hence locking is not allowed.
+ return formats_.api_format.input_stream().num_channels();
}
-int AudioProcessingImpl::num_output_channels() const {
- return api_format_.output_stream().num_channels();
+size_t AudioProcessingImpl::num_proc_channels() const {
+ // Used as callback from submodules, hence locking is not allowed.
+ const bool multi_channel_capture = config_.pipeline.multi_channel_capture &&
+ constants_.multi_channel_capture_support;
+ if (capture_nonlocked_.echo_controller_enabled && !multi_channel_capture) {
+ return 1;
+ }
+ return num_output_channels();
+}
+
+size_t AudioProcessingImpl::num_output_channels() const {
+ // Used as callback from submodules, hence locking is not allowed.
+ return formats_.api_format.output_stream().num_channels();
}
void AudioProcessingImpl::set_output_will_be_muted(bool muted) {
- CriticalSectionScoped lock(crit_);
- output_will_be_muted_ = muted;
- if (agc_manager_.get()) {
- agc_manager_->SetCaptureMuted(output_will_be_muted_);
+ MutexLock lock(&mutex_capture_);
+ capture_.output_will_be_muted = muted;
+ if (submodules_.agc_manager.get()) {
+ submodules_.agc_manager->SetCaptureMuted(capture_.output_will_be_muted);
}
}
+void AudioProcessingImpl::SetRuntimeSetting(RuntimeSetting setting) {
+ switch (setting.type()) {
+ case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
+ case RuntimeSetting::Type::kPlayoutAudioDeviceChange:
+ render_runtime_settings_enqueuer_.Enqueue(setting);
+ return;
+ case RuntimeSetting::Type::kCapturePreGain:
+ case RuntimeSetting::Type::kCaptureCompressionGain:
+ case RuntimeSetting::Type::kCaptureFixedPostGain:
+ case RuntimeSetting::Type::kCaptureOutputUsed:
+ capture_runtime_settings_enqueuer_.Enqueue(setting);
+ return;
+ case RuntimeSetting::Type::kPlayoutVolumeChange:
+ capture_runtime_settings_enqueuer_.Enqueue(setting);
+ render_runtime_settings_enqueuer_.Enqueue(setting);
+ return;
+ case RuntimeSetting::Type::kNotSpecified:
+ RTC_NOTREACHED();
+ return;
+ }
+ // The language allows the enum to have a non-enumerator
+ // value. Check that this doesn't happen.
+ RTC_NOTREACHED();
+}
-int AudioProcessingImpl::ProcessStream(const float* const* src,
- size_t samples_per_channel,
- int input_sample_rate_hz,
- ChannelLayout input_layout,
- int output_sample_rate_hz,
- ChannelLayout output_layout,
- float* const* dest) {
- CriticalSectionScoped crit_scoped(crit_);
- StreamConfig input_stream = api_format_.input_stream();
- input_stream.set_sample_rate_hz(input_sample_rate_hz);
- input_stream.set_num_channels(ChannelsFromLayout(input_layout));
- input_stream.set_has_keyboard(LayoutHasKeyboard(input_layout));
-
- StreamConfig output_stream = api_format_.output_stream();
- output_stream.set_sample_rate_hz(output_sample_rate_hz);
- output_stream.set_num_channels(ChannelsFromLayout(output_layout));
- output_stream.set_has_keyboard(LayoutHasKeyboard(output_layout));
-
- if (samples_per_channel != input_stream.num_frames()) {
- return kBadDataLengthError;
+AudioProcessingImpl::RuntimeSettingEnqueuer::RuntimeSettingEnqueuer(
+ SwapQueue<RuntimeSetting>* runtime_settings)
+ : runtime_settings_(*runtime_settings) {
+ RTC_DCHECK(runtime_settings);
+}
+
+AudioProcessingImpl::RuntimeSettingEnqueuer::~RuntimeSettingEnqueuer() =
+ default;
+
+void AudioProcessingImpl::RuntimeSettingEnqueuer::Enqueue(
+ RuntimeSetting setting) {
+ size_t remaining_attempts = 10;
+ while (!runtime_settings_.Insert(&setting) && remaining_attempts-- > 0) {
+ RuntimeSetting setting_to_discard;
+ if (runtime_settings_.Remove(&setting_to_discard))
+ RTC_LOG(LS_ERROR)
+ << "The runtime settings queue is full. Oldest setting discarded.";
}
- return ProcessStream(src, input_stream, output_stream, dest);
+ if (remaining_attempts == 0)
+ RTC_LOG(LS_ERROR) << "Cannot enqueue a new runtime setting.";
+}
+
+int AudioProcessingImpl::MaybeInitializeCapture(
+ const StreamConfig& input_config,
+ const StreamConfig& output_config) {
+ ProcessingConfig processing_config;
+ bool reinitialization_required = false;
+ {
+ // Acquire the capture lock in order to access api_format. The lock is
+ // released immediately, as we may need to acquire the render lock as part
+ // of the conditional reinitialization.
+ MutexLock lock_capture(&mutex_capture_);
+ processing_config = formats_.api_format;
+ reinitialization_required = UpdateActiveSubmoduleStates();
+ }
+
+ if (processing_config.input_stream() != input_config) {
+ processing_config.input_stream() = input_config;
+ reinitialization_required = true;
+ }
+
+ if (processing_config.output_stream() != output_config) {
+ processing_config.output_stream() = output_config;
+ reinitialization_required = true;
+ }
+
+ if (reinitialization_required) {
+ MutexLock lock_render(&mutex_render_);
+ MutexLock lock_capture(&mutex_capture_);
+ RETURN_ON_ERR(InitializeLocked(processing_config));
+ }
+ return kNoError;
}
int AudioProcessingImpl::ProcessStream(const float* const* src,
const StreamConfig& input_config,
const StreamConfig& output_config,
float* const* dest) {
- CriticalSectionScoped crit_scoped(crit_);
+ TRACE_EVENT0("webrtc", "AudioProcessing::ProcessStream_StreamConfig");
if (!src || !dest) {
return kNullPointerError;
}
- ProcessingConfig processing_config = api_format_;
- processing_config.input_stream() = input_config;
- processing_config.output_stream() = output_config;
+ RETURN_ON_ERR(MaybeInitializeCapture(input_config, output_config));
- RETURN_ON_ERR(MaybeInitializeLocked(processing_config));
- assert(processing_config.input_stream().num_frames() ==
- api_format_.input_stream().num_frames());
+ MutexLock lock_capture(&mutex_capture_);
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- RETURN_ON_ERR(WriteConfigMessage(false));
+ if (aec_dump_) {
+ RecordUnprocessedCaptureStream(src);
+ }
- event_msg_->set_type(audioproc::Event::STREAM);
- audioproc::Stream* msg = event_msg_->mutable_stream();
- const size_t channel_size =
- sizeof(float) * api_format_.input_stream().num_frames();
- for (int i = 0; i < api_format_.input_stream().num_channels(); ++i)
- msg->add_input_channel(src[i], channel_size);
+ capture_.keyboard_info.Extract(src, formats_.api_format.input_stream());
+ capture_.capture_audio->CopyFrom(src, formats_.api_format.input_stream());
+ if (capture_.capture_fullband_audio) {
+ capture_.capture_fullband_audio->CopyFrom(
+ src, formats_.api_format.input_stream());
+ }
+ RETURN_ON_ERR(ProcessCaptureStreamLocked());
+ if (capture_.capture_fullband_audio) {
+ capture_.capture_fullband_audio->CopyTo(formats_.api_format.output_stream(),
+ dest);
+ } else {
+ capture_.capture_audio->CopyTo(formats_.api_format.output_stream(), dest);
}
-#endif
- capture_audio_->CopyFrom(src, api_format_.input_stream());
- RETURN_ON_ERR(ProcessStreamLocked());
- capture_audio_->CopyTo(api_format_.output_stream(), dest);
+ if (aec_dump_) {
+ RecordProcessedCaptureStream(dest);
+ }
+ return kNoError;
+}
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- audioproc::Stream* msg = event_msg_->mutable_stream();
- const size_t channel_size =
- sizeof(float) * api_format_.output_stream().num_frames();
- for (int i = 0; i < api_format_.output_stream().num_channels(); ++i)
- msg->add_output_channel(dest[i], channel_size);
- RETURN_ON_ERR(WriteMessageToDebugFile());
+void AudioProcessingImpl::HandleCaptureRuntimeSettings() {
+ RuntimeSetting setting;
+ while (capture_runtime_settings_.Remove(&setting)) {
+ if (aec_dump_) {
+ aec_dump_->WriteRuntimeSetting(setting);
+ }
+ switch (setting.type()) {
+ case RuntimeSetting::Type::kCapturePreGain:
+ if (config_.pre_amplifier.enabled) {
+ float value;
+ setting.GetFloat(&value);
+ config_.pre_amplifier.fixed_gain_factor = value;
+ submodules_.pre_amplifier->SetGainFactor(value);
+ }
+ // TODO(bugs.chromium.org/9138): Log setting handling by Aec Dump.
+ break;
+ case RuntimeSetting::Type::kCaptureCompressionGain: {
+ if (!submodules_.agc_manager) {
+ float value;
+ setting.GetFloat(&value);
+ int int_value = static_cast<int>(value + .5f);
+ config_.gain_controller1.compression_gain_db = int_value;
+ if (submodules_.gain_control) {
+ int error =
+ submodules_.gain_control->set_compression_gain_db(int_value);
+ RTC_DCHECK_EQ(kNoError, error);
+ }
+ }
+ break;
+ }
+ case RuntimeSetting::Type::kCaptureFixedPostGain: {
+ if (submodules_.gain_controller2) {
+ float value;
+ setting.GetFloat(&value);
+ config_.gain_controller2.fixed_digital.gain_db = value;
+ submodules_.gain_controller2->ApplyConfig(config_.gain_controller2);
+ }
+ break;
+ }
+ case RuntimeSetting::Type::kPlayoutVolumeChange: {
+ int value;
+ setting.GetInt(&value);
+ capture_.playout_volume = value;
+ break;
+ }
+ case RuntimeSetting::Type::kPlayoutAudioDeviceChange:
+ RTC_NOTREACHED();
+ break;
+ case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
+ RTC_NOTREACHED();
+ break;
+ case RuntimeSetting::Type::kNotSpecified:
+ RTC_NOTREACHED();
+ break;
+ case RuntimeSetting::Type::kCaptureOutputUsed:
+ // TODO(b/154437967): Add support for reducing complexity when it is
+ // known that the capture output will not be used.
+ break;
+ }
}
-#endif
+}
- return kNoError;
+void AudioProcessingImpl::HandleRenderRuntimeSettings() {
+ RuntimeSetting setting;
+ while (render_runtime_settings_.Remove(&setting)) {
+ if (aec_dump_) {
+ aec_dump_->WriteRuntimeSetting(setting);
+ }
+ switch (setting.type()) {
+ case RuntimeSetting::Type::kPlayoutAudioDeviceChange: // fall-through
+ case RuntimeSetting::Type::kPlayoutVolumeChange: // fall-through
+ case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
+ if (submodules_.render_pre_processor) {
+ submodules_.render_pre_processor->SetRuntimeSetting(setting);
+ }
+ break;
+ case RuntimeSetting::Type::kCapturePreGain: // fall-through
+ case RuntimeSetting::Type::kCaptureCompressionGain: // fall-through
+ case RuntimeSetting::Type::kCaptureFixedPostGain: // fall-through
+ case RuntimeSetting::Type::kCaptureOutputUsed: // fall-through
+ case RuntimeSetting::Type::kNotSpecified:
+ RTC_NOTREACHED();
+ break;
+ }
+ }
}
-int AudioProcessingImpl::ProcessStream(AudioFrame* frame) {
- CriticalSectionScoped crit_scoped(crit_);
- if (!frame) {
- return kNullPointerError;
+void AudioProcessingImpl::QueueBandedRenderAudio(AudioBuffer* audio) {
+ RTC_DCHECK_GE(160, audio->num_frames_per_band());
+
+ if (submodules_.echo_control_mobile) {
+ EchoControlMobileImpl::PackRenderAudioBuffer(audio, num_output_channels(),
+ num_reverse_channels(),
+ &aecm_render_queue_buffer_);
+ RTC_DCHECK(aecm_render_signal_queue_);
+ // Insert the samples into the queue.
+ if (!aecm_render_signal_queue_->Insert(&aecm_render_queue_buffer_)) {
+ // The data queue is full and needs to be emptied.
+ EmptyQueuedRenderAudio();
+
+ // Retry the insert (should always work).
+ bool result =
+ aecm_render_signal_queue_->Insert(&aecm_render_queue_buffer_);
+ RTC_DCHECK(result);
+ }
}
- // Must be a native rate.
- if (frame->sample_rate_hz_ != kSampleRate8kHz &&
- frame->sample_rate_hz_ != kSampleRate16kHz &&
- frame->sample_rate_hz_ != kSampleRate32kHz &&
- frame->sample_rate_hz_ != kSampleRate48kHz) {
- return kBadSampleRateError;
- }
- if (echo_control_mobile_->is_enabled() &&
- frame->sample_rate_hz_ > kMaxAECMSampleRateHz) {
- LOG(LS_ERROR) << "AECM only supports 16 or 8 kHz sample rates";
- return kUnsupportedComponentError;
- }
-
- // TODO(ajm): The input and output rates and channels are currently
- // constrained to be identical in the int16 interface.
- ProcessingConfig processing_config = api_format_;
- processing_config.input_stream().set_sample_rate_hz(frame->sample_rate_hz_);
- processing_config.input_stream().set_num_channels(frame->num_channels_);
- processing_config.output_stream().set_sample_rate_hz(frame->sample_rate_hz_);
- processing_config.output_stream().set_num_channels(frame->num_channels_);
-
- RETURN_ON_ERR(MaybeInitializeLocked(processing_config));
- if (frame->samples_per_channel_ != api_format_.input_stream().num_frames()) {
- return kBadDataLengthError;
+
+ if (!submodules_.agc_manager && submodules_.gain_control) {
+ GainControlImpl::PackRenderAudioBuffer(*audio, &agc_render_queue_buffer_);
+ // Insert the samples into the queue.
+ if (!agc_render_signal_queue_->Insert(&agc_render_queue_buffer_)) {
+ // The data queue is full and needs to be emptied.
+ EmptyQueuedRenderAudio();
+
+ // Retry the insert (should always work).
+ bool result = agc_render_signal_queue_->Insert(&agc_render_queue_buffer_);
+ RTC_DCHECK(result);
+ }
}
+}
+
+void AudioProcessingImpl::QueueNonbandedRenderAudio(AudioBuffer* audio) {
+ ResidualEchoDetector::PackRenderAudioBuffer(audio, &red_render_queue_buffer_);
+
+ // Insert the samples into the queue.
+ if (!red_render_signal_queue_->Insert(&red_render_queue_buffer_)) {
+ // The data queue is full and needs to be emptied.
+ EmptyQueuedRenderAudio();
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- event_msg_->set_type(audioproc::Event::STREAM);
- audioproc::Stream* msg = event_msg_->mutable_stream();
- const size_t data_size =
- sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
- msg->set_input_data(frame->data_, data_size);
+ // Retry the insert (should always work).
+ bool result = red_render_signal_queue_->Insert(&red_render_queue_buffer_);
+ RTC_DCHECK(result);
}
-#endif
+}
+
+void AudioProcessingImpl::AllocateRenderQueue() {
+ const size_t new_agc_render_queue_element_max_size =
+ std::max(static_cast<size_t>(1), kMaxAllowedValuesOfSamplesPerBand);
- capture_audio_->DeinterleaveFrom(frame);
- RETURN_ON_ERR(ProcessStreamLocked());
- capture_audio_->InterleaveTo(frame, output_copy_needed(is_data_processed()));
+ const size_t new_red_render_queue_element_max_size =
+ std::max(static_cast<size_t>(1), kMaxAllowedValuesOfSamplesPerFrame);
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- audioproc::Stream* msg = event_msg_->mutable_stream();
- const size_t data_size =
- sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
- msg->set_output_data(frame->data_, data_size);
- RETURN_ON_ERR(WriteMessageToDebugFile());
+ // Reallocate the queues if the queue item sizes are too small to fit the
+ // data to put in the queues.
+
+ if (agc_render_queue_element_max_size_ <
+ new_agc_render_queue_element_max_size) {
+ agc_render_queue_element_max_size_ = new_agc_render_queue_element_max_size;
+
+ std::vector<int16_t> template_queue_element(
+ agc_render_queue_element_max_size_);
+
+ agc_render_signal_queue_.reset(
+ new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>(
+ kMaxNumFramesToBuffer, template_queue_element,
+ RenderQueueItemVerifier<int16_t>(
+ agc_render_queue_element_max_size_)));
+
+ agc_render_queue_buffer_.resize(agc_render_queue_element_max_size_);
+ agc_capture_queue_buffer_.resize(agc_render_queue_element_max_size_);
+ } else {
+ agc_render_signal_queue_->Clear();
+ }
+
+ if (red_render_queue_element_max_size_ <
+ new_red_render_queue_element_max_size) {
+ red_render_queue_element_max_size_ = new_red_render_queue_element_max_size;
+
+ std::vector<float> template_queue_element(
+ red_render_queue_element_max_size_);
+
+ red_render_signal_queue_.reset(
+ new SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>(
+ kMaxNumFramesToBuffer, template_queue_element,
+ RenderQueueItemVerifier<float>(
+ red_render_queue_element_max_size_)));
+
+ red_render_queue_buffer_.resize(red_render_queue_element_max_size_);
+ red_capture_queue_buffer_.resize(red_render_queue_element_max_size_);
+ } else {
+ red_render_signal_queue_->Clear();
+ }
+}
+
+void AudioProcessingImpl::EmptyQueuedRenderAudio() {
+ MutexLock lock_capture(&mutex_capture_);
+ EmptyQueuedRenderAudioLocked();
+}
+
+void AudioProcessingImpl::EmptyQueuedRenderAudioLocked() {
+ if (submodules_.echo_control_mobile) {
+ RTC_DCHECK(aecm_render_signal_queue_);
+ while (aecm_render_signal_queue_->Remove(&aecm_capture_queue_buffer_)) {
+ submodules_.echo_control_mobile->ProcessRenderAudio(
+ aecm_capture_queue_buffer_);
+ }
+ }
+
+ if (submodules_.gain_control) {
+ while (agc_render_signal_queue_->Remove(&agc_capture_queue_buffer_)) {
+ submodules_.gain_control->ProcessRenderAudio(agc_capture_queue_buffer_);
+ }
+ }
+
+ while (red_render_signal_queue_->Remove(&red_capture_queue_buffer_)) {
+ RTC_DCHECK(submodules_.echo_detector);
+ submodules_.echo_detector->AnalyzeRenderAudio(red_capture_queue_buffer_);
+ }
+}
+
+int AudioProcessingImpl::ProcessStream(const int16_t* const src,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
+ int16_t* const dest) {
+ TRACE_EVENT0("webrtc", "AudioProcessing::ProcessStream_AudioFrame");
+ RETURN_ON_ERR(MaybeInitializeCapture(input_config, output_config));
+
+ MutexLock lock_capture(&mutex_capture_);
+
+ if (aec_dump_) {
+ RecordUnprocessedCaptureStream(src, input_config);
+ }
+
+ capture_.capture_audio->CopyFrom(src, input_config);
+ if (capture_.capture_fullband_audio) {
+ capture_.capture_fullband_audio->CopyFrom(src, input_config);
+ }
+ RETURN_ON_ERR(ProcessCaptureStreamLocked());
+ if (submodule_states_.CaptureMultiBandProcessingPresent() ||
+ submodule_states_.CaptureFullBandProcessingActive()) {
+ if (capture_.capture_fullband_audio) {
+ capture_.capture_fullband_audio->CopyTo(output_config, dest);
+ } else {
+ capture_.capture_audio->CopyTo(output_config, dest);
+ }
+ }
+
+ if (aec_dump_) {
+ RecordProcessedCaptureStream(dest, output_config);
}
-#endif
return kNoError;
}
-int AudioProcessingImpl::ProcessStreamLocked() {
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- audioproc::Stream* msg = event_msg_->mutable_stream();
- msg->set_delay(stream_delay_ms_);
- msg->set_drift(echo_cancellation_->stream_drift_samples());
- msg->set_level(gain_control()->stream_analog_level());
- msg->set_keypress(key_pressed_);
+int AudioProcessingImpl::ProcessCaptureStreamLocked() {
+ EmptyQueuedRenderAudioLocked();
+ HandleCaptureRuntimeSettings();
+
+ // Ensure that not both the AEC and AECM are active at the same time.
+ // TODO(peah): Simplify once the public API Enable functions for these
+ // are moved to APM.
+ RTC_DCHECK_LE(
+ !!submodules_.echo_controller + !!submodules_.echo_control_mobile, 1);
+
+ AudioBuffer* capture_buffer = capture_.capture_audio.get(); // For brevity.
+ AudioBuffer* linear_aec_buffer = capture_.linear_aec_output.get();
+
+ if (submodules_.high_pass_filter &&
+ config_.high_pass_filter.apply_in_full_band &&
+ !constants_.enforce_split_band_hpf) {
+ submodules_.high_pass_filter->Process(capture_buffer,
+ /*use_split_band_data=*/false);
+ }
+
+ if (submodules_.pre_amplifier) {
+ submodules_.pre_amplifier->ApplyGain(AudioFrameView<float>(
+ capture_buffer->channels(), capture_buffer->num_channels(),
+ capture_buffer->num_frames()));
+ }
+
+ capture_input_rms_.Analyze(rtc::ArrayView<const float>(
+ capture_buffer->channels_const()[0],
+ capture_nonlocked_.capture_processing_format.num_frames()));
+ const bool log_rms = ++capture_rms_interval_counter_ >= 1000;
+ if (log_rms) {
+ capture_rms_interval_counter_ = 0;
+ RmsLevel::Levels levels = capture_input_rms_.AverageAndPeak();
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.ApmCaptureInputLevelAverageRms",
+ levels.average, 1, RmsLevel::kMinLevelDb, 64);
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.ApmCaptureInputLevelPeakRms",
+ levels.peak, 1, RmsLevel::kMinLevelDb, 64);
+ }
+
+ if (submodules_.echo_controller) {
+ // Detect and flag any change in the analog gain.
+ int analog_mic_level = recommended_stream_analog_level_locked();
+ capture_.echo_path_gain_change =
+ capture_.prev_analog_mic_level != analog_mic_level &&
+ capture_.prev_analog_mic_level != -1;
+ capture_.prev_analog_mic_level = analog_mic_level;
+
+ // Detect and flag any change in the pre-amplifier gain.
+ if (submodules_.pre_amplifier) {
+ float pre_amp_gain = submodules_.pre_amplifier->GetGainFactor();
+ capture_.echo_path_gain_change =
+ capture_.echo_path_gain_change ||
+ (capture_.prev_pre_amp_gain != pre_amp_gain &&
+ capture_.prev_pre_amp_gain >= 0.f);
+ capture_.prev_pre_amp_gain = pre_amp_gain;
+ }
+
+ // Detect volume change.
+ capture_.echo_path_gain_change =
+ capture_.echo_path_gain_change ||
+ (capture_.prev_playout_volume != capture_.playout_volume &&
+ capture_.prev_playout_volume >= 0);
+ capture_.prev_playout_volume = capture_.playout_volume;
+
+ submodules_.echo_controller->AnalyzeCapture(capture_buffer);
}
-#endif
- MaybeUpdateHistograms();
+ if (submodules_.agc_manager) {
+ submodules_.agc_manager->AnalyzePreProcess(capture_buffer);
+ }
- AudioBuffer* ca = capture_audio_.get(); // For brevity.
+ if (submodule_states_.CaptureMultiBandSubModulesActive() &&
+ SampleRateSupportsMultiBand(
+ capture_nonlocked_.capture_processing_format.sample_rate_hz())) {
+ capture_buffer->SplitIntoFrequencyBands();
+ }
- if (use_new_agc_ && gain_control_->is_enabled()) {
- agc_manager_->AnalyzePreProcess(ca->channels()[0], ca->num_channels(),
- fwd_proc_format_.num_frames());
+ const bool multi_channel_capture = config_.pipeline.multi_channel_capture &&
+ constants_.multi_channel_capture_support;
+ if (submodules_.echo_controller && !multi_channel_capture) {
+ // Force down-mixing of the number of channels after the detection of
+ // capture signal saturation.
+ // TODO(peah): Look into ensuring that this kind of tampering with the
+ // AudioBuffer functionality should not be needed.
+ capture_buffer->set_num_channels(1);
}
- bool data_processed = is_data_processed();
- if (analysis_needed(data_processed)) {
- ca->SplitIntoFrequencyBands();
+ if (submodules_.high_pass_filter &&
+ (!config_.high_pass_filter.apply_in_full_band ||
+ constants_.enforce_split_band_hpf)) {
+ submodules_.high_pass_filter->Process(capture_buffer,
+ /*use_split_band_data=*/true);
}
- if (intelligibility_enabled_) {
- intelligibility_enhancer_->AnalyzeCaptureAudio(
- ca->split_channels_f(kBand0To8kHz), split_rate_, ca->num_channels());
+ if (submodules_.gain_control) {
+ RETURN_ON_ERR(
+ submodules_.gain_control->AnalyzeCaptureAudio(*capture_buffer));
}
- if (beamformer_enabled_) {
- beamformer_->ProcessChunk(*ca->split_data_f(), ca->split_data_f());
- ca->set_num_channels(1);
+ if ((!config_.noise_suppression.analyze_linear_aec_output_when_available ||
+ !linear_aec_buffer || submodules_.echo_control_mobile) &&
+ submodules_.noise_suppressor) {
+ submodules_.noise_suppressor->Analyze(*capture_buffer);
}
- RETURN_ON_ERR(high_pass_filter_->ProcessCaptureAudio(ca));
- RETURN_ON_ERR(gain_control_->AnalyzeCaptureAudio(ca));
- RETURN_ON_ERR(noise_suppression_->AnalyzeCaptureAudio(ca));
- RETURN_ON_ERR(echo_cancellation_->ProcessCaptureAudio(ca));
+ if (submodules_.echo_control_mobile) {
+ // Ensure that the stream delay was set before the call to the
+ // AECM ProcessCaptureAudio function.
+ if (!capture_.was_stream_delay_set) {
+ return AudioProcessing::kStreamParameterNotSetError;
+ }
+
+ if (submodules_.noise_suppressor) {
+ submodules_.noise_suppressor->Process(capture_buffer);
+ }
+
+ RETURN_ON_ERR(submodules_.echo_control_mobile->ProcessCaptureAudio(
+ capture_buffer, stream_delay_ms()));
+ } else {
+ if (submodules_.echo_controller) {
+ data_dumper_->DumpRaw("stream_delay", stream_delay_ms());
+
+ if (capture_.was_stream_delay_set) {
+ submodules_.echo_controller->SetAudioBufferDelay(stream_delay_ms());
+ }
+
+ submodules_.echo_controller->ProcessCapture(
+ capture_buffer, linear_aec_buffer, capture_.echo_path_gain_change);
+ }
+
+ if (config_.noise_suppression.analyze_linear_aec_output_when_available &&
+ linear_aec_buffer && submodules_.noise_suppressor) {
+ submodules_.noise_suppressor->Analyze(*linear_aec_buffer);
+ }
- if (echo_control_mobile_->is_enabled() && noise_suppression_->is_enabled()) {
- ca->CopyLowPassToReference();
+ if (submodules_.noise_suppressor) {
+ submodules_.noise_suppressor->Process(capture_buffer);
+ }
}
- RETURN_ON_ERR(noise_suppression_->ProcessCaptureAudio(ca));
- RETURN_ON_ERR(echo_control_mobile_->ProcessCaptureAudio(ca));
- RETURN_ON_ERR(voice_detection_->ProcessCaptureAudio(ca));
- if (use_new_agc_ && gain_control_->is_enabled() &&
- (!beamformer_enabled_ || beamformer_->is_target_present())) {
- agc_manager_->Process(ca->split_bands_const(0)[kBand0To8kHz],
- ca->num_frames_per_band(), split_rate_);
+ if (config_.voice_detection.enabled) {
+ capture_.stats.voice_detected =
+ submodules_.voice_detector->ProcessCaptureAudio(capture_buffer);
+ } else {
+ capture_.stats.voice_detected = absl::nullopt;
}
- RETURN_ON_ERR(gain_control_->ProcessCaptureAudio(ca));
- if (synthesis_needed(data_processed)) {
- ca->MergeFrequencyBands();
+ if (submodules_.agc_manager) {
+ submodules_.agc_manager->Process(capture_buffer);
+
+ absl::optional<int> new_digital_gain =
+ submodules_.agc_manager->GetDigitalComressionGain();
+ if (new_digital_gain && submodules_.gain_control) {
+ submodules_.gain_control->set_compression_gain_db(*new_digital_gain);
+ }
+ }
+
+ if (submodules_.gain_control) {
+ // TODO(peah): Add reporting from AEC3 whether there is echo.
+ RETURN_ON_ERR(submodules_.gain_control->ProcessCaptureAudio(
+ capture_buffer, /*stream_has_echo*/ false));
+ }
+
+ if (submodule_states_.CaptureMultiBandProcessingPresent() &&
+ SampleRateSupportsMultiBand(
+ capture_nonlocked_.capture_processing_format.sample_rate_hz())) {
+ capture_buffer->MergeFrequencyBands();
+ }
+
+ if (capture_.capture_fullband_audio) {
+ const auto& ec = submodules_.echo_controller;
+ bool ec_active = ec ? ec->ActiveProcessing() : false;
+ // Only update the fullband buffer if the multiband processing has changed
+ // the signal. Keep the original signal otherwise.
+ if (submodule_states_.CaptureMultiBandProcessingActive(ec_active)) {
+ capture_buffer->CopyTo(capture_.capture_fullband_audio.get());
+ }
+ capture_buffer = capture_.capture_fullband_audio.get();
+ }
+
+ if (config_.residual_echo_detector.enabled) {
+ RTC_DCHECK(submodules_.echo_detector);
+ submodules_.echo_detector->AnalyzeCaptureAudio(rtc::ArrayView<const float>(
+ capture_buffer->channels()[0], capture_buffer->num_frames()));
}
// TODO(aluebs): Investigate if the transient suppression placement should be
// before or after the AGC.
- if (transient_suppressor_enabled_) {
- float voice_probability =
- agc_manager_.get() ? agc_manager_->voice_probability() : 1.f;
+ if (submodules_.transient_suppressor) {
+ float voice_probability = submodules_.agc_manager.get()
+ ? submodules_.agc_manager->voice_probability()
+ : 1.f;
+
+ submodules_.transient_suppressor->Suppress(
+ capture_buffer->channels()[0], capture_buffer->num_frames(),
+ capture_buffer->num_channels(),
+ capture_buffer->split_bands_const(0)[kBand0To8kHz],
+ capture_buffer->num_frames_per_band(),
+ capture_.keyboard_info.keyboard_data,
+ capture_.keyboard_info.num_keyboard_frames, voice_probability,
+ capture_.key_pressed);
+ }
+
+ // Experimental APM sub-module that analyzes |capture_buffer|.
+ if (submodules_.capture_analyzer) {
+ submodules_.capture_analyzer->Analyze(capture_buffer);
+ }
- transient_suppressor_->Suppress(
- ca->channels_f()[0], ca->num_frames(), ca->num_channels(),
- ca->split_bands_const_f(0)[kBand0To8kHz], ca->num_frames_per_band(),
- ca->keyboard_data(), ca->num_keyboard_frames(), voice_probability,
- key_pressed_);
+ if (submodules_.gain_controller2) {
+ submodules_.gain_controller2->NotifyAnalogLevel(
+ recommended_stream_analog_level_locked());
+ submodules_.gain_controller2->Process(capture_buffer);
+ }
+
+ if (submodules_.capture_post_processor) {
+ submodules_.capture_post_processor->Process(capture_buffer);
}
// The level estimator operates on the recombined data.
- RETURN_ON_ERR(level_estimator_->ProcessStream(ca));
+ if (config_.level_estimation.enabled) {
+ submodules_.output_level_estimator->ProcessStream(*capture_buffer);
+ capture_.stats.output_rms_dbfs = submodules_.output_level_estimator->RMS();
+ } else {
+ capture_.stats.output_rms_dbfs = absl::nullopt;
+ }
+
+ capture_output_rms_.Analyze(rtc::ArrayView<const float>(
+ capture_buffer->channels_const()[0],
+ capture_nonlocked_.capture_processing_format.num_frames()));
+ if (log_rms) {
+ RmsLevel::Levels levels = capture_output_rms_.AverageAndPeak();
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.ApmCaptureOutputLevelAverageRms",
+ levels.average, 1, RmsLevel::kMinLevelDb, 64);
+ RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.ApmCaptureOutputLevelPeakRms",
+ levels.peak, 1, RmsLevel::kMinLevelDb, 64);
+ }
+
+ if (submodules_.agc_manager) {
+ int level = recommended_stream_analog_level_locked();
+ data_dumper_->DumpRaw("experimental_gain_control_stream_analog_level", 1,
+ &level);
+ }
+
+ // Compute echo-related stats.
+ if (submodules_.echo_controller) {
+ auto ec_metrics = submodules_.echo_controller->GetMetrics();
+ capture_.stats.echo_return_loss = ec_metrics.echo_return_loss;
+ capture_.stats.echo_return_loss_enhancement =
+ ec_metrics.echo_return_loss_enhancement;
+ capture_.stats.delay_ms = ec_metrics.delay_ms;
+ }
+ if (config_.residual_echo_detector.enabled) {
+ RTC_DCHECK(submodules_.echo_detector);
+ auto ed_metrics = submodules_.echo_detector->GetMetrics();
+ capture_.stats.residual_echo_likelihood = ed_metrics.echo_likelihood;
+ capture_.stats.residual_echo_likelihood_recent_max =
+ ed_metrics.echo_likelihood_recent_max;
+ }
- was_stream_delay_set_ = false;
+ // Pass stats for reporting.
+ stats_reporter_.UpdateStatistics(capture_.stats);
+
+ capture_.was_stream_delay_set = false;
return kNoError;
}
-int AudioProcessingImpl::AnalyzeReverseStream(const float* const* data,
- size_t samples_per_channel,
- int rev_sample_rate_hz,
- ChannelLayout layout) {
- const StreamConfig reverse_config = {
- rev_sample_rate_hz, ChannelsFromLayout(layout), LayoutHasKeyboard(layout),
- };
- if (samples_per_channel != reverse_config.num_frames()) {
- return kBadDataLengthError;
- }
- return AnalyzeReverseStream(data, reverse_config, reverse_config);
+int AudioProcessingImpl::AnalyzeReverseStream(
+ const float* const* data,
+ const StreamConfig& reverse_config) {
+ TRACE_EVENT0("webrtc", "AudioProcessing::AnalyzeReverseStream_StreamConfig");
+ MutexLock lock(&mutex_render_);
+ return AnalyzeReverseStreamLocked(data, reverse_config, reverse_config);
}
-int AudioProcessingImpl::ProcessReverseStream(
- const float* const* src,
- const StreamConfig& reverse_input_config,
- const StreamConfig& reverse_output_config,
- float* const* dest) {
- RETURN_ON_ERR(
- AnalyzeReverseStream(src, reverse_input_config, reverse_output_config));
- if (is_rev_processed()) {
- render_audio_->CopyTo(api_format_.reverse_output_stream(), dest);
- } else if (rev_conversion_needed()) {
- render_converter_->Convert(src, reverse_input_config.num_samples(), dest,
- reverse_output_config.num_samples());
+int AudioProcessingImpl::ProcessReverseStream(const float* const* src,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
+ float* const* dest) {
+ TRACE_EVENT0("webrtc", "AudioProcessing::ProcessReverseStream_StreamConfig");
+ MutexLock lock(&mutex_render_);
+ RETURN_ON_ERR(AnalyzeReverseStreamLocked(src, input_config, output_config));
+ if (submodule_states_.RenderMultiBandProcessingActive() ||
+ submodule_states_.RenderFullBandProcessingActive()) {
+ render_.render_audio->CopyTo(formats_.api_format.reverse_output_stream(),
+ dest);
+ } else if (formats_.api_format.reverse_input_stream() !=
+ formats_.api_format.reverse_output_stream()) {
+ render_.render_converter->Convert(src, input_config.num_samples(), dest,
+ output_config.num_samples());
} else {
- CopyAudioIfNeeded(src, reverse_input_config.num_frames(),
- reverse_input_config.num_channels(), dest);
+ CopyAudioIfNeeded(src, input_config.num_frames(),
+ input_config.num_channels(), dest);
}
return kNoError;
}
-int AudioProcessingImpl::AnalyzeReverseStream(
+int AudioProcessingImpl::AnalyzeReverseStreamLocked(
const float* const* src,
- const StreamConfig& reverse_input_config,
- const StreamConfig& reverse_output_config) {
- CriticalSectionScoped crit_scoped(crit_);
- if (src == NULL) {
+ const StreamConfig& input_config,
+ const StreamConfig& output_config) {
+ if (src == nullptr) {
return kNullPointerError;
}
- if (reverse_input_config.num_channels() <= 0) {
+ if (input_config.num_channels() == 0) {
return kBadNumberChannelsError;
}
- ProcessingConfig processing_config = api_format_;
- processing_config.reverse_input_stream() = reverse_input_config;
- processing_config.reverse_output_stream() = reverse_output_config;
+ ProcessingConfig processing_config = formats_.api_format;
+ processing_config.reverse_input_stream() = input_config;
+ processing_config.reverse_output_stream() = output_config;
- RETURN_ON_ERR(MaybeInitializeLocked(processing_config));
- assert(reverse_input_config.num_frames() ==
- api_format_.reverse_input_stream().num_frames());
+ RETURN_ON_ERR(MaybeInitializeRender(processing_config));
+ RTC_DCHECK_EQ(input_config.num_frames(),
+ formats_.api_format.reverse_input_stream().num_frames());
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
- audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
+ if (aec_dump_) {
const size_t channel_size =
- sizeof(float) * api_format_.reverse_input_stream().num_frames();
- for (int i = 0; i < api_format_.reverse_input_stream().num_channels(); ++i)
- msg->add_channel(src[i], channel_size);
- RETURN_ON_ERR(WriteMessageToDebugFile());
- }
-#endif
-
- render_audio_->CopyFrom(src, api_format_.reverse_input_stream());
- return ProcessReverseStreamLocked();
-}
-
-int AudioProcessingImpl::ProcessReverseStream(AudioFrame* frame) {
- RETURN_ON_ERR(AnalyzeReverseStream(frame));
- if (is_rev_processed()) {
- render_audio_->InterleaveTo(frame, true);
- }
-
- return kNoError;
+ formats_.api_format.reverse_input_stream().num_frames();
+ const size_t num_channels =
+ formats_.api_format.reverse_input_stream().num_channels();
+ aec_dump_->WriteRenderStreamMessage(
+ AudioFrameView<const float>(src, num_channels, channel_size));
+ }
+ render_.render_audio->CopyFrom(src,
+ formats_.api_format.reverse_input_stream());
+ return ProcessRenderStreamLocked();
}
-int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) {
- CriticalSectionScoped crit_scoped(crit_);
- if (frame == NULL) {
- return kNullPointerError;
- }
- // Must be a native rate.
- if (frame->sample_rate_hz_ != kSampleRate8kHz &&
- frame->sample_rate_hz_ != kSampleRate16kHz &&
- frame->sample_rate_hz_ != kSampleRate32kHz &&
- frame->sample_rate_hz_ != kSampleRate48kHz) {
- return kBadSampleRateError;
- }
- // This interface does not tolerate different forward and reverse rates.
- if (frame->sample_rate_hz_ != api_format_.input_stream().sample_rate_hz()) {
- return kBadSampleRateError;
- }
+int AudioProcessingImpl::ProcessReverseStream(const int16_t* const src,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
+ int16_t* const dest) {
+ TRACE_EVENT0("webrtc", "AudioProcessing::ProcessReverseStream_AudioFrame");
- if (frame->num_channels_ <= 0) {
- return kBadNumberChannelsError;
+ if (input_config.num_channels() <= 0) {
+ return AudioProcessing::Error::kBadNumberChannelsError;
}
- ProcessingConfig processing_config = api_format_;
+ MutexLock lock(&mutex_render_);
+ ProcessingConfig processing_config = formats_.api_format;
processing_config.reverse_input_stream().set_sample_rate_hz(
- frame->sample_rate_hz_);
+ input_config.sample_rate_hz());
processing_config.reverse_input_stream().set_num_channels(
- frame->num_channels_);
+ input_config.num_channels());
processing_config.reverse_output_stream().set_sample_rate_hz(
- frame->sample_rate_hz_);
+ output_config.sample_rate_hz());
processing_config.reverse_output_stream().set_num_channels(
- frame->num_channels_);
+ output_config.num_channels());
- RETURN_ON_ERR(MaybeInitializeLocked(processing_config));
- if (frame->samples_per_channel_ !=
- api_format_.reverse_input_stream().num_frames()) {
+ RETURN_ON_ERR(MaybeInitializeRender(processing_config));
+ if (input_config.num_frames() !=
+ formats_.api_format.reverse_input_stream().num_frames()) {
return kBadDataLengthError;
}
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- if (debug_file_->Open()) {
- event_msg_->set_type(audioproc::Event::REVERSE_STREAM);
- audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream();
- const size_t data_size =
- sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_;
- msg->set_data(frame->data_, data_size);
- RETURN_ON_ERR(WriteMessageToDebugFile());
+ if (aec_dump_) {
+ aec_dump_->WriteRenderStreamMessage(src, input_config.num_frames(),
+ input_config.num_channels());
}
-#endif
- render_audio_->DeinterleaveFrom(frame);
- return ProcessReverseStreamLocked();
+
+ render_.render_audio->CopyFrom(src, input_config);
+ RETURN_ON_ERR(ProcessRenderStreamLocked());
+ if (submodule_states_.RenderMultiBandProcessingActive() ||
+ submodule_states_.RenderFullBandProcessingActive()) {
+ render_.render_audio->CopyTo(output_config, dest);
+ }
+ return kNoError;
}
-int AudioProcessingImpl::ProcessReverseStreamLocked() {
- AudioBuffer* ra = render_audio_.get(); // For brevity.
- if (rev_proc_format_.sample_rate_hz() == kSampleRate32kHz) {
- ra->SplitIntoFrequencyBands();
+int AudioProcessingImpl::ProcessRenderStreamLocked() {
+ AudioBuffer* render_buffer = render_.render_audio.get(); // For brevity.
+
+ HandleRenderRuntimeSettings();
+
+ if (submodules_.render_pre_processor) {
+ submodules_.render_pre_processor->Process(render_buffer);
+ }
+
+ QueueNonbandedRenderAudio(render_buffer);
+
+ if (submodule_states_.RenderMultiBandSubModulesActive() &&
+ SampleRateSupportsMultiBand(
+ formats_.render_processing_format.sample_rate_hz())) {
+ render_buffer->SplitIntoFrequencyBands();
}
- if (intelligibility_enabled_) {
- intelligibility_enhancer_->ProcessRenderAudio(
- ra->split_channels_f(kBand0To8kHz), split_rate_, ra->num_channels());
+ if (submodule_states_.RenderMultiBandSubModulesActive()) {
+ QueueBandedRenderAudio(render_buffer);
}
- RETURN_ON_ERR(echo_cancellation_->ProcessRenderAudio(ra));
- RETURN_ON_ERR(echo_control_mobile_->ProcessRenderAudio(ra));
- if (!use_new_agc_) {
- RETURN_ON_ERR(gain_control_->ProcessRenderAudio(ra));
+ // TODO(peah): Perform the queuing inside QueueRenderAudiuo().
+ if (submodules_.echo_controller) {
+ submodules_.echo_controller->AnalyzeRender(render_buffer);
}
- if (rev_proc_format_.sample_rate_hz() == kSampleRate32kHz &&
- is_rev_processed()) {
- ra->MergeFrequencyBands();
+ if (submodule_states_.RenderMultiBandProcessingActive() &&
+ SampleRateSupportsMultiBand(
+ formats_.render_processing_format.sample_rate_hz())) {
+ render_buffer->MergeFrequencyBands();
}
return kNoError;
}
int AudioProcessingImpl::set_stream_delay_ms(int delay) {
+ MutexLock lock(&mutex_capture_);
Error retval = kNoError;
- was_stream_delay_set_ = true;
- delay += delay_offset_ms_;
+ capture_.was_stream_delay_set = true;
if (delay < 0) {
delay = 0;
@@ -876,400 +1478,602 @@ int AudioProcessingImpl::set_stream_delay_ms(int delay) {
retval = kBadStreamParameterWarning;
}
- stream_delay_ms_ = delay;
+ capture_nonlocked_.stream_delay_ms = delay;
return retval;
}
-int AudioProcessingImpl::stream_delay_ms() const {
- return stream_delay_ms_;
+bool AudioProcessingImpl::GetLinearAecOutput(
+ rtc::ArrayView<std::array<float, 160>> linear_output) const {
+ MutexLock lock(&mutex_capture_);
+ AudioBuffer* linear_aec_buffer = capture_.linear_aec_output.get();
+
+ RTC_DCHECK(linear_aec_buffer);
+ if (linear_aec_buffer) {
+ RTC_DCHECK_EQ(1, linear_aec_buffer->num_bands());
+ RTC_DCHECK_EQ(linear_output.size(), linear_aec_buffer->num_channels());
+
+ for (size_t ch = 0; ch < linear_aec_buffer->num_channels(); ++ch) {
+ RTC_DCHECK_EQ(linear_output[ch].size(), linear_aec_buffer->num_frames());
+ rtc::ArrayView<const float> channel_view =
+ rtc::ArrayView<const float>(linear_aec_buffer->channels_const()[ch],
+ linear_aec_buffer->num_frames());
+ std::copy(channel_view.begin(), channel_view.end(),
+ linear_output[ch].begin());
+ }
+ return true;
+ }
+ RTC_LOG(LS_ERROR) << "No linear AEC output available";
+ RTC_NOTREACHED();
+ return false;
}
-bool AudioProcessingImpl::was_stream_delay_set() const {
- return was_stream_delay_set_;
+int AudioProcessingImpl::stream_delay_ms() const {
+ // Used as callback from submodules, hence locking is not allowed.
+ return capture_nonlocked_.stream_delay_ms;
}
void AudioProcessingImpl::set_stream_key_pressed(bool key_pressed) {
- key_pressed_ = key_pressed;
+ MutexLock lock(&mutex_capture_);
+ capture_.key_pressed = key_pressed;
}
-void AudioProcessingImpl::set_delay_offset_ms(int offset) {
- CriticalSectionScoped crit_scoped(crit_);
- delay_offset_ms_ = offset;
-}
+void AudioProcessingImpl::set_stream_analog_level(int level) {
+ MutexLock lock_capture(&mutex_capture_);
-int AudioProcessingImpl::delay_offset_ms() const {
- return delay_offset_ms_;
+ if (submodules_.agc_manager) {
+ submodules_.agc_manager->set_stream_analog_level(level);
+ data_dumper_->DumpRaw("experimental_gain_control_set_stream_analog_level",
+ 1, &level);
+ } else if (submodules_.gain_control) {
+ int error = submodules_.gain_control->set_stream_analog_level(level);
+ RTC_DCHECK_EQ(kNoError, error);
+ } else {
+ capture_.cached_stream_analog_level_ = level;
+ }
}
-int AudioProcessingImpl::StartDebugRecording(
- const char filename[AudioProcessing::kMaxFilenameSize]) {
- CriticalSectionScoped crit_scoped(crit_);
- static_assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize, "");
-
- if (filename == NULL) {
- return kNullPointerError;
- }
+int AudioProcessingImpl::recommended_stream_analog_level() const {
+ MutexLock lock_capture(&mutex_capture_);
+ return recommended_stream_analog_level_locked();
+}
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- // Stop any ongoing recording.
- if (debug_file_->Open()) {
- if (debug_file_->CloseFile() == -1) {
- return kFileError;
- }
+int AudioProcessingImpl::recommended_stream_analog_level_locked() const {
+ if (submodules_.agc_manager) {
+ return submodules_.agc_manager->stream_analog_level();
+ } else if (submodules_.gain_control) {
+ return submodules_.gain_control->stream_analog_level();
+ } else {
+ return capture_.cached_stream_analog_level_;
}
+}
- if (debug_file_->OpenFile(filename, false) == -1) {
- debug_file_->CloseFile();
- return kFileError;
+bool AudioProcessingImpl::CreateAndAttachAecDump(const std::string& file_name,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) {
+ std::unique_ptr<AecDump> aec_dump =
+ AecDumpFactory::Create(file_name, max_log_size_bytes, worker_queue);
+ if (!aec_dump) {
+ return false;
}
- RETURN_ON_ERR(WriteConfigMessage(true));
- RETURN_ON_ERR(WriteInitMessage());
- return kNoError;
-#else
- return kUnsupportedFunctionError;
-#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
+ AttachAecDump(std::move(aec_dump));
+ return true;
}
-int AudioProcessingImpl::StartDebugRecording(FILE* handle) {
- CriticalSectionScoped crit_scoped(crit_);
-
- if (handle == NULL) {
- return kNullPointerError;
+bool AudioProcessingImpl::CreateAndAttachAecDump(FILE* handle,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) {
+ std::unique_ptr<AecDump> aec_dump =
+ AecDumpFactory::Create(handle, max_log_size_bytes, worker_queue);
+ if (!aec_dump) {
+ return false;
}
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- // Stop any ongoing recording.
- if (debug_file_->Open()) {
- if (debug_file_->CloseFile() == -1) {
- return kFileError;
- }
- }
+ AttachAecDump(std::move(aec_dump));
+ return true;
+}
- if (debug_file_->OpenFromFileHandle(handle, true, false) == -1) {
- return kFileError;
- }
+void AudioProcessingImpl::AttachAecDump(std::unique_ptr<AecDump> aec_dump) {
+ RTC_DCHECK(aec_dump);
+ MutexLock lock_render(&mutex_render_);
+ MutexLock lock_capture(&mutex_capture_);
- RETURN_ON_ERR(WriteConfigMessage(true));
- RETURN_ON_ERR(WriteInitMessage());
- return kNoError;
-#else
- return kUnsupportedFunctionError;
-#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
+ // The previously attached AecDump will be destroyed with the
+ // 'aec_dump' parameter, which is after locks are released.
+ aec_dump_.swap(aec_dump);
+ WriteAecDumpConfigMessage(true);
+ aec_dump_->WriteInitMessage(formats_.api_format, rtc::TimeUTCMillis());
}
-int AudioProcessingImpl::StartDebugRecordingForPlatformFile(
- rtc::PlatformFile handle) {
- FILE* stream = rtc::FdopenPlatformFileForWriting(handle);
- return StartDebugRecording(stream);
+void AudioProcessingImpl::DetachAecDump() {
+ // The d-tor of a task-queue based AecDump blocks until all pending
+ // tasks are done. This construction avoids blocking while holding
+ // the render and capture locks.
+ std::unique_ptr<AecDump> aec_dump = nullptr;
+ {
+ MutexLock lock_render(&mutex_render_);
+ MutexLock lock_capture(&mutex_capture_);
+ aec_dump = std::move(aec_dump_);
+ }
}
-int AudioProcessingImpl::StopDebugRecording() {
- CriticalSectionScoped crit_scoped(crit_);
-
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- // We just return if recording hasn't started.
- if (debug_file_->Open()) {
- if (debug_file_->CloseFile() == -1) {
- return kFileError;
- }
- }
- return kNoError;
-#else
- return kUnsupportedFunctionError;
-#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
+void AudioProcessingImpl::MutateConfig(
+ rtc::FunctionView<void(AudioProcessing::Config*)> mutator) {
+ MutexLock lock_render(&mutex_render_);
+ MutexLock lock_capture(&mutex_capture_);
+ mutator(&config_);
+ ApplyConfig(config_);
}
-EchoCancellation* AudioProcessingImpl::echo_cancellation() const {
- return echo_cancellation_;
+AudioProcessing::Config AudioProcessingImpl::GetConfig() const {
+ MutexLock lock_render(&mutex_render_);
+ MutexLock lock_capture(&mutex_capture_);
+ return config_;
}
-EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const {
- return echo_control_mobile_;
+bool AudioProcessingImpl::UpdateActiveSubmoduleStates() {
+ return submodule_states_.Update(
+ config_.high_pass_filter.enabled, !!submodules_.echo_control_mobile,
+ config_.residual_echo_detector.enabled, !!submodules_.noise_suppressor,
+ !!submodules_.gain_control, !!submodules_.gain_controller2,
+ config_.pre_amplifier.enabled, capture_nonlocked_.echo_controller_enabled,
+ config_.voice_detection.enabled, !!submodules_.transient_suppressor);
}
-GainControl* AudioProcessingImpl::gain_control() const {
- if (use_new_agc_) {
- return gain_control_for_new_agc_.get();
+void AudioProcessingImpl::InitializeTransientSuppressor() {
+ if (config_.transient_suppression.enabled) {
+ // Attempt to create a transient suppressor, if one is not already created.
+ if (!submodules_.transient_suppressor) {
+ submodules_.transient_suppressor =
+ CreateTransientSuppressor(submodule_creation_overrides_);
+ }
+ if (submodules_.transient_suppressor) {
+ submodules_.transient_suppressor->Initialize(
+ proc_fullband_sample_rate_hz(), capture_nonlocked_.split_rate,
+ num_proc_channels());
+ } else {
+ RTC_LOG(LS_WARNING)
+ << "No transient suppressor created (probably disabled)";
+ }
+ } else {
+ submodules_.transient_suppressor.reset();
}
- return gain_control_;
}
-HighPassFilter* AudioProcessingImpl::high_pass_filter() const {
- return high_pass_filter_;
+void AudioProcessingImpl::InitializeHighPassFilter(bool forced_reset) {
+ bool high_pass_filter_needed_by_aec =
+ config_.echo_canceller.enabled &&
+ config_.echo_canceller.enforce_high_pass_filtering &&
+ !config_.echo_canceller.mobile_mode;
+ if (submodule_states_.HighPassFilteringRequired() ||
+ high_pass_filter_needed_by_aec) {
+ bool use_full_band = config_.high_pass_filter.apply_in_full_band &&
+ !constants_.enforce_split_band_hpf;
+ int rate = use_full_band ? proc_fullband_sample_rate_hz()
+ : proc_split_sample_rate_hz();
+ size_t num_channels =
+ use_full_band ? num_output_channels() : num_proc_channels();
+
+ if (!submodules_.high_pass_filter ||
+ rate != submodules_.high_pass_filter->sample_rate_hz() ||
+ forced_reset ||
+ num_channels != submodules_.high_pass_filter->num_channels()) {
+ submodules_.high_pass_filter.reset(
+ new HighPassFilter(rate, num_channels));
+ }
+ } else {
+ submodules_.high_pass_filter.reset();
+ }
}
-LevelEstimator* AudioProcessingImpl::level_estimator() const {
- return level_estimator_;
+void AudioProcessingImpl::InitializeVoiceDetector() {
+ if (config_.voice_detection.enabled) {
+ submodules_.voice_detector = std::make_unique<VoiceDetection>(
+ proc_split_sample_rate_hz(), VoiceDetection::kVeryLowLikelihood);
+ } else {
+ submodules_.voice_detector.reset();
+ }
}
+void AudioProcessingImpl::InitializeEchoController() {
+ bool use_echo_controller =
+ echo_control_factory_ ||
+ (config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode);
+
+ if (use_echo_controller) {
+ // Create and activate the echo controller.
+ if (echo_control_factory_) {
+ submodules_.echo_controller = echo_control_factory_->Create(
+ proc_sample_rate_hz(), num_reverse_channels(), num_proc_channels());
+ RTC_DCHECK(submodules_.echo_controller);
+ } else {
+ EchoCanceller3Config config =
+ use_setup_specific_default_aec3_config_
+ ? EchoCanceller3::CreateDefaultConfig(num_reverse_channels(),
+ num_proc_channels())
+ : EchoCanceller3Config();
+ submodules_.echo_controller = std::make_unique<EchoCanceller3>(
+ config, proc_sample_rate_hz(), num_reverse_channels(),
+ num_proc_channels());
+ }
-NoiseSuppression* AudioProcessingImpl::noise_suppression() const {
- return noise_suppression_;
-}
+ // Setup the storage for returning the linear AEC output.
+ if (config_.echo_canceller.export_linear_aec_output) {
+ constexpr int kLinearOutputRateHz = 16000;
+ capture_.linear_aec_output = std::make_unique<AudioBuffer>(
+ kLinearOutputRateHz, num_proc_channels(), kLinearOutputRateHz,
+ num_proc_channels(), kLinearOutputRateHz, num_proc_channels());
+ } else {
+ capture_.linear_aec_output.reset();
+ }
-VoiceDetection* AudioProcessingImpl::voice_detection() const {
- return voice_detection_;
-}
+ capture_nonlocked_.echo_controller_enabled = true;
-bool AudioProcessingImpl::is_data_processed() const {
- if (beamformer_enabled_) {
- return true;
+ submodules_.echo_control_mobile.reset();
+ aecm_render_signal_queue_.reset();
+ return;
}
- int enabled_count = 0;
- for (auto item : component_list_) {
- if (item->is_component_enabled()) {
- enabled_count++;
- }
- }
+ submodules_.echo_controller.reset();
+ capture_nonlocked_.echo_controller_enabled = false;
+ capture_.linear_aec_output.reset();
- // Data is unchanged if no components are enabled, or if only level_estimator_
- // or voice_detection_ is enabled.
- if (enabled_count == 0) {
- return false;
- } else if (enabled_count == 1) {
- if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) {
- return false;
- }
- } else if (enabled_count == 2) {
- if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) {
- return false;
- }
+ if (!config_.echo_canceller.enabled) {
+ submodules_.echo_control_mobile.reset();
+ aecm_render_signal_queue_.reset();
+ return;
}
- return true;
-}
-bool AudioProcessingImpl::output_copy_needed(bool is_data_processed) const {
- // Check if we've upmixed or downmixed the audio.
- return ((api_format_.output_stream().num_channels() !=
- api_format_.input_stream().num_channels()) ||
- is_data_processed || transient_suppressor_enabled_);
-}
+ if (config_.echo_canceller.mobile_mode) {
+ // Create and activate AECM.
+ size_t max_element_size =
+ std::max(static_cast<size_t>(1),
+ kMaxAllowedValuesOfSamplesPerBand *
+ EchoControlMobileImpl::NumCancellersRequired(
+ num_output_channels(), num_reverse_channels()));
-bool AudioProcessingImpl::synthesis_needed(bool is_data_processed) const {
- return (is_data_processed &&
- (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
- fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz));
-}
+ std::vector<int16_t> template_queue_element(max_element_size);
-bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
- if (!is_data_processed && !voice_detection_->is_enabled() &&
- !transient_suppressor_enabled_) {
- // Only level_estimator_ is enabled.
- return false;
- } else if (fwd_proc_format_.sample_rate_hz() == kSampleRate32kHz ||
- fwd_proc_format_.sample_rate_hz() == kSampleRate48kHz) {
- // Something besides level_estimator_ is enabled, and we have super-wb.
- return true;
- }
- return false;
-}
+ aecm_render_signal_queue_.reset(
+ new SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>(
+ kMaxNumFramesToBuffer, template_queue_element,
+ RenderQueueItemVerifier<int16_t>(max_element_size)));
-bool AudioProcessingImpl::is_rev_processed() const {
- return intelligibility_enabled_ && intelligibility_enhancer_->active();
-}
+ aecm_render_queue_buffer_.resize(max_element_size);
+ aecm_capture_queue_buffer_.resize(max_element_size);
-bool AudioProcessingImpl::rev_conversion_needed() const {
- return (api_format_.reverse_input_stream() !=
- api_format_.reverse_output_stream());
-}
+ submodules_.echo_control_mobile.reset(new EchoControlMobileImpl());
-void AudioProcessingImpl::InitializeExperimentalAgc() {
- if (use_new_agc_) {
- if (!agc_manager_.get()) {
- agc_manager_.reset(new AgcManagerDirect(gain_control_,
- gain_control_for_new_agc_.get(),
- agc_startup_min_volume_));
- }
- agc_manager_->Initialize();
- agc_manager_->SetCaptureMuted(output_will_be_muted_);
+ submodules_.echo_control_mobile->Initialize(proc_split_sample_rate_hz(),
+ num_reverse_channels(),
+ num_output_channels());
+ return;
}
+
+ submodules_.echo_control_mobile.reset();
+ aecm_render_signal_queue_.reset();
}
-void AudioProcessingImpl::InitializeTransient() {
- if (transient_suppressor_enabled_) {
- if (!transient_suppressor_.get()) {
- transient_suppressor_.reset(new TransientSuppressor());
+void AudioProcessingImpl::InitializeGainController1() {
+ if (!config_.gain_controller1.enabled) {
+ submodules_.agc_manager.reset();
+ submodules_.gain_control.reset();
+ return;
+ }
+
+ if (!submodules_.gain_control) {
+ submodules_.gain_control.reset(new GainControlImpl());
+ }
+
+ submodules_.gain_control->Initialize(num_proc_channels(),
+ proc_sample_rate_hz());
+
+ if (!config_.gain_controller1.analog_gain_controller.enabled) {
+ int error = submodules_.gain_control->set_mode(
+ Agc1ConfigModeToInterfaceMode(config_.gain_controller1.mode));
+ RTC_DCHECK_EQ(kNoError, error);
+ error = submodules_.gain_control->set_target_level_dbfs(
+ config_.gain_controller1.target_level_dbfs);
+ RTC_DCHECK_EQ(kNoError, error);
+ error = submodules_.gain_control->set_compression_gain_db(
+ config_.gain_controller1.compression_gain_db);
+ RTC_DCHECK_EQ(kNoError, error);
+ error = submodules_.gain_control->enable_limiter(
+ config_.gain_controller1.enable_limiter);
+ RTC_DCHECK_EQ(kNoError, error);
+ error = submodules_.gain_control->set_analog_level_limits(
+ config_.gain_controller1.analog_level_minimum,
+ config_.gain_controller1.analog_level_maximum);
+ RTC_DCHECK_EQ(kNoError, error);
+
+ submodules_.agc_manager.reset();
+ return;
+ }
+
+ if (!submodules_.agc_manager.get() ||
+ submodules_.agc_manager->num_channels() !=
+ static_cast<int>(num_proc_channels()) ||
+ submodules_.agc_manager->sample_rate_hz() !=
+ capture_nonlocked_.split_rate) {
+ int stream_analog_level = -1;
+ const bool re_creation = !!submodules_.agc_manager;
+ if (re_creation) {
+ stream_analog_level = submodules_.agc_manager->stream_analog_level();
+ }
+ submodules_.agc_manager.reset(new AgcManagerDirect(
+ num_proc_channels(),
+ config_.gain_controller1.analog_gain_controller.startup_min_volume,
+ config_.gain_controller1.analog_gain_controller.clipped_level_min,
+ config_.gain_controller1.analog_gain_controller
+ .enable_agc2_level_estimator,
+ !config_.gain_controller1.analog_gain_controller
+ .enable_digital_adaptive,
+ capture_nonlocked_.split_rate));
+ if (re_creation) {
+ submodules_.agc_manager->set_stream_analog_level(stream_analog_level);
}
- transient_suppressor_->Initialize(
- fwd_proc_format_.sample_rate_hz(), split_rate_,
- api_format_.output_stream().num_channels());
}
+ submodules_.agc_manager->Initialize();
+ submodules_.agc_manager->SetupDigitalGainControl(
+ submodules_.gain_control.get());
+ submodules_.agc_manager->SetCaptureMuted(capture_.output_will_be_muted);
}
-void AudioProcessingImpl::InitializeBeamformer() {
- if (beamformer_enabled_) {
- if (!beamformer_) {
- beamformer_.reset(
- new NonlinearBeamformer(array_geometry_, target_direction_));
+void AudioProcessingImpl::InitializeGainController2() {
+ if (config_.gain_controller2.enabled) {
+ if (!submodules_.gain_controller2) {
+ // TODO(alessiob): Move the injected gain controller once injection is
+ // implemented.
+ submodules_.gain_controller2.reset(new GainController2());
}
- beamformer_->Initialize(kChunkSizeMs, split_rate_);
+
+ submodules_.gain_controller2->Initialize(proc_fullband_sample_rate_hz());
+ submodules_.gain_controller2->ApplyConfig(config_.gain_controller2);
+ } else {
+ submodules_.gain_controller2.reset();
}
}
-void AudioProcessingImpl::InitializeIntelligibility() {
- if (intelligibility_enabled_) {
- IntelligibilityEnhancer::Config config;
- config.sample_rate_hz = split_rate_;
- config.num_capture_channels = capture_audio_->num_channels();
- config.num_render_channels = render_audio_->num_channels();
- intelligibility_enhancer_.reset(new IntelligibilityEnhancer(config));
+void AudioProcessingImpl::InitializeNoiseSuppressor() {
+ submodules_.noise_suppressor.reset();
+
+ if (config_.noise_suppression.enabled) {
+ auto map_level =
+ [](AudioProcessing::Config::NoiseSuppression::Level level) {
+ using NoiseSuppresionConfig =
+ AudioProcessing::Config::NoiseSuppression;
+ switch (level) {
+ case NoiseSuppresionConfig::kLow:
+ return NsConfig::SuppressionLevel::k6dB;
+ case NoiseSuppresionConfig::kModerate:
+ return NsConfig::SuppressionLevel::k12dB;
+ case NoiseSuppresionConfig::kHigh:
+ return NsConfig::SuppressionLevel::k18dB;
+ case NoiseSuppresionConfig::kVeryHigh:
+ return NsConfig::SuppressionLevel::k21dB;
+ default:
+ RTC_NOTREACHED();
+ }
+ };
+
+ NsConfig cfg;
+ cfg.target_level = map_level(config_.noise_suppression.level);
+ submodules_.noise_suppressor = std::make_unique<NoiseSuppressor>(
+ cfg, proc_sample_rate_hz(), num_proc_channels());
}
}
-void AudioProcessingImpl::MaybeUpdateHistograms() {
- static const int kMinDiffDelayMs = 60;
+void AudioProcessingImpl::InitializePreAmplifier() {
+ if (config_.pre_amplifier.enabled) {
+ submodules_.pre_amplifier.reset(
+ new GainApplier(true, config_.pre_amplifier.fixed_gain_factor));
+ } else {
+ submodules_.pre_amplifier.reset();
+ }
+}
- if (echo_cancellation()->is_enabled()) {
- // Activate delay_jumps_ counters if we know echo_cancellation is runnning.
- // If a stream has echo we know that the echo_cancellation is in process.
- if (stream_delay_jumps_ == -1 && echo_cancellation()->stream_has_echo()) {
- stream_delay_jumps_ = 0;
- }
- if (aec_system_delay_jumps_ == -1 &&
- echo_cancellation()->stream_has_echo()) {
- aec_system_delay_jumps_ = 0;
- }
+void AudioProcessingImpl::InitializeResidualEchoDetector() {
+ RTC_DCHECK(submodules_.echo_detector);
+ submodules_.echo_detector->Initialize(
+ proc_fullband_sample_rate_hz(), 1,
+ formats_.render_processing_format.sample_rate_hz(), 1);
+}
- // Detect a jump in platform reported system delay and log the difference.
- const int diff_stream_delay_ms = stream_delay_ms_ - last_stream_delay_ms_;
- if (diff_stream_delay_ms > kMinDiffDelayMs && last_stream_delay_ms_ != 0) {
- RTC_HISTOGRAM_COUNTS("WebRTC.Audio.PlatformReportedStreamDelayJump",
- diff_stream_delay_ms, kMinDiffDelayMs, 1000, 100);
- if (stream_delay_jumps_ == -1) {
- stream_delay_jumps_ = 0; // Activate counter if needed.
- }
- stream_delay_jumps_++;
- }
- last_stream_delay_ms_ = stream_delay_ms_;
-
- // Detect a jump in AEC system delay and log the difference.
- const int frames_per_ms = rtc::CheckedDivExact(split_rate_, 1000);
- const int aec_system_delay_ms =
- WebRtcAec_system_delay(echo_cancellation()->aec_core()) / frames_per_ms;
- const int diff_aec_system_delay_ms =
- aec_system_delay_ms - last_aec_system_delay_ms_;
- if (diff_aec_system_delay_ms > kMinDiffDelayMs &&
- last_aec_system_delay_ms_ != 0) {
- RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AecSystemDelayJump",
- diff_aec_system_delay_ms, kMinDiffDelayMs, 1000,
- 100);
- if (aec_system_delay_jumps_ == -1) {
- aec_system_delay_jumps_ = 0; // Activate counter if needed.
- }
- aec_system_delay_jumps_++;
- }
- last_aec_system_delay_ms_ = aec_system_delay_ms;
+void AudioProcessingImpl::InitializeAnalyzer() {
+ if (submodules_.capture_analyzer) {
+ submodules_.capture_analyzer->Initialize(proc_fullband_sample_rate_hz(),
+ num_proc_channels());
}
}
-void AudioProcessingImpl::UpdateHistogramsOnCallEnd() {
- CriticalSectionScoped crit_scoped(crit_);
- if (stream_delay_jumps_ > -1) {
- RTC_HISTOGRAM_ENUMERATION(
- "WebRTC.Audio.NumOfPlatformReportedStreamDelayJumps",
- stream_delay_jumps_, 51);
+void AudioProcessingImpl::InitializePostProcessor() {
+ if (submodules_.capture_post_processor) {
+ submodules_.capture_post_processor->Initialize(
+ proc_fullband_sample_rate_hz(), num_proc_channels());
}
- stream_delay_jumps_ = -1;
- last_stream_delay_ms_ = 0;
+}
- if (aec_system_delay_jumps_ > -1) {
- RTC_HISTOGRAM_ENUMERATION("WebRTC.Audio.NumOfAecSystemDelayJumps",
- aec_system_delay_jumps_, 51);
+void AudioProcessingImpl::InitializePreProcessor() {
+ if (submodules_.render_pre_processor) {
+ submodules_.render_pre_processor->Initialize(
+ formats_.render_processing_format.sample_rate_hz(),
+ formats_.render_processing_format.num_channels());
}
- aec_system_delay_jumps_ = -1;
- last_aec_system_delay_ms_ = 0;
}
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
-int AudioProcessingImpl::WriteMessageToDebugFile() {
- int32_t size = event_msg_->ByteSize();
- if (size <= 0) {
- return kUnspecifiedError;
+void AudioProcessingImpl::WriteAecDumpConfigMessage(bool forced) {
+ if (!aec_dump_) {
+ return;
}
-#if defined(WEBRTC_ARCH_BIG_ENDIAN)
-// TODO(ajm): Use little-endian "on the wire". For the moment, we can be
-// pretty safe in assuming little-endian.
-#endif
- if (!event_msg_->SerializeToString(&event_str_)) {
- return kUnspecifiedError;
+ std::string experiments_description = "";
+ // TODO(peah): Add semicolon-separated concatenations of experiment
+ // descriptions for other submodules.
+ if (config_.gain_controller1.analog_gain_controller.clipped_level_min !=
+ kClippedLevelMin) {
+ experiments_description += "AgcClippingLevelExperiment;";
}
-
- // Write message preceded by its size.
- if (!debug_file_->Write(&size, sizeof(int32_t))) {
- return kFileError;
+ if (!!submodules_.capture_post_processor) {
+ experiments_description += "CapturePostProcessor;";
+ }
+ if (!!submodules_.render_pre_processor) {
+ experiments_description += "RenderPreProcessor;";
}
- if (!debug_file_->Write(event_str_.data(), event_str_.length())) {
- return kFileError;
+ if (capture_nonlocked_.echo_controller_enabled) {
+ experiments_description += "EchoController;";
+ }
+ if (config_.gain_controller2.enabled) {
+ experiments_description += "GainController2;";
}
- event_msg_->Clear();
+ InternalAPMConfig apm_config;
- return kNoError;
+ apm_config.aec_enabled = config_.echo_canceller.enabled;
+ apm_config.aec_delay_agnostic_enabled = false;
+ apm_config.aec_extended_filter_enabled = false;
+ apm_config.aec_suppression_level = 0;
+
+ apm_config.aecm_enabled = !!submodules_.echo_control_mobile;
+ apm_config.aecm_comfort_noise_enabled =
+ submodules_.echo_control_mobile &&
+ submodules_.echo_control_mobile->is_comfort_noise_enabled();
+ apm_config.aecm_routing_mode =
+ submodules_.echo_control_mobile
+ ? static_cast<int>(submodules_.echo_control_mobile->routing_mode())
+ : 0;
+
+ apm_config.agc_enabled = !!submodules_.gain_control;
+
+ apm_config.agc_mode = submodules_.gain_control
+ ? static_cast<int>(submodules_.gain_control->mode())
+ : GainControl::kAdaptiveAnalog;
+ apm_config.agc_limiter_enabled =
+ submodules_.gain_control ? submodules_.gain_control->is_limiter_enabled()
+ : false;
+ apm_config.noise_robust_agc_enabled = !!submodules_.agc_manager;
+
+ apm_config.hpf_enabled = config_.high_pass_filter.enabled;
+
+ apm_config.ns_enabled = config_.noise_suppression.enabled;
+ apm_config.ns_level = static_cast<int>(config_.noise_suppression.level);
+
+ apm_config.transient_suppression_enabled =
+ config_.transient_suppression.enabled;
+ apm_config.experiments_description = experiments_description;
+ apm_config.pre_amplifier_enabled = config_.pre_amplifier.enabled;
+ apm_config.pre_amplifier_fixed_gain_factor =
+ config_.pre_amplifier.fixed_gain_factor;
+
+ if (!forced && apm_config == apm_config_for_aec_dump_) {
+ return;
+ }
+ aec_dump_->WriteConfig(apm_config);
+ apm_config_for_aec_dump_ = apm_config;
}
-int AudioProcessingImpl::WriteInitMessage() {
- event_msg_->set_type(audioproc::Event::INIT);
- audioproc::Init* msg = event_msg_->mutable_init();
- msg->set_sample_rate(api_format_.input_stream().sample_rate_hz());
- msg->set_num_input_channels(api_format_.input_stream().num_channels());
- msg->set_num_output_channels(api_format_.output_stream().num_channels());
- msg->set_num_reverse_channels(
- api_format_.reverse_input_stream().num_channels());
- msg->set_reverse_sample_rate(
- api_format_.reverse_input_stream().sample_rate_hz());
- msg->set_output_sample_rate(api_format_.output_stream().sample_rate_hz());
- // TODO(ekmeyerson): Add reverse output fields to event_msg_.
-
- RETURN_ON_ERR(WriteMessageToDebugFile());
- return kNoError;
+void AudioProcessingImpl::RecordUnprocessedCaptureStream(
+ const float* const* src) {
+ RTC_DCHECK(aec_dump_);
+ WriteAecDumpConfigMessage(false);
+
+ const size_t channel_size = formats_.api_format.input_stream().num_frames();
+ const size_t num_channels = formats_.api_format.input_stream().num_channels();
+ aec_dump_->AddCaptureStreamInput(
+ AudioFrameView<const float>(src, num_channels, channel_size));
+ RecordAudioProcessingState();
}
-int AudioProcessingImpl::WriteConfigMessage(bool forced) {
- audioproc::Config config;
+void AudioProcessingImpl::RecordUnprocessedCaptureStream(
+ const int16_t* const data,
+ const StreamConfig& config) {
+ RTC_DCHECK(aec_dump_);
+ WriteAecDumpConfigMessage(false);
- config.set_aec_enabled(echo_cancellation_->is_enabled());
- config.set_aec_delay_agnostic_enabled(
- echo_cancellation_->is_delay_agnostic_enabled());
- config.set_aec_drift_compensation_enabled(
- echo_cancellation_->is_drift_compensation_enabled());
- config.set_aec_extended_filter_enabled(
- echo_cancellation_->is_extended_filter_enabled());
- config.set_aec_suppression_level(
- static_cast<int>(echo_cancellation_->suppression_level()));
+ aec_dump_->AddCaptureStreamInput(data, config.num_channels(),
+ config.num_frames());
+ RecordAudioProcessingState();
+}
- config.set_aecm_enabled(echo_control_mobile_->is_enabled());
- config.set_aecm_comfort_noise_enabled(
- echo_control_mobile_->is_comfort_noise_enabled());
- config.set_aecm_routing_mode(
- static_cast<int>(echo_control_mobile_->routing_mode()));
+void AudioProcessingImpl::RecordProcessedCaptureStream(
+ const float* const* processed_capture_stream) {
+ RTC_DCHECK(aec_dump_);
- config.set_agc_enabled(gain_control_->is_enabled());
- config.set_agc_mode(static_cast<int>(gain_control_->mode()));
- config.set_agc_limiter_enabled(gain_control_->is_limiter_enabled());
- config.set_noise_robust_agc_enabled(use_new_agc_);
+ const size_t channel_size = formats_.api_format.output_stream().num_frames();
+ const size_t num_channels =
+ formats_.api_format.output_stream().num_channels();
+ aec_dump_->AddCaptureStreamOutput(AudioFrameView<const float>(
+ processed_capture_stream, num_channels, channel_size));
+ aec_dump_->WriteCaptureStreamMessage();
+}
- config.set_hpf_enabled(high_pass_filter_->is_enabled());
+void AudioProcessingImpl::RecordProcessedCaptureStream(
+ const int16_t* const data,
+ const StreamConfig& config) {
+ RTC_DCHECK(aec_dump_);
- config.set_ns_enabled(noise_suppression_->is_enabled());
- config.set_ns_level(static_cast<int>(noise_suppression_->level()));
+ aec_dump_->AddCaptureStreamOutput(data, config.num_channels(),
+ config.num_frames());
+ aec_dump_->WriteCaptureStreamMessage();
+}
- config.set_transient_suppression_enabled(transient_suppressor_enabled_);
+void AudioProcessingImpl::RecordAudioProcessingState() {
+ RTC_DCHECK(aec_dump_);
+ AecDump::AudioProcessingState audio_proc_state;
+ audio_proc_state.delay = capture_nonlocked_.stream_delay_ms;
+ audio_proc_state.drift = 0;
+ audio_proc_state.level = recommended_stream_analog_level_locked();
+ audio_proc_state.keypress = capture_.key_pressed;
+ aec_dump_->AddAudioProcessingState(audio_proc_state);
+}
- std::string serialized_config = config.SerializeAsString();
- if (!forced && last_serialized_config_ == serialized_config) {
- return kNoError;
+AudioProcessingImpl::ApmCaptureState::ApmCaptureState()
+ : was_stream_delay_set(false),
+ output_will_be_muted(false),
+ key_pressed(false),
+ capture_processing_format(kSampleRate16kHz),
+ split_rate(kSampleRate16kHz),
+ echo_path_gain_change(false),
+ prev_analog_mic_level(-1),
+ prev_pre_amp_gain(-1.f),
+ playout_volume(-1),
+ prev_playout_volume(-1) {}
+
+AudioProcessingImpl::ApmCaptureState::~ApmCaptureState() = default;
+
+void AudioProcessingImpl::ApmCaptureState::KeyboardInfo::Extract(
+ const float* const* data,
+ const StreamConfig& stream_config) {
+ if (stream_config.has_keyboard()) {
+ keyboard_data = data[stream_config.num_channels()];
+ } else {
+ keyboard_data = NULL;
}
+ num_keyboard_frames = stream_config.num_frames();
+}
- last_serialized_config_ = serialized_config;
+AudioProcessingImpl::ApmRenderState::ApmRenderState() = default;
- event_msg_->set_type(audioproc::Event::CONFIG);
- event_msg_->mutable_config()->CopyFrom(config);
+AudioProcessingImpl::ApmRenderState::~ApmRenderState() = default;
- RETURN_ON_ERR(WriteMessageToDebugFile());
- return kNoError;
+AudioProcessingImpl::ApmStatsReporter::ApmStatsReporter()
+ : stats_message_queue_(1) {}
+
+AudioProcessingImpl::ApmStatsReporter::~ApmStatsReporter() = default;
+
+AudioProcessingStats AudioProcessingImpl::ApmStatsReporter::GetStatistics() {
+ MutexLock lock_stats(&mutex_stats_);
+ bool new_stats_available = stats_message_queue_.Remove(&cached_stats_);
+ // If the message queue is full, return the cached stats.
+ static_cast<void>(new_stats_available);
+
+ return cached_stats_;
+}
+
+void AudioProcessingImpl::ApmStatsReporter::UpdateStatistics(
+ const AudioProcessingStats& new_stats) {
+ AudioProcessingStats stats_to_queue = new_stats;
+ bool stats_message_passed = stats_message_queue_.Insert(&stats_to_queue);
+ // If the message queue is full, discard the new stats.
+ static_cast<void>(stats_message_passed);
}
-#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/audio_processing_impl.h b/webrtc/modules/audio_processing/audio_processing_impl.h
index 542886e..d0eec0e 100644
--- a/webrtc/modules/audio_processing/audio_processing_impl.h
+++ b/webrtc/modules/audio_processing/audio_processing_impl.h
@@ -8,212 +8,514 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
+#ifndef MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
+#define MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
+
+#include <stdio.h>
#include <list>
+#include <memory>
#include <string>
#include <vector>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/base/thread_annotations.h"
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
+#include "api/function_view.h"
+#include "modules/audio_processing/aec3/echo_canceller3.h"
+#include "modules/audio_processing/agc/agc_manager_direct.h"
+#include "modules/audio_processing/agc/gain_control.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/echo_control_mobile_impl.h"
+#include "modules/audio_processing/gain_control_impl.h"
+#include "modules/audio_processing/gain_controller2.h"
+#include "modules/audio_processing/high_pass_filter.h"
+#include "modules/audio_processing/include/aec_dump.h"
+#include "modules/audio_processing/include/audio_frame_proxies.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "modules/audio_processing/include/audio_processing_statistics.h"
+#include "modules/audio_processing/level_estimator.h"
+#include "modules/audio_processing/ns/noise_suppressor.h"
+#include "modules/audio_processing/optionally_built_submodule_creators.h"
+#include "modules/audio_processing/render_queue_item_verifier.h"
+#include "modules/audio_processing/residual_echo_detector.h"
+#include "modules/audio_processing/rms_level.h"
+#include "modules/audio_processing/transient/transient_suppressor.h"
+#include "modules/audio_processing/voice_detection.h"
+#include "rtc_base/gtest_prod_util.h"
+#include "rtc_base/ignore_wundef.h"
+#include "rtc_base/swap_queue.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
namespace webrtc {
-class AgcManagerDirect;
-class AudioBuffer;
+class ApmDataDumper;
class AudioConverter;
-template<typename T>
-class Beamformer;
-
-class CriticalSectionWrapper;
-class EchoCancellationImpl;
-class EchoControlMobileImpl;
-class FileWrapper;
-class GainControlImpl;
-class GainControlForNewAgc;
-class HighPassFilterImpl;
-class LevelEstimatorImpl;
-class NoiseSuppressionImpl;
-class ProcessingComponent;
-class TransientSuppressor;
-class VoiceDetectionImpl;
-class IntelligibilityEnhancer;
-
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
-namespace audioproc {
-
-class Event;
-
-} // namespace audioproc
-#endif
-
class AudioProcessingImpl : public AudioProcessing {
public:
- explicit AudioProcessingImpl(const Config& config);
-
- // AudioProcessingImpl takes ownership of beamformer.
- AudioProcessingImpl(const Config& config, Beamformer<float>* beamformer);
- virtual ~AudioProcessingImpl();
-
- // AudioProcessing methods.
+ // Methods forcing APM to run in a single-threaded manner.
+ // Acquires both the render and capture locks.
+ explicit AudioProcessingImpl(const webrtc::Config& config);
+ // AudioProcessingImpl takes ownership of capture post processor.
+ AudioProcessingImpl(const webrtc::Config& config,
+ std::unique_ptr<CustomProcessing> capture_post_processor,
+ std::unique_ptr<CustomProcessing> render_pre_processor,
+ std::unique_ptr<EchoControlFactory> echo_control_factory,
+ rtc::scoped_refptr<EchoDetector> echo_detector,
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer);
+ ~AudioProcessingImpl() override;
int Initialize() override;
- int Initialize(int input_sample_rate_hz,
- int output_sample_rate_hz,
- int reverse_sample_rate_hz,
- ChannelLayout input_layout,
- ChannelLayout output_layout,
- ChannelLayout reverse_layout) override;
+ int Initialize(int capture_input_sample_rate_hz,
+ int capture_output_sample_rate_hz,
+ int render_sample_rate_hz,
+ ChannelLayout capture_input_layout,
+ ChannelLayout capture_output_layout,
+ ChannelLayout render_input_layout) override;
int Initialize(const ProcessingConfig& processing_config) override;
- void SetExtraOptions(const Config& config) override;
- int proc_sample_rate_hz() const override;
- int proc_split_sample_rate_hz() const override;
- int num_input_channels() const override;
- int num_output_channels() const override;
- int num_reverse_channels() const override;
- void set_output_will_be_muted(bool muted) override;
- int ProcessStream(AudioFrame* frame) override;
- int ProcessStream(const float* const* src,
- size_t samples_per_channel,
- int input_sample_rate_hz,
- ChannelLayout input_layout,
- int output_sample_rate_hz,
- ChannelLayout output_layout,
- float* const* dest) override;
+ void ApplyConfig(const AudioProcessing::Config& config) override;
+ bool CreateAndAttachAecDump(const std::string& file_name,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) override;
+ bool CreateAndAttachAecDump(FILE* handle,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) override;
+ // TODO(webrtc:5298) Deprecated variant.
+ void AttachAecDump(std::unique_ptr<AecDump> aec_dump) override;
+ void DetachAecDump() override;
+ void SetRuntimeSetting(RuntimeSetting setting) override;
+
+ // Capture-side exclusive methods possibly running APM in a
+ // multi-threaded manner. Acquire the capture lock.
+ int ProcessStream(const int16_t* const src,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
+ int16_t* const dest) override;
int ProcessStream(const float* const* src,
const StreamConfig& input_config,
const StreamConfig& output_config,
float* const* dest) override;
- int AnalyzeReverseStream(AudioFrame* frame) override;
- int ProcessReverseStream(AudioFrame* frame) override;
+ bool GetLinearAecOutput(
+ rtc::ArrayView<std::array<float, 160>> linear_output) const override;
+ void set_output_will_be_muted(bool muted) override;
+ int set_stream_delay_ms(int delay) override;
+ void set_stream_key_pressed(bool key_pressed) override;
+ void set_stream_analog_level(int level) override;
+ int recommended_stream_analog_level() const
+ RTC_LOCKS_EXCLUDED(mutex_capture_) override;
+
+ // Render-side exclusive methods possibly running APM in a
+ // multi-threaded manner. Acquire the render lock.
+ int ProcessReverseStream(const int16_t* const src,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
+ int16_t* const dest) override;
int AnalyzeReverseStream(const float* const* data,
- size_t samples_per_channel,
- int sample_rate_hz,
- ChannelLayout layout) override;
+ const StreamConfig& reverse_config) override;
int ProcessReverseStream(const float* const* src,
- const StreamConfig& reverse_input_config,
- const StreamConfig& reverse_output_config,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
float* const* dest) override;
- int set_stream_delay_ms(int delay) override;
+
+ // Methods only accessed from APM submodules or
+ // from AudioProcessing tests in a single-threaded manner.
+ // Hence there is no need for locks in these.
+ int proc_sample_rate_hz() const override;
+ int proc_split_sample_rate_hz() const override;
+ size_t num_input_channels() const override;
+ size_t num_proc_channels() const override;
+ size_t num_output_channels() const override;
+ size_t num_reverse_channels() const override;
int stream_delay_ms() const override;
- bool was_stream_delay_set() const override;
- void set_delay_offset_ms(int offset) override;
- int delay_offset_ms() const override;
- void set_stream_key_pressed(bool key_pressed) override;
- int StartDebugRecording(const char filename[kMaxFilenameSize]) override;
- int StartDebugRecording(FILE* handle) override;
- int StartDebugRecordingForPlatformFile(rtc::PlatformFile handle) override;
- int StopDebugRecording() override;
- void UpdateHistogramsOnCallEnd() override;
- EchoCancellation* echo_cancellation() const override;
- EchoControlMobile* echo_control_mobile() const override;
- GainControl* gain_control() const override;
- HighPassFilter* high_pass_filter() const override;
- LevelEstimator* level_estimator() const override;
- NoiseSuppression* noise_suppression() const override;
- VoiceDetection* voice_detection() const override;
+
+ AudioProcessingStats GetStatistics(bool has_remote_tracks) override {
+ return GetStatistics();
+ }
+ AudioProcessingStats GetStatistics() override {
+ return stats_reporter_.GetStatistics();
+ }
+
+ // TODO(peah): Remove MutateConfig once the new API allows that.
+ void MutateConfig(rtc::FunctionView<void(AudioProcessing::Config*)> mutator);
+ AudioProcessing::Config GetConfig() const override;
protected:
// Overridden in a mock.
- virtual int InitializeLocked() EXCLUSIVE_LOCKS_REQUIRED(crit_);
+ virtual void InitializeLocked()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_);
private:
+ // TODO(peah): These friend classes should be removed as soon as the new
+ // parameter setting scheme allows.
+ FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, DefaultBehavior);
+ FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, ValidConfigBehavior);
+ FRIEND_TEST_ALL_PREFIXES(ApmConfiguration, InValidConfigBehavior);
+ FRIEND_TEST_ALL_PREFIXES(ApmWithSubmodulesExcludedTest,
+ ToggleTransientSuppressor);
+ FRIEND_TEST_ALL_PREFIXES(ApmWithSubmodulesExcludedTest,
+ ReinitializeTransientSuppressor);
+ FRIEND_TEST_ALL_PREFIXES(ApmWithSubmodulesExcludedTest,
+ BitexactWithDisabledModules);
+
+ int recommended_stream_analog_level_locked() const
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ void OverrideSubmoduleCreationForTesting(
+ const ApmSubmoduleCreationOverrides& overrides);
+
+ // Class providing thread-safe message pipe functionality for
+ // |runtime_settings_|.
+ class RuntimeSettingEnqueuer {
+ public:
+ explicit RuntimeSettingEnqueuer(
+ SwapQueue<RuntimeSetting>* runtime_settings);
+ ~RuntimeSettingEnqueuer();
+ void Enqueue(RuntimeSetting setting);
+
+ private:
+ SwapQueue<RuntimeSetting>& runtime_settings_;
+ };
+
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ static int instance_count_;
+ const bool use_setup_specific_default_aec3_config_;
+
+ SwapQueue<RuntimeSetting> capture_runtime_settings_;
+ SwapQueue<RuntimeSetting> render_runtime_settings_;
+
+ RuntimeSettingEnqueuer capture_runtime_settings_enqueuer_;
+ RuntimeSettingEnqueuer render_runtime_settings_enqueuer_;
+
+ // EchoControl factory.
+ std::unique_ptr<EchoControlFactory> echo_control_factory_;
+
+ class SubmoduleStates {
+ public:
+ SubmoduleStates(bool capture_post_processor_enabled,
+ bool render_pre_processor_enabled,
+ bool capture_analyzer_enabled);
+ // Updates the submodule state and returns true if it has changed.
+ bool Update(bool high_pass_filter_enabled,
+ bool mobile_echo_controller_enabled,
+ bool residual_echo_detector_enabled,
+ bool noise_suppressor_enabled,
+ bool adaptive_gain_controller_enabled,
+ bool gain_controller2_enabled,
+ bool pre_amplifier_enabled,
+ bool echo_controller_enabled,
+ bool voice_detector_enabled,
+ bool transient_suppressor_enabled);
+ bool CaptureMultiBandSubModulesActive() const;
+ bool CaptureMultiBandProcessingPresent() const;
+ bool CaptureMultiBandProcessingActive(bool ec_processing_active) const;
+ bool CaptureFullBandProcessingActive() const;
+ bool CaptureAnalyzerActive() const;
+ bool RenderMultiBandSubModulesActive() const;
+ bool RenderFullBandProcessingActive() const;
+ bool RenderMultiBandProcessingActive() const;
+ bool HighPassFilteringRequired() const;
+
+ private:
+ const bool capture_post_processor_enabled_ = false;
+ const bool render_pre_processor_enabled_ = false;
+ const bool capture_analyzer_enabled_ = false;
+ bool high_pass_filter_enabled_ = false;
+ bool mobile_echo_controller_enabled_ = false;
+ bool residual_echo_detector_enabled_ = false;
+ bool noise_suppressor_enabled_ = false;
+ bool adaptive_gain_controller_enabled_ = false;
+ bool gain_controller2_enabled_ = false;
+ bool pre_amplifier_enabled_ = false;
+ bool echo_controller_enabled_ = false;
+ bool voice_detector_enabled_ = false;
+ bool transient_suppressor_enabled_ = false;
+ bool first_update_ = true;
+ };
+
+ // Methods for modifying the formats struct that is used by both
+ // the render and capture threads. The check for whether modifications are
+ // needed is done while holding a single lock only, thereby avoiding that the
+ // capture thread blocks the render thread.
+ // Called by render: Holds the render lock when reading the format struct and
+ // acquires both locks if reinitialization is required.
+ int MaybeInitializeRender(const ProcessingConfig& processing_config)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_);
+ // Called by capture: Holds the capture lock when reading the format struct
+ // and acquires both locks if reinitialization is needed.
+ int MaybeInitializeCapture(const StreamConfig& input_config,
+ const StreamConfig& output_config);
+
+ // Method for updating the state keeping track of the active submodules.
+ // Returns a bool indicating whether the state has changed.
+ bool UpdateActiveSubmoduleStates()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ // Methods requiring APM running in a single-threaded manner, requiring both
+ // the render and capture lock to be acquired.
int InitializeLocked(const ProcessingConfig& config)
- EXCLUSIVE_LOCKS_REQUIRED(crit_);
- int MaybeInitializeLocked(const ProcessingConfig& config)
- EXCLUSIVE_LOCKS_REQUIRED(crit_);
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_);
+ void InitializeResidualEchoDetector()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_);
+ void InitializeEchoController()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_);
+
+ // Initializations of capture-only submodules, requiring the capture lock
+ // already acquired.
+ void InitializeHighPassFilter(bool forced_reset)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void InitializeVoiceDetector() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void InitializeGainController1() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void InitializeTransientSuppressor()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void InitializeGainController2() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void InitializeNoiseSuppressor() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void InitializePreAmplifier() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void InitializePostProcessor() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void InitializeAnalyzer() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ // Initializations of render-only submodules, requiring the render lock
+ // already acquired.
+ void InitializePreProcessor() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_);
+
+ // Sample rate used for the fullband processing.
+ int proc_fullband_sample_rate_hz() const
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ // Empties and handles the respective RuntimeSetting queues.
+ void HandleCaptureRuntimeSettings()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void HandleRenderRuntimeSettings()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_);
+
+ void EmptyQueuedRenderAudio() RTC_LOCKS_EXCLUDED(mutex_capture_);
+ void EmptyQueuedRenderAudioLocked()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+ void AllocateRenderQueue()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_, mutex_capture_);
+ void QueueBandedRenderAudio(AudioBuffer* audio)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_);
+ void QueueNonbandedRenderAudio(AudioBuffer* audio)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_);
+
+ // Capture-side exclusive methods possibly running APM in a multi-threaded
+ // manner that are called with the render lock already acquired.
+ int ProcessCaptureStreamLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ // Render-side exclusive methods possibly running APM in a multi-threaded
+ // manner that are called with the render lock already acquired.
// TODO(ekm): Remove once all clients updated to new interface.
- int AnalyzeReverseStream(const float* const* src,
- const StreamConfig& input_config,
- const StreamConfig& output_config);
- int ProcessStreamLocked() EXCLUSIVE_LOCKS_REQUIRED(crit_);
- int ProcessReverseStreamLocked() EXCLUSIVE_LOCKS_REQUIRED(crit_);
-
- bool is_data_processed() const;
- bool output_copy_needed(bool is_data_processed) const;
- bool synthesis_needed(bool is_data_processed) const;
- bool analysis_needed(bool is_data_processed) const;
- bool is_rev_processed() const;
- bool rev_conversion_needed() const;
- void InitializeExperimentalAgc() EXCLUSIVE_LOCKS_REQUIRED(crit_);
- void InitializeTransient() EXCLUSIVE_LOCKS_REQUIRED(crit_);
- void InitializeBeamformer() EXCLUSIVE_LOCKS_REQUIRED(crit_);
- void InitializeIntelligibility() EXCLUSIVE_LOCKS_REQUIRED(crit_);
- void MaybeUpdateHistograms() EXCLUSIVE_LOCKS_REQUIRED(crit_);
-
- EchoCancellationImpl* echo_cancellation_;
- EchoControlMobileImpl* echo_control_mobile_;
- GainControlImpl* gain_control_;
- HighPassFilterImpl* high_pass_filter_;
- LevelEstimatorImpl* level_estimator_;
- NoiseSuppressionImpl* noise_suppression_;
- VoiceDetectionImpl* voice_detection_;
- rtc::scoped_ptr<GainControlForNewAgc> gain_control_for_new_agc_;
-
- std::list<ProcessingComponent*> component_list_;
- CriticalSectionWrapper* crit_;
- rtc::scoped_ptr<AudioBuffer> render_audio_;
- rtc::scoped_ptr<AudioBuffer> capture_audio_;
- rtc::scoped_ptr<AudioConverter> render_converter_;
-#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
- // TODO(andrew): make this more graceful. Ideally we would split this stuff
- // out into a separate class with an "enabled" and "disabled" implementation.
- int WriteMessageToDebugFile();
- int WriteInitMessage();
-
- // Writes Config message. If not |forced|, only writes the current config if
- // it is different from the last saved one; if |forced|, writes the config
- // regardless of the last saved.
- int WriteConfigMessage(bool forced);
-
- rtc::scoped_ptr<FileWrapper> debug_file_;
- rtc::scoped_ptr<audioproc::Event> event_msg_; // Protobuf message.
- std::string event_str_; // Memory for protobuf serialization.
-
- // Serialized string of last saved APM configuration.
- std::string last_serialized_config_;
-#endif
-
- // Format of processing streams at input/output call sites.
- ProcessingConfig api_format_;
-
- // Only the rate and samples fields of fwd_proc_format_ are used because the
- // forward processing number of channels is mutable and is tracked by the
- // capture_audio_.
- StreamConfig fwd_proc_format_;
- StreamConfig rev_proc_format_;
- int split_rate_;
-
- int stream_delay_ms_;
- int delay_offset_ms_;
- bool was_stream_delay_set_;
- int last_stream_delay_ms_;
- int last_aec_system_delay_ms_;
- int stream_delay_jumps_;
- int aec_system_delay_jumps_;
-
- bool output_will_be_muted_ GUARDED_BY(crit_);
-
- bool key_pressed_;
-
- // Only set through the constructor's Config parameter.
- const bool use_new_agc_;
- rtc::scoped_ptr<AgcManagerDirect> agc_manager_ GUARDED_BY(crit_);
- int agc_startup_min_volume_;
-
- bool transient_suppressor_enabled_;
- rtc::scoped_ptr<TransientSuppressor> transient_suppressor_;
- const bool beamformer_enabled_;
- rtc::scoped_ptr<Beamformer<float>> beamformer_;
- const std::vector<Point> array_geometry_;
- const SphericalPointf target_direction_;
-
- bool intelligibility_enabled_;
- rtc::scoped_ptr<IntelligibilityEnhancer> intelligibility_enhancer_;
+ int AnalyzeReverseStreamLocked(const float* const* src,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_);
+ int ProcessRenderStreamLocked() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_render_);
+
+ // Collects configuration settings from public and private
+ // submodules to be saved as an audioproc::Config message on the
+ // AecDump if it is attached. If not |forced|, only writes the current
+ // config if it is different from the last saved one; if |forced|,
+ // writes the config regardless of the last saved.
+ void WriteAecDumpConfigMessage(bool forced)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ // Notifies attached AecDump of current configuration and capture data.
+ void RecordUnprocessedCaptureStream(const float* const* capture_stream)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ void RecordUnprocessedCaptureStream(const int16_t* const data,
+ const StreamConfig& config)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ // Notifies attached AecDump of current configuration and
+ // processed capture data and issues a capture stream recording
+ // request.
+ void RecordProcessedCaptureStream(
+ const float* const* processed_capture_stream)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ void RecordProcessedCaptureStream(const int16_t* const data,
+ const StreamConfig& config)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ // Notifies attached AecDump about current state (delay, drift, etc).
+ void RecordAudioProcessingState()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_capture_);
+
+ // AecDump instance used for optionally logging APM config, input
+ // and output to file in the AEC-dump format defined in debug.proto.
+ std::unique_ptr<AecDump> aec_dump_;
+
+ // Hold the last config written with AecDump for avoiding writing
+ // the same config twice.
+ InternalAPMConfig apm_config_for_aec_dump_ RTC_GUARDED_BY(mutex_capture_);
+
+ // Critical sections.
+ mutable Mutex mutex_render_ RTC_ACQUIRED_BEFORE(mutex_capture_);
+ mutable Mutex mutex_capture_;
+
+ // Struct containing the Config specifying the behavior of APM.
+ AudioProcessing::Config config_;
+
+ // Overrides for testing the exclusion of some submodules from the build.
+ ApmSubmoduleCreationOverrides submodule_creation_overrides_
+ RTC_GUARDED_BY(mutex_capture_);
+
+ // Class containing information about what submodules are active.
+ SubmoduleStates submodule_states_;
+
+ // Struct containing the pointers to the submodules.
+ struct Submodules {
+ Submodules(std::unique_ptr<CustomProcessing> capture_post_processor,
+ std::unique_ptr<CustomProcessing> render_pre_processor,
+ rtc::scoped_refptr<EchoDetector> echo_detector,
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer)
+ : echo_detector(std::move(echo_detector)),
+ capture_post_processor(std::move(capture_post_processor)),
+ render_pre_processor(std::move(render_pre_processor)),
+ capture_analyzer(std::move(capture_analyzer)) {}
+ // Accessed internally from capture or during initialization.
+ std::unique_ptr<AgcManagerDirect> agc_manager;
+ std::unique_ptr<GainControlImpl> gain_control;
+ std::unique_ptr<GainController2> gain_controller2;
+ std::unique_ptr<HighPassFilter> high_pass_filter;
+ rtc::scoped_refptr<EchoDetector> echo_detector;
+ std::unique_ptr<EchoControl> echo_controller;
+ std::unique_ptr<EchoControlMobileImpl> echo_control_mobile;
+ std::unique_ptr<NoiseSuppressor> noise_suppressor;
+ std::unique_ptr<TransientSuppressor> transient_suppressor;
+ std::unique_ptr<CustomProcessing> capture_post_processor;
+ std::unique_ptr<CustomProcessing> render_pre_processor;
+ std::unique_ptr<GainApplier> pre_amplifier;
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer;
+ std::unique_ptr<LevelEstimator> output_level_estimator;
+ std::unique_ptr<VoiceDetection> voice_detector;
+ } submodules_;
+
+ // State that is written to while holding both the render and capture locks
+ // but can be read without any lock being held.
+ // As this is only accessed internally of APM, and all internal methods in APM
+ // either are holding the render or capture locks, this construct is safe as
+ // it is not possible to read the variables while writing them.
+ struct ApmFormatState {
+ ApmFormatState()
+ : // Format of processing streams at input/output call sites.
+ api_format({{{kSampleRate16kHz, 1, false},
+ {kSampleRate16kHz, 1, false},
+ {kSampleRate16kHz, 1, false},
+ {kSampleRate16kHz, 1, false}}}),
+ render_processing_format(kSampleRate16kHz, 1) {}
+ ProcessingConfig api_format;
+ StreamConfig render_processing_format;
+ } formats_;
+
+ // APM constants.
+ const struct ApmConstants {
+ ApmConstants(bool multi_channel_render_support,
+ bool multi_channel_capture_support,
+ bool enforce_split_band_hpf)
+ : multi_channel_render_support(multi_channel_render_support),
+ multi_channel_capture_support(multi_channel_capture_support),
+ enforce_split_band_hpf(enforce_split_band_hpf) {}
+ bool multi_channel_render_support;
+ bool multi_channel_capture_support;
+ bool enforce_split_band_hpf;
+ } constants_;
+
+ struct ApmCaptureState {
+ ApmCaptureState();
+ ~ApmCaptureState();
+ bool was_stream_delay_set;
+ bool output_will_be_muted;
+ bool key_pressed;
+ std::unique_ptr<AudioBuffer> capture_audio;
+ std::unique_ptr<AudioBuffer> capture_fullband_audio;
+ std::unique_ptr<AudioBuffer> linear_aec_output;
+ // Only the rate and samples fields of capture_processing_format_ are used
+ // because the capture processing number of channels is mutable and is
+ // tracked by the capture_audio_.
+ StreamConfig capture_processing_format;
+ int split_rate;
+ bool echo_path_gain_change;
+ int prev_analog_mic_level;
+ float prev_pre_amp_gain;
+ int playout_volume;
+ int prev_playout_volume;
+ AudioProcessingStats stats;
+ struct KeyboardInfo {
+ void Extract(const float* const* data, const StreamConfig& stream_config);
+ size_t num_keyboard_frames = 0;
+ const float* keyboard_data = nullptr;
+ } keyboard_info;
+ int cached_stream_analog_level_ = 0;
+ } capture_ RTC_GUARDED_BY(mutex_capture_);
+
+ struct ApmCaptureNonLockedState {
+ ApmCaptureNonLockedState()
+ : capture_processing_format(kSampleRate16kHz),
+ split_rate(kSampleRate16kHz),
+ stream_delay_ms(0) {}
+ // Only the rate and samples fields of capture_processing_format_ are used
+ // because the forward processing number of channels is mutable and is
+ // tracked by the capture_audio_.
+ StreamConfig capture_processing_format;
+ int split_rate;
+ int stream_delay_ms;
+ bool echo_controller_enabled = false;
+ } capture_nonlocked_;
+
+ struct ApmRenderState {
+ ApmRenderState();
+ ~ApmRenderState();
+ std::unique_ptr<AudioConverter> render_converter;
+ std::unique_ptr<AudioBuffer> render_audio;
+ } render_ RTC_GUARDED_BY(mutex_render_);
+
+ // Class for statistics reporting. The class is thread-safe and no lock is
+ // needed when accessing it.
+ class ApmStatsReporter {
+ public:
+ ApmStatsReporter();
+ ~ApmStatsReporter();
+
+ // Returns the most recently reported statistics.
+ AudioProcessingStats GetStatistics();
+
+ // Update the cached statistics.
+ void UpdateStatistics(const AudioProcessingStats& new_stats);
+
+ private:
+ Mutex mutex_stats_;
+ AudioProcessingStats cached_stats_ RTC_GUARDED_BY(mutex_stats_);
+ SwapQueue<AudioProcessingStats> stats_message_queue_;
+ } stats_reporter_;
+
+ std::vector<int16_t> aecm_render_queue_buffer_ RTC_GUARDED_BY(mutex_render_);
+ std::vector<int16_t> aecm_capture_queue_buffer_
+ RTC_GUARDED_BY(mutex_capture_);
+
+ size_t agc_render_queue_element_max_size_ RTC_GUARDED_BY(mutex_render_)
+ RTC_GUARDED_BY(mutex_capture_) = 0;
+ std::vector<int16_t> agc_render_queue_buffer_ RTC_GUARDED_BY(mutex_render_);
+ std::vector<int16_t> agc_capture_queue_buffer_ RTC_GUARDED_BY(mutex_capture_);
+
+ size_t red_render_queue_element_max_size_ RTC_GUARDED_BY(mutex_render_)
+ RTC_GUARDED_BY(mutex_capture_) = 0;
+ std::vector<float> red_render_queue_buffer_ RTC_GUARDED_BY(mutex_render_);
+ std::vector<float> red_capture_queue_buffer_ RTC_GUARDED_BY(mutex_capture_);
+
+ RmsLevel capture_input_rms_ RTC_GUARDED_BY(mutex_capture_);
+ RmsLevel capture_output_rms_ RTC_GUARDED_BY(mutex_capture_);
+ int capture_rms_interval_counter_ RTC_GUARDED_BY(mutex_capture_) = 0;
+
+ // Lock protection not needed.
+ std::unique_ptr<
+ SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>>
+ aecm_render_signal_queue_;
+ std::unique_ptr<
+ SwapQueue<std::vector<int16_t>, RenderQueueItemVerifier<int16_t>>>
+ agc_render_signal_queue_;
+ std::unique_ptr<SwapQueue<std::vector<float>, RenderQueueItemVerifier<float>>>
+ red_render_signal_queue_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
+#endif // MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
diff --git a/webrtc/modules/audio_processing/beamformer/array_util.cc b/webrtc/modules/audio_processing/beamformer/array_util.cc
deleted file mode 100644
index d97beea..0000000
--- a/webrtc/modules/audio_processing/beamformer/array_util.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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 "webrtc/modules/audio_processing/beamformer/array_util.h"
-
-#include <algorithm>
-#include <limits>
-
-#include "webrtc/base/checks.h"
-
-namespace webrtc {
-namespace {
-
-const float kMaxDotProduct = 1e-6f;
-
-} // namespace
-
-float GetMinimumSpacing(const std::vector<Point>& array_geometry) {
- RTC_CHECK_GT(array_geometry.size(), 1u);
- float mic_spacing = std::numeric_limits<float>::max();
- for (size_t i = 0; i < (array_geometry.size() - 1); ++i) {
- for (size_t j = i + 1; j < array_geometry.size(); ++j) {
- mic_spacing =
- std::min(mic_spacing, Distance(array_geometry[i], array_geometry[j]));
- }
- }
- return mic_spacing;
-}
-
-Point PairDirection(const Point& a, const Point& b) {
- return {b.x() - a.x(), b.y() - a.y(), b.z() - a.z()};
-}
-
-float DotProduct(const Point& a, const Point& b) {
- return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
-}
-
-Point CrossProduct(const Point& a, const Point& b) {
- return {a.y() * b.z() - a.z() * b.y(), a.z() * b.x() - a.x() * b.z(),
- a.x() * b.y() - a.y() * b.x()};
-}
-
-bool AreParallel(const Point& a, const Point& b) {
- Point cross_product = CrossProduct(a, b);
- return DotProduct(cross_product, cross_product) < kMaxDotProduct;
-}
-
-bool ArePerpendicular(const Point& a, const Point& b) {
- return std::abs(DotProduct(a, b)) < kMaxDotProduct;
-}
-
-rtc::Maybe<Point> GetDirectionIfLinear(
- const std::vector<Point>& array_geometry) {
- RTC_DCHECK_GT(array_geometry.size(), 1u);
- const Point first_pair_direction =
- PairDirection(array_geometry[0], array_geometry[1]);
- for (size_t i = 2u; i < array_geometry.size(); ++i) {
- const Point pair_direction =
- PairDirection(array_geometry[i - 1], array_geometry[i]);
- if (!AreParallel(first_pair_direction, pair_direction)) {
- return rtc::Maybe<Point>();
- }
- }
- return rtc::Maybe<Point>(first_pair_direction);
-}
-
-rtc::Maybe<Point> GetNormalIfPlanar(const std::vector<Point>& array_geometry) {
- RTC_DCHECK_GT(array_geometry.size(), 1u);
- const Point first_pair_direction =
- PairDirection(array_geometry[0], array_geometry[1]);
- Point pair_direction(0.f, 0.f, 0.f);
- size_t i = 2u;
- bool is_linear = true;
- for (; i < array_geometry.size() && is_linear; ++i) {
- pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]);
- if (!AreParallel(first_pair_direction, pair_direction)) {
- is_linear = false;
- }
- }
- if (is_linear) {
- return rtc::Maybe<Point>();
- }
- const Point normal_direction =
- CrossProduct(first_pair_direction, pair_direction);
- for (; i < array_geometry.size(); ++i) {
- pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]);
- if (!ArePerpendicular(normal_direction, pair_direction)) {
- return rtc::Maybe<Point>();
- }
- }
- return rtc::Maybe<Point>(normal_direction);
-}
-
-rtc::Maybe<Point> GetArrayNormalIfExists(
- const std::vector<Point>& array_geometry) {
- const rtc::Maybe<Point> direction = GetDirectionIfLinear(array_geometry);
- if (direction) {
- return rtc::Maybe<Point>(Point(direction->y(), -direction->x(), 0.f));
- }
- const rtc::Maybe<Point> normal = GetNormalIfPlanar(array_geometry);
- if (normal && normal->z() < kMaxDotProduct) {
- return normal;
- }
- return rtc::Maybe<Point>();
-}
-
-Point AzimuthToPoint(float azimuth) {
- return Point(std::cos(azimuth), std::sin(azimuth), 0.f);
-}
-
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/beamformer/array_util.h b/webrtc/modules/audio_processing/beamformer/array_util.h
deleted file mode 100644
index 7fff973..0000000
--- a/webrtc/modules/audio_processing/beamformer/array_util.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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 WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
-
-#include <cmath>
-#include <vector>
-
-#include "webrtc/base/maybe.h"
-
-namespace webrtc {
-
-// Coordinates in meters. The convention used is:
-// x: the horizontal dimension, with positive to the right from the camera's
-// perspective.
-// y: the depth dimension, with positive forward from the camera's
-// perspective.
-// z: the vertical dimension, with positive upwards.
-template<typename T>
-struct CartesianPoint {
- CartesianPoint() {
- c[0] = 0;
- c[1] = 0;
- c[2] = 0;
- }
- CartesianPoint(T x, T y, T z) {
- c[0] = x;
- c[1] = y;
- c[2] = z;
- }
- T x() const { return c[0]; }
- T y() const { return c[1]; }
- T z() const { return c[2]; }
- T c[3];
-};
-
-using Point = CartesianPoint<float>;
-
-// Calculates the direction from a to b.
-Point PairDirection(const Point& a, const Point& b);
-
-float DotProduct(const Point& a, const Point& b);
-Point CrossProduct(const Point& a, const Point& b);
-
-bool AreParallel(const Point& a, const Point& b);
-bool ArePerpendicular(const Point& a, const Point& b);
-
-// Returns the minimum distance between any two Points in the given
-// |array_geometry|.
-float GetMinimumSpacing(const std::vector<Point>& array_geometry);
-
-// If the given array geometry is linear it returns the direction without
-// normalizing.
-rtc::Maybe<Point> GetDirectionIfLinear(
- const std::vector<Point>& array_geometry);
-
-// If the given array geometry is planar it returns the normal without
-// normalizing.
-rtc::Maybe<Point> GetNormalIfPlanar(const std::vector<Point>& array_geometry);
-
-// Returns the normal of an array if it has one and it is in the xy-plane.
-rtc::Maybe<Point> GetArrayNormalIfExists(
- const std::vector<Point>& array_geometry);
-
-// The resulting Point will be in the xy-plane.
-Point AzimuthToPoint(float azimuth);
-
-template<typename T>
-float Distance(CartesianPoint<T> a, CartesianPoint<T> b) {
- return std::sqrt((a.x() - b.x()) * (a.x() - b.x()) +
- (a.y() - b.y()) * (a.y() - b.y()) +
- (a.z() - b.z()) * (a.z() - b.z()));
-}
-
-// The convention used:
-// azimuth: zero is to the right from the camera's perspective, with positive
-// angles in radians counter-clockwise.
-// elevation: zero is horizontal, with positive angles in radians upwards.
-// radius: distance from the camera in meters.
-template <typename T>
-struct SphericalPoint {
- SphericalPoint(T azimuth, T elevation, T radius) {
- s[0] = azimuth;
- s[1] = elevation;
- s[2] = radius;
- }
- T azimuth() const { return s[0]; }
- T elevation() const { return s[1]; }
- T distance() const { return s[2]; }
- T s[3];
-};
-
-using SphericalPointf = SphericalPoint<float>;
-
-// Helper functions to transform degrees to radians and the inverse.
-template <typename T>
-T DegreesToRadians(T angle_degrees) {
- return M_PI * angle_degrees / 180;
-}
-
-template <typename T>
-T RadiansToDegrees(T angle_radians) {
- return 180 * angle_radians / M_PI;
-}
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
diff --git a/webrtc/modules/audio_processing/beamformer/beamformer.h b/webrtc/modules/audio_processing/beamformer/beamformer.h
deleted file mode 100644
index 6a9ff45..0000000
--- a/webrtc/modules/audio_processing/beamformer/beamformer.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_BEAMFORMER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_BEAMFORMER_H_
-
-#include "webrtc/common_audio/channel_buffer.h"
-#include "webrtc/modules/audio_processing/beamformer/array_util.h"
-
-namespace webrtc {
-
-template<typename T>
-class Beamformer {
- public:
- virtual ~Beamformer() {}
-
- // Process one time-domain chunk of audio. The audio is expected to be split
- // into frequency bands inside the ChannelBuffer. The number of frames and
- // channels must correspond to the constructor parameters. The same
- // ChannelBuffer can be passed in as |input| and |output|.
- virtual void ProcessChunk(const ChannelBuffer<T>& input,
- ChannelBuffer<T>* output) = 0;
-
- // Sample rate corresponds to the lower band.
- // Needs to be called before the the Beamformer can be used.
- virtual void Initialize(int chunk_size_ms, int sample_rate_hz) = 0;
-
- // Aim the beamformer at a point in space.
- virtual void AimAt(const SphericalPointf& spherical_point) = 0;
-
- // Indicates whether a given point is inside of the beam.
- virtual bool IsInBeam(const SphericalPointf& spherical_point) { return true; }
-
- // Returns true if the current data contains the target signal.
- // Which signals are considered "targets" is implementation dependent.
- virtual bool is_target_present() = 0;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_BEAMFORMER_H_
diff --git a/webrtc/modules/audio_processing/beamformer/complex_matrix.h b/webrtc/modules/audio_processing/beamformer/complex_matrix.h
deleted file mode 100644
index bfa3563..0000000
--- a/webrtc/modules/audio_processing/beamformer/complex_matrix.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
-
-#include <complex>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/beamformer/matrix.h"
-
-namespace webrtc {
-
-using std::complex;
-
-// An extension of Matrix for operations that only work on a complex type.
-template <typename T>
-class ComplexMatrix : public Matrix<complex<T> > {
- public:
- ComplexMatrix() : Matrix<complex<T> >() {}
-
- ComplexMatrix(int num_rows, int num_columns)
- : Matrix<complex<T> >(num_rows, num_columns) {}
-
- ComplexMatrix(const complex<T>* data, int num_rows, int num_columns)
- : Matrix<complex<T> >(data, num_rows, num_columns) {}
-
- // Complex Matrix operations.
- ComplexMatrix& PointwiseConjugate() {
- complex<T>* const data = this->data();
- size_t size = this->num_rows() * this->num_columns();
- for (size_t i = 0; i < size; ++i) {
- data[i] = conj(data[i]);
- }
-
- return *this;
- }
-
- ComplexMatrix& PointwiseConjugate(const ComplexMatrix& operand) {
- this->CopyFrom(operand);
- return PointwiseConjugate();
- }
-
- ComplexMatrix& ConjugateTranspose() {
- this->CopyDataToScratch();
- int num_rows = this->num_rows();
- this->SetNumRows(this->num_columns());
- this->SetNumColumns(num_rows);
- this->Resize();
- return ConjugateTranspose(this->scratch_elements());
- }
-
- ComplexMatrix& ConjugateTranspose(const ComplexMatrix& operand) {
- RTC_CHECK_EQ(operand.num_rows(), this->num_columns());
- RTC_CHECK_EQ(operand.num_columns(), this->num_rows());
- return ConjugateTranspose(operand.elements());
- }
-
- ComplexMatrix& ZeroImag() {
- complex<T>* const data = this->data();
- size_t size = this->num_rows() * this->num_columns();
- for (size_t i = 0; i < size; ++i) {
- data[i] = complex<T>(data[i].real(), 0);
- }
-
- return *this;
- }
-
- ComplexMatrix& ZeroImag(const ComplexMatrix& operand) {
- this->CopyFrom(operand);
- return ZeroImag();
- }
-
- private:
- ComplexMatrix& ConjugateTranspose(const complex<T>* const* src) {
- complex<T>* const* elements = this->elements();
- for (int i = 0; i < this->num_rows(); ++i) {
- for (int j = 0; j < this->num_columns(); ++j) {
- elements[i][j] = conj(src[j][i]);
- }
- }
-
- return *this;
- }
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
diff --git a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.cc b/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.cc
deleted file mode 100644
index d072832..0000000
--- a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#define _USE_MATH_DEFINES
-
-#include "webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h"
-
-#include <cmath>
-
-namespace webrtc {
-namespace {
-
-float BesselJ0(float x) {
-#if WEBRTC_WIN
- return _j0(x);
-#else
- return j0(x);
-#endif
-}
-
-// Calculates the Euclidean norm for a row vector.
-float Norm(const ComplexMatrix<float>& x) {
- RTC_CHECK_EQ(1, x.num_rows());
- const size_t length = x.num_columns();
- const complex<float>* elems = x.elements()[0];
- float result = 0.f;
- for (size_t i = 0u; i < length; ++i) {
- result += std::norm(elems[i]);
- }
- return std::sqrt(result);
-}
-
-} // namespace
-
-void CovarianceMatrixGenerator::UniformCovarianceMatrix(
- float wave_number,
- const std::vector<Point>& geometry,
- ComplexMatrix<float>* mat) {
- RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_rows());
- RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
-
- complex<float>* const* mat_els = mat->elements();
- for (size_t i = 0; i < geometry.size(); ++i) {
- for (size_t j = 0; j < geometry.size(); ++j) {
- if (wave_number > 0.f) {
- mat_els[i][j] =
- BesselJ0(wave_number * Distance(geometry[i], geometry[j]));
- } else {
- mat_els[i][j] = i == j ? 1.f : 0.f;
- }
- }
- }
-}
-
-void CovarianceMatrixGenerator::AngledCovarianceMatrix(
- float sound_speed,
- float angle,
- size_t frequency_bin,
- size_t fft_size,
- size_t num_freq_bins,
- int sample_rate,
- const std::vector<Point>& geometry,
- ComplexMatrix<float>* mat) {
- RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_rows());
- RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
-
- ComplexMatrix<float> interf_cov_vector(1, geometry.size());
- ComplexMatrix<float> interf_cov_vector_transposed(geometry.size(), 1);
- PhaseAlignmentMasks(frequency_bin,
- fft_size,
- sample_rate,
- sound_speed,
- geometry,
- angle,
- &interf_cov_vector);
- interf_cov_vector.Scale(1.f / Norm(interf_cov_vector));
- interf_cov_vector_transposed.Transpose(interf_cov_vector);
- interf_cov_vector.PointwiseConjugate();
- mat->Multiply(interf_cov_vector_transposed, interf_cov_vector);
-}
-
-void CovarianceMatrixGenerator::PhaseAlignmentMasks(
- size_t frequency_bin,
- size_t fft_size,
- int sample_rate,
- float sound_speed,
- const std::vector<Point>& geometry,
- float angle,
- ComplexMatrix<float>* mat) {
- RTC_CHECK_EQ(1, mat->num_rows());
- RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
-
- float freq_in_hertz =
- (static_cast<float>(frequency_bin) / fft_size) * sample_rate;
-
- complex<float>* const* mat_els = mat->elements();
- for (size_t c_ix = 0; c_ix < geometry.size(); ++c_ix) {
- float distance = std::cos(angle) * geometry[c_ix].x() +
- std::sin(angle) * geometry[c_ix].y();
- float phase_shift = -2.f * M_PI * distance * freq_in_hertz / sound_speed;
-
- // Euler's formula for mat[0][c_ix] = e^(j * phase_shift).
- mat_els[0][c_ix] = complex<float>(cos(phase_shift), sin(phase_shift));
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h b/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h
deleted file mode 100644
index 5375518..0000000
--- a/webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COVARIANCE_MATRIX_GENERATOR_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COVARIANCE_MATRIX_GENERATOR_H_
-
-#include "webrtc/modules/audio_processing/beamformer/complex_matrix.h"
-#include "webrtc/modules/audio_processing/beamformer/array_util.h"
-
-namespace webrtc {
-
-// Helper class for Beamformer in charge of generating covariance matrices. For
-// each function, the passed-in ComplexMatrix is expected to be of size
-// |num_input_channels| x |num_input_channels|.
-class CovarianceMatrixGenerator {
- public:
- // A uniform covariance matrix with a gap at the target location. WARNING:
- // The target angle is assumed to be 0.
- static void UniformCovarianceMatrix(float wave_number,
- const std::vector<Point>& geometry,
- ComplexMatrix<float>* mat);
-
- // The covariance matrix of a source at the given angle.
- static void AngledCovarianceMatrix(float sound_speed,
- float angle,
- size_t frequency_bin,
- size_t fft_size,
- size_t num_freq_bins,
- int sample_rate,
- const std::vector<Point>& geometry,
- ComplexMatrix<float>* mat);
-
- // Calculates phase shifts that, when applied to a multichannel signal and
- // added together, cause constructive interferernce for sources located at
- // the given angle.
- static void PhaseAlignmentMasks(size_t frequency_bin,
- size_t fft_size,
- int sample_rate,
- float sound_speed,
- const std::vector<Point>& geometry,
- float angle,
- ComplexMatrix<float>* mat);
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_BF_HELPERS_H_
diff --git a/webrtc/modules/audio_processing/beamformer/matrix.h b/webrtc/modules/audio_processing/beamformer/matrix.h
deleted file mode 100644
index 162aef1..0000000
--- a/webrtc/modules/audio_processing/beamformer/matrix.h
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
-
-#include <algorithm>
-#include <cstring>
-#include <string>
-#include <vector>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/base/scoped_ptr.h"
-
-namespace {
-
-// Wrappers to get around the compiler warning resulting from the fact that
-// there's no std::sqrt overload for ints. We cast all non-complex types to
-// a double for the sqrt method.
-template <typename T>
-T sqrt_wrapper(T x) {
- return sqrt(static_cast<double>(x));
-}
-
-template <typename S>
-std::complex<S> sqrt_wrapper(std::complex<S> x) {
- return sqrt(x);
-}
-} // namespace
-
-namespace webrtc {
-
-// Matrix is a class for doing standard matrix operations on 2 dimensional
-// matrices of any size. Results of matrix operations are stored in the
-// calling object. Function overloads exist for both in-place (the calling
-// object is used as both an operand and the result) and out-of-place (all
-// operands are passed in as parameters) operations. If operand dimensions
-// mismatch, the program crashes. Out-of-place operations change the size of
-// the calling object, if necessary, before operating.
-//
-// 'In-place' operations that inherently change the size of the matrix (eg.
-// Transpose, Multiply on different-sized matrices) must make temporary copies
-// (|scratch_elements_| and |scratch_data_|) of existing data to complete the
-// operations.
-//
-// The data is stored contiguously. Data can be accessed internally as a flat
-// array, |data_|, or as an array of row pointers, |elements_|, but is
-// available to users only as an array of row pointers through |elements()|.
-// Memory for storage is allocated when a matrix is resized only if the new
-// size overflows capacity. Memory needed temporarily for any operations is
-// similarly resized only if the new size overflows capacity.
-//
-// If you pass in storage through the ctor, that storage is copied into the
-// matrix. TODO(claguna): albeit tricky, allow for data to be referenced
-// instead of copied, and owned by the user.
-template <typename T>
-class Matrix {
- public:
- Matrix() : num_rows_(0), num_columns_(0) {}
-
- // Allocates space for the elements and initializes all values to zero.
- Matrix(int num_rows, int num_columns)
- : num_rows_(num_rows), num_columns_(num_columns) {
- Resize();
- scratch_data_.resize(num_rows_ * num_columns_);
- scratch_elements_.resize(num_rows_);
- }
-
- // Copies |data| into the new Matrix.
- Matrix(const T* data, int num_rows, int num_columns)
- : num_rows_(0), num_columns_(0) {
- CopyFrom(data, num_rows, num_columns);
- scratch_data_.resize(num_rows_ * num_columns_);
- scratch_elements_.resize(num_rows_);
- }
-
- virtual ~Matrix() {}
-
- // Deep copy an existing matrix.
- void CopyFrom(const Matrix& other) {
- CopyFrom(&other.data_[0], other.num_rows_, other.num_columns_);
- }
-
- // Copy |data| into the Matrix. The current data is lost.
- void CopyFrom(const T* const data, int num_rows, int num_columns) {
- Resize(num_rows, num_columns);
- memcpy(&data_[0], data, num_rows_ * num_columns_ * sizeof(data_[0]));
- }
-
- Matrix& CopyFromColumn(const T* const* src,
- size_t column_index,
- int num_rows) {
- Resize(1, num_rows);
- for (int i = 0; i < num_columns_; ++i) {
- data_[i] = src[i][column_index];
- }
-
- return *this;
- }
-
- void Resize(int num_rows, int num_columns) {
- if (num_rows != num_rows_ || num_columns != num_columns_) {
- num_rows_ = num_rows;
- num_columns_ = num_columns;
- Resize();
- }
- }
-
- // Accessors and mutators.
- int num_rows() const { return num_rows_; }
- int num_columns() const { return num_columns_; }
- T* const* elements() { return &elements_[0]; }
- const T* const* elements() const { return &elements_[0]; }
-
- T Trace() {
- RTC_CHECK_EQ(num_rows_, num_columns_);
-
- T trace = 0;
- for (int i = 0; i < num_rows_; ++i) {
- trace += elements_[i][i];
- }
- return trace;
- }
-
- // Matrix Operations. Returns *this to support method chaining.
- Matrix& Transpose() {
- CopyDataToScratch();
- Resize(num_columns_, num_rows_);
- return Transpose(scratch_elements());
- }
-
- Matrix& Transpose(const Matrix& operand) {
- RTC_CHECK_EQ(operand.num_rows_, num_columns_);
- RTC_CHECK_EQ(operand.num_columns_, num_rows_);
-
- return Transpose(operand.elements());
- }
-
- template <typename S>
- Matrix& Scale(const S& scalar) {
- for (size_t i = 0; i < data_.size(); ++i) {
- data_[i] *= scalar;
- }
-
- return *this;
- }
-
- template <typename S>
- Matrix& Scale(const Matrix& operand, const S& scalar) {
- CopyFrom(operand);
- return Scale(scalar);
- }
-
- Matrix& Add(const Matrix& operand) {
- RTC_CHECK_EQ(num_rows_, operand.num_rows_);
- RTC_CHECK_EQ(num_columns_, operand.num_columns_);
-
- for (size_t i = 0; i < data_.size(); ++i) {
- data_[i] += operand.data_[i];
- }
-
- return *this;
- }
-
- Matrix& Add(const Matrix& lhs, const Matrix& rhs) {
- CopyFrom(lhs);
- return Add(rhs);
- }
-
- Matrix& Subtract(const Matrix& operand) {
- RTC_CHECK_EQ(num_rows_, operand.num_rows_);
- RTC_CHECK_EQ(num_columns_, operand.num_columns_);
-
- for (size_t i = 0; i < data_.size(); ++i) {
- data_[i] -= operand.data_[i];
- }
-
- return *this;
- }
-
- Matrix& Subtract(const Matrix& lhs, const Matrix& rhs) {
- CopyFrom(lhs);
- return Subtract(rhs);
- }
-
- Matrix& PointwiseMultiply(const Matrix& operand) {
- RTC_CHECK_EQ(num_rows_, operand.num_rows_);
- RTC_CHECK_EQ(num_columns_, operand.num_columns_);
-
- for (size_t i = 0; i < data_.size(); ++i) {
- data_[i] *= operand.data_[i];
- }
-
- return *this;
- }
-
- Matrix& PointwiseMultiply(const Matrix& lhs, const Matrix& rhs) {
- CopyFrom(lhs);
- return PointwiseMultiply(rhs);
- }
-
- Matrix& PointwiseDivide(const Matrix& operand) {
- RTC_CHECK_EQ(num_rows_, operand.num_rows_);
- RTC_CHECK_EQ(num_columns_, operand.num_columns_);
-
- for (size_t i = 0; i < data_.size(); ++i) {
- data_[i] /= operand.data_[i];
- }
-
- return *this;
- }
-
- Matrix& PointwiseDivide(const Matrix& lhs, const Matrix& rhs) {
- CopyFrom(lhs);
- return PointwiseDivide(rhs);
- }
-
- Matrix& PointwiseSquareRoot() {
- for (size_t i = 0; i < data_.size(); ++i) {
- data_[i] = sqrt_wrapper(data_[i]);
- }
-
- return *this;
- }
-
- Matrix& PointwiseSquareRoot(const Matrix& operand) {
- CopyFrom(operand);
- return PointwiseSquareRoot();
- }
-
- Matrix& PointwiseAbsoluteValue() {
- for (size_t i = 0; i < data_.size(); ++i) {
- data_[i] = abs(data_[i]);
- }
-
- return *this;
- }
-
- Matrix& PointwiseAbsoluteValue(const Matrix& operand) {
- CopyFrom(operand);
- return PointwiseAbsoluteValue();
- }
-
- Matrix& PointwiseSquare() {
- for (size_t i = 0; i < data_.size(); ++i) {
- data_[i] *= data_[i];
- }
-
- return *this;
- }
-
- Matrix& PointwiseSquare(const Matrix& operand) {
- CopyFrom(operand);
- return PointwiseSquare();
- }
-
- Matrix& Multiply(const Matrix& lhs, const Matrix& rhs) {
- RTC_CHECK_EQ(lhs.num_columns_, rhs.num_rows_);
- RTC_CHECK_EQ(num_rows_, lhs.num_rows_);
- RTC_CHECK_EQ(num_columns_, rhs.num_columns_);
-
- return Multiply(lhs.elements(), rhs.num_rows_, rhs.elements());
- }
-
- Matrix& Multiply(const Matrix& rhs) {
- RTC_CHECK_EQ(num_columns_, rhs.num_rows_);
-
- CopyDataToScratch();
- Resize(num_rows_, rhs.num_columns_);
- return Multiply(scratch_elements(), rhs.num_rows_, rhs.elements());
- }
-
- std::string ToString() const {
- std::ostringstream ss;
- ss << std::endl << "Matrix" << std::endl;
-
- for (int i = 0; i < num_rows_; ++i) {
- for (int j = 0; j < num_columns_; ++j) {
- ss << elements_[i][j] << " ";
- }
- ss << std::endl;
- }
- ss << std::endl;
-
- return ss.str();
- }
-
- protected:
- void SetNumRows(const int num_rows) { num_rows_ = num_rows; }
- void SetNumColumns(const int num_columns) { num_columns_ = num_columns; }
- T* data() { return &data_[0]; }
- const T* data() const { return &data_[0]; }
- const T* const* scratch_elements() const { return &scratch_elements_[0]; }
-
- // Resize the matrix. If an increase in capacity is required, the current
- // data is lost.
- void Resize() {
- size_t size = num_rows_ * num_columns_;
- data_.resize(size);
- elements_.resize(num_rows_);
-
- for (int i = 0; i < num_rows_; ++i) {
- elements_[i] = &data_[i * num_columns_];
- }
- }
-
- // Copies data_ into scratch_data_ and updates scratch_elements_ accordingly.
- void CopyDataToScratch() {
- scratch_data_ = data_;
- scratch_elements_.resize(num_rows_);
-
- for (int i = 0; i < num_rows_; ++i) {
- scratch_elements_[i] = &scratch_data_[i * num_columns_];
- }
- }
-
- private:
- int num_rows_;
- int num_columns_;
- std::vector<T> data_;
- std::vector<T*> elements_;
-
- // Stores temporary copies of |data_| and |elements_| for in-place operations
- // where referring to original data is necessary.
- std::vector<T> scratch_data_;
- std::vector<T*> scratch_elements_;
-
- // Helpers for Transpose and Multiply operations that unify in-place and
- // out-of-place solutions.
- Matrix& Transpose(const T* const* src) {
- for (int i = 0; i < num_rows_; ++i) {
- for (int j = 0; j < num_columns_; ++j) {
- elements_[i][j] = src[j][i];
- }
- }
-
- return *this;
- }
-
- Matrix& Multiply(const T* const* lhs, int num_rows_rhs, const T* const* rhs) {
- for (int row = 0; row < num_rows_; ++row) {
- for (int col = 0; col < num_columns_; ++col) {
- T cur_element = 0;
- for (int i = 0; i < num_rows_rhs; ++i) {
- cur_element += lhs[row][i] * rhs[i][col];
- }
-
- elements_[row][col] = cur_element;
- }
- }
-
- return *this;
- }
-
- RTC_DISALLOW_COPY_AND_ASSIGN(Matrix);
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
diff --git a/webrtc/modules/audio_processing/beamformer/matrix_test_helpers.h b/webrtc/modules/audio_processing/beamformer/matrix_test_helpers.h
deleted file mode 100644
index 7c58670..0000000
--- a/webrtc/modules/audio_processing/beamformer/matrix_test_helpers.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/modules/audio_processing/beamformer/complex_matrix.h"
-#include "webrtc/modules/audio_processing/beamformer/matrix.h"
-
-namespace {
-const float kTolerance = 0.001f;
-}
-
-namespace webrtc {
-
-using std::complex;
-
-// Functions used in both matrix_unittest and complex_matrix_unittest.
-class MatrixTestHelpers {
- public:
- template <typename T>
- static void ValidateMatrixEquality(const Matrix<T>& expected,
- const Matrix<T>& actual) {
- EXPECT_EQ(expected.num_rows(), actual.num_rows());
- EXPECT_EQ(expected.num_columns(), actual.num_columns());
-
- const T* const* expected_elements = expected.elements();
- const T* const* actual_elements = actual.elements();
- for (int i = 0; i < expected.num_rows(); ++i) {
- for (int j = 0; j < expected.num_columns(); ++j) {
- EXPECT_EQ(expected_elements[i][j], actual_elements[i][j]);
- }
- }
- }
-
- static void ValidateMatrixEqualityFloat(const Matrix<float>& expected,
- const Matrix<float>& actual) {
- EXPECT_EQ(expected.num_rows(), actual.num_rows());
- EXPECT_EQ(expected.num_columns(), actual.num_columns());
-
- const float* const* expected_elements = expected.elements();
- const float* const* actual_elements = actual.elements();
- for (int i = 0; i < expected.num_rows(); ++i) {
- for (int j = 0; j < expected.num_columns(); ++j) {
- EXPECT_NEAR(expected_elements[i][j], actual_elements[i][j], kTolerance);
- }
- }
- }
-
- static void ValidateMatrixEqualityComplexFloat(
- const Matrix<complex<float> >& expected,
- const Matrix<complex<float> >& actual) {
- EXPECT_EQ(expected.num_rows(), actual.num_rows());
- EXPECT_EQ(expected.num_columns(), actual.num_columns());
-
- const complex<float>* const* expected_elements = expected.elements();
- const complex<float>* const* actual_elements = actual.elements();
- for (int i = 0; i < expected.num_rows(); ++i) {
- for (int j = 0; j < expected.num_columns(); ++j) {
- EXPECT_NEAR(expected_elements[i][j].real(),
- actual_elements[i][j].real(),
- kTolerance);
- EXPECT_NEAR(expected_elements[i][j].imag(),
- actual_elements[i][j].imag(),
- kTolerance);
- }
- }
- }
-
- static void ValidateMatrixNearEqualityComplexFloat(
- const Matrix<complex<float> >& expected,
- const Matrix<complex<float> >& actual,
- float tolerance) {
- EXPECT_EQ(expected.num_rows(), actual.num_rows());
- EXPECT_EQ(expected.num_columns(), actual.num_columns());
-
- const complex<float>* const* expected_elements = expected.elements();
- const complex<float>* const* actual_elements = actual.elements();
- for (int i = 0; i < expected.num_rows(); ++i) {
- for (int j = 0; j < expected.num_columns(); ++j) {
- EXPECT_NEAR(expected_elements[i][j].real(),
- actual_elements[i][j].real(),
- tolerance);
- EXPECT_NEAR(expected_elements[i][j].imag(),
- actual_elements[i][j].imag(),
- tolerance);
- }
- }
- }
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
diff --git a/webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.cc b/webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.cc
deleted file mode 100644
index 029fa08..0000000
--- a/webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.cc
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#define _USE_MATH_DEFINES
-
-#include "webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h"
-
-#include <algorithm>
-#include <cmath>
-#include <numeric>
-#include <vector>
-
-#include "webrtc/base/arraysize.h"
-#include "webrtc/common_audio/window_generator.h"
-#include "webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h"
-
-namespace webrtc {
-namespace {
-
-// Alpha for the Kaiser Bessel Derived window.
-const float kKbdAlpha = 1.5f;
-
-const float kSpeedOfSoundMeterSeconds = 343;
-
-// The minimum separation in radians between the target direction and an
-// interferer scenario.
-const float kMinAwayRadians = 0.2f;
-
-// The separation between the target direction and the closest interferer
-// scenario is proportional to this constant.
-const float kAwaySlope = 0.008f;
-
-// When calculating the interference covariance matrix, this is the weight for
-// the weighted average between the uniform covariance matrix and the angled
-// covariance matrix.
-// Rpsi = Rpsi_angled * kBalance + Rpsi_uniform * (1 - kBalance)
-const float kBalance = 0.95f;
-
-// Alpha coefficients for mask smoothing.
-const float kMaskTimeSmoothAlpha = 0.2f;
-const float kMaskFrequencySmoothAlpha = 0.6f;
-
-// The average mask is computed from masks in this mid-frequency range. If these
-// ranges are changed |kMaskQuantile| might need to be adjusted.
-const int kLowMeanStartHz = 200;
-const int kLowMeanEndHz = 400;
-
-// Range limiter for subtractive terms in the nominator and denominator of the
-// postfilter expression. It handles the scenario mismatch between the true and
-// model sources (target and interference).
-const float kCutOffConstant = 0.9999f;
-
-// Quantile of mask values which is used to estimate target presence.
-const float kMaskQuantile = 0.7f;
-// Mask threshold over which the data is considered signal and not interference.
-// It has to be updated every time the postfilter calculation is changed
-// significantly.
-// TODO(aluebs): Write a tool to tune the target threshold automatically based
-// on files annotated with target and interference ground truth.
-const float kMaskTargetThreshold = 0.01f;
-// Time in seconds after which the data is considered interference if the mask
-// does not pass |kMaskTargetThreshold|.
-const float kHoldTargetSeconds = 0.25f;
-
-// To compensate for the attenuation this algorithm introduces to the target
-// signal. It was estimated empirically from a low-noise low-reverberation
-// recording from broadside.
-const float kCompensationGain = 2.f;
-
-// Does conjugate(|norm_mat|) * |mat| * transpose(|norm_mat|). No extra space is
-// used; to accomplish this, we compute both multiplications in the same loop.
-// The returned norm is clamped to be non-negative.
-float Norm(const ComplexMatrix<float>& mat,
- const ComplexMatrix<float>& norm_mat) {
- RTC_CHECK_EQ(norm_mat.num_rows(), 1);
- RTC_CHECK_EQ(norm_mat.num_columns(), mat.num_rows());
- RTC_CHECK_EQ(norm_mat.num_columns(), mat.num_columns());
-
- complex<float> first_product = complex<float>(0.f, 0.f);
- complex<float> second_product = complex<float>(0.f, 0.f);
-
- const complex<float>* const* mat_els = mat.elements();
- const complex<float>* const* norm_mat_els = norm_mat.elements();
-
- for (int i = 0; i < norm_mat.num_columns(); ++i) {
- for (int j = 0; j < norm_mat.num_columns(); ++j) {
- first_product += conj(norm_mat_els[0][j]) * mat_els[j][i];
- }
- second_product += first_product * norm_mat_els[0][i];
- first_product = 0.f;
- }
- return std::max(second_product.real(), 0.f);
-}
-
-// Does conjugate(|lhs|) * |rhs| for row vectors |lhs| and |rhs|.
-complex<float> ConjugateDotProduct(const ComplexMatrix<float>& lhs,
- const ComplexMatrix<float>& rhs) {
- RTC_CHECK_EQ(lhs.num_rows(), 1);
- RTC_CHECK_EQ(rhs.num_rows(), 1);
- RTC_CHECK_EQ(lhs.num_columns(), rhs.num_columns());
-
- const complex<float>* const* lhs_elements = lhs.elements();
- const complex<float>* const* rhs_elements = rhs.elements();
-
- complex<float> result = complex<float>(0.f, 0.f);
- for (int i = 0; i < lhs.num_columns(); ++i) {
- result += conj(lhs_elements[0][i]) * rhs_elements[0][i];
- }
-
- return result;
-}
-
-// Works for positive numbers only.
-size_t Round(float x) {
- return static_cast<size_t>(std::floor(x + 0.5f));
-}
-
-// Calculates the sum of absolute values of a complex matrix.
-float SumAbs(const ComplexMatrix<float>& mat) {
- float sum_abs = 0.f;
- const complex<float>* const* mat_els = mat.elements();
- for (int i = 0; i < mat.num_rows(); ++i) {
- for (int j = 0; j < mat.num_columns(); ++j) {
- sum_abs += std::abs(mat_els[i][j]);
- }
- }
- return sum_abs;
-}
-
-// Calculates the sum of squares of a complex matrix.
-float SumSquares(const ComplexMatrix<float>& mat) {
- float sum_squares = 0.f;
- const complex<float>* const* mat_els = mat.elements();
- for (int i = 0; i < mat.num_rows(); ++i) {
- for (int j = 0; j < mat.num_columns(); ++j) {
- float abs_value = std::abs(mat_els[i][j]);
- sum_squares += abs_value * abs_value;
- }
- }
- return sum_squares;
-}
-
-// Does |out| = |in|.' * conj(|in|) for row vector |in|.
-void TransposedConjugatedProduct(const ComplexMatrix<float>& in,
- ComplexMatrix<float>* out) {
- RTC_CHECK_EQ(in.num_rows(), 1);
- RTC_CHECK_EQ(out->num_rows(), in.num_columns());
- RTC_CHECK_EQ(out->num_columns(), in.num_columns());
- const complex<float>* in_elements = in.elements()[0];
- complex<float>* const* out_elements = out->elements();
- for (int i = 0; i < out->num_rows(); ++i) {
- for (int j = 0; j < out->num_columns(); ++j) {
- out_elements[i][j] = in_elements[i] * conj(in_elements[j]);
- }
- }
-}
-
-std::vector<Point> GetCenteredArray(std::vector<Point> array_geometry) {
- for (int dim = 0; dim < 3; ++dim) {
- float center = 0.f;
- for (size_t i = 0; i < array_geometry.size(); ++i) {
- center += array_geometry[i].c[dim];
- }
- center /= array_geometry.size();
- for (size_t i = 0; i < array_geometry.size(); ++i) {
- array_geometry[i].c[dim] -= center;
- }
- }
- return array_geometry;
-}
-
-} // namespace
-
-const float NonlinearBeamformer::kHalfBeamWidthRadians = DegreesToRadians(20.f);
-
-// static
-const size_t NonlinearBeamformer::kNumFreqBins;
-
-NonlinearBeamformer::NonlinearBeamformer(
- const std::vector<Point>& array_geometry,
- SphericalPointf target_direction)
- : num_input_channels_(array_geometry.size()),
- array_geometry_(GetCenteredArray(array_geometry)),
- array_normal_(GetArrayNormalIfExists(array_geometry)),
- min_mic_spacing_(GetMinimumSpacing(array_geometry)),
- target_angle_radians_(target_direction.azimuth()),
- away_radians_(std::min(
- static_cast<float>(M_PI),
- std::max(kMinAwayRadians,
- kAwaySlope * static_cast<float>(M_PI) / min_mic_spacing_))) {
- WindowGenerator::KaiserBesselDerived(kKbdAlpha, kFftSize, window_);
-}
-
-void NonlinearBeamformer::Initialize(int chunk_size_ms, int sample_rate_hz) {
- chunk_length_ =
- static_cast<size_t>(sample_rate_hz / (1000.f / chunk_size_ms));
- sample_rate_hz_ = sample_rate_hz;
-
- high_pass_postfilter_mask_ = 1.f;
- is_target_present_ = false;
- hold_target_blocks_ = kHoldTargetSeconds * 2 * sample_rate_hz / kFftSize;
- interference_blocks_count_ = hold_target_blocks_;
-
- lapped_transform_.reset(new LappedTransform(num_input_channels_,
- 1,
- chunk_length_,
- window_,
- kFftSize,
- kFftSize / 2,
- this));
- for (size_t i = 0; i < kNumFreqBins; ++i) {
- time_smooth_mask_[i] = 1.f;
- final_mask_[i] = 1.f;
- float freq_hz = (static_cast<float>(i) / kFftSize) * sample_rate_hz_;
- wave_numbers_[i] = 2 * M_PI * freq_hz / kSpeedOfSoundMeterSeconds;
- }
-
- InitLowFrequencyCorrectionRanges();
- InitDiffuseCovMats();
- AimAt(SphericalPointf(target_angle_radians_, 0.f, 1.f));
-}
-
-// These bin indexes determine the regions over which a mean is taken. This is
-// applied as a constant value over the adjacent end "frequency correction"
-// regions.
-//
-// low_mean_start_bin_ high_mean_start_bin_
-// v v constant
-// |----------------|--------|----------------|-------|----------------|
-// constant ^ ^
-// low_mean_end_bin_ high_mean_end_bin_
-//
-void NonlinearBeamformer::InitLowFrequencyCorrectionRanges() {
- low_mean_start_bin_ = Round(kLowMeanStartHz * kFftSize / sample_rate_hz_);
- low_mean_end_bin_ = Round(kLowMeanEndHz * kFftSize / sample_rate_hz_);
-
- RTC_DCHECK_GT(low_mean_start_bin_, 0U);
- RTC_DCHECK_LT(low_mean_start_bin_, low_mean_end_bin_);
-}
-
-void NonlinearBeamformer::InitHighFrequencyCorrectionRanges() {
- const float kAliasingFreqHz =
- kSpeedOfSoundMeterSeconds /
- (min_mic_spacing_ * (1.f + std::abs(std::cos(target_angle_radians_))));
- const float kHighMeanStartHz = std::min(0.5f * kAliasingFreqHz,
- sample_rate_hz_ / 2.f);
- const float kHighMeanEndHz = std::min(0.75f * kAliasingFreqHz,
- sample_rate_hz_ / 2.f);
- high_mean_start_bin_ = Round(kHighMeanStartHz * kFftSize / sample_rate_hz_);
- high_mean_end_bin_ = Round(kHighMeanEndHz * kFftSize / sample_rate_hz_);
-
- RTC_DCHECK_LT(low_mean_end_bin_, high_mean_end_bin_);
- RTC_DCHECK_LT(high_mean_start_bin_, high_mean_end_bin_);
- RTC_DCHECK_LT(high_mean_end_bin_, kNumFreqBins - 1);
-}
-
-void NonlinearBeamformer::InitInterfAngles() {
- interf_angles_radians_.clear();
- const Point target_direction = AzimuthToPoint(target_angle_radians_);
- const Point clockwise_interf_direction =
- AzimuthToPoint(target_angle_radians_ - away_radians_);
- if (!array_normal_ ||
- DotProduct(*array_normal_, target_direction) *
- DotProduct(*array_normal_, clockwise_interf_direction) >=
- 0.f) {
- // The target and clockwise interferer are in the same half-plane defined
- // by the array.
- interf_angles_radians_.push_back(target_angle_radians_ - away_radians_);
- } else {
- // Otherwise, the interferer will begin reflecting back at the target.
- // Instead rotate it away 180 degrees.
- interf_angles_radians_.push_back(target_angle_radians_ - away_radians_ +
- M_PI);
- }
- const Point counterclock_interf_direction =
- AzimuthToPoint(target_angle_radians_ + away_radians_);
- if (!array_normal_ ||
- DotProduct(*array_normal_, target_direction) *
- DotProduct(*array_normal_, counterclock_interf_direction) >=
- 0.f) {
- // The target and counter-clockwise interferer are in the same half-plane
- // defined by the array.
- interf_angles_radians_.push_back(target_angle_radians_ + away_radians_);
- } else {
- // Otherwise, the interferer will begin reflecting back at the target.
- // Instead rotate it away 180 degrees.
- interf_angles_radians_.push_back(target_angle_radians_ + away_radians_ -
- M_PI);
- }
-}
-
-void NonlinearBeamformer::InitDelaySumMasks() {
- for (size_t f_ix = 0; f_ix < kNumFreqBins; ++f_ix) {
- delay_sum_masks_[f_ix].Resize(1, num_input_channels_);
- CovarianceMatrixGenerator::PhaseAlignmentMasks(
- f_ix, kFftSize, sample_rate_hz_, kSpeedOfSoundMeterSeconds,
- array_geometry_, target_angle_radians_, &delay_sum_masks_[f_ix]);
-
- complex_f norm_factor = sqrt(
- ConjugateDotProduct(delay_sum_masks_[f_ix], delay_sum_masks_[f_ix]));
- delay_sum_masks_[f_ix].Scale(1.f / norm_factor);
- normalized_delay_sum_masks_[f_ix].CopyFrom(delay_sum_masks_[f_ix]);
- normalized_delay_sum_masks_[f_ix].Scale(1.f / SumAbs(
- normalized_delay_sum_masks_[f_ix]));
- }
-}
-
-void NonlinearBeamformer::InitTargetCovMats() {
- for (size_t i = 0; i < kNumFreqBins; ++i) {
- target_cov_mats_[i].Resize(num_input_channels_, num_input_channels_);
- TransposedConjugatedProduct(delay_sum_masks_[i], &target_cov_mats_[i]);
- }
-}
-
-void NonlinearBeamformer::InitDiffuseCovMats() {
- for (size_t i = 0; i < kNumFreqBins; ++i) {
- uniform_cov_mat_[i].Resize(num_input_channels_, num_input_channels_);
- CovarianceMatrixGenerator::UniformCovarianceMatrix(
- wave_numbers_[i], array_geometry_, &uniform_cov_mat_[i]);
- complex_f normalization_factor = uniform_cov_mat_[i].elements()[0][0];
- uniform_cov_mat_[i].Scale(1.f / normalization_factor);
- uniform_cov_mat_[i].Scale(1 - kBalance);
- }
-}
-
-void NonlinearBeamformer::InitInterfCovMats() {
- for (size_t i = 0; i < kNumFreqBins; ++i) {
- interf_cov_mats_[i].clear();
- for (size_t j = 0; j < interf_angles_radians_.size(); ++j) {
- interf_cov_mats_[i].push_back(new ComplexMatrixF(num_input_channels_,
- num_input_channels_));
- ComplexMatrixF angled_cov_mat(num_input_channels_, num_input_channels_);
- CovarianceMatrixGenerator::AngledCovarianceMatrix(
- kSpeedOfSoundMeterSeconds,
- interf_angles_radians_[j],
- i,
- kFftSize,
- kNumFreqBins,
- sample_rate_hz_,
- array_geometry_,
- &angled_cov_mat);
- // Normalize matrices before averaging them.
- complex_f normalization_factor = angled_cov_mat.elements()[0][0];
- angled_cov_mat.Scale(1.f / normalization_factor);
- // Weighted average of matrices.
- angled_cov_mat.Scale(kBalance);
- interf_cov_mats_[i][j]->Add(uniform_cov_mat_[i], angled_cov_mat);
- }
- }
-}
-
-void NonlinearBeamformer::NormalizeCovMats() {
- for (size_t i = 0; i < kNumFreqBins; ++i) {
- rxiws_[i] = Norm(target_cov_mats_[i], delay_sum_masks_[i]);
- rpsiws_[i].clear();
- for (size_t j = 0; j < interf_angles_radians_.size(); ++j) {
- rpsiws_[i].push_back(Norm(*interf_cov_mats_[i][j], delay_sum_masks_[i]));
- }
- }
-}
-
-void NonlinearBeamformer::ProcessChunk(const ChannelBuffer<float>& input,
- ChannelBuffer<float>* output) {
- RTC_DCHECK_EQ(input.num_channels(), num_input_channels_);
- RTC_DCHECK_EQ(input.num_frames_per_band(), chunk_length_);
-
- float old_high_pass_mask = high_pass_postfilter_mask_;
- lapped_transform_->ProcessChunk(input.channels(0), output->channels(0));
- // Ramp up/down for smoothing. 1 mask per 10ms results in audible
- // discontinuities.
- const float ramp_increment =
- (high_pass_postfilter_mask_ - old_high_pass_mask) /
- input.num_frames_per_band();
- // Apply the smoothed high-pass mask to the first channel of each band.
- // This can be done because the effct of the linear beamformer is negligible
- // compared to the post-filter.
- for (size_t i = 1; i < input.num_bands(); ++i) {
- float smoothed_mask = old_high_pass_mask;
- for (size_t j = 0; j < input.num_frames_per_band(); ++j) {
- smoothed_mask += ramp_increment;
- output->channels(i)[0][j] = input.channels(i)[0][j] * smoothed_mask;
- }
- }
-}
-
-void NonlinearBeamformer::AimAt(const SphericalPointf& target_direction) {
- target_angle_radians_ = target_direction.azimuth();
- InitHighFrequencyCorrectionRanges();
- InitInterfAngles();
- InitDelaySumMasks();
- InitTargetCovMats();
- InitInterfCovMats();
- NormalizeCovMats();
-}
-
-bool NonlinearBeamformer::IsInBeam(const SphericalPointf& spherical_point) {
- // If more than half-beamwidth degrees away from the beam's center,
- // you are out of the beam.
- return fabs(spherical_point.azimuth() - target_angle_radians_) <
- kHalfBeamWidthRadians;
-}
-
-void NonlinearBeamformer::ProcessAudioBlock(const complex_f* const* input,
- int num_input_channels,
- size_t num_freq_bins,
- int num_output_channels,
- complex_f* const* output) {
- RTC_CHECK_EQ(num_freq_bins, kNumFreqBins);
- RTC_CHECK_EQ(num_input_channels, num_input_channels_);
- RTC_CHECK_EQ(num_output_channels, 1);
-
- // Calculating the post-filter masks. Note that we need two for each
- // frequency bin to account for the positive and negative interferer
- // angle.
- for (size_t i = low_mean_start_bin_; i <= high_mean_end_bin_; ++i) {
- eig_m_.CopyFromColumn(input, i, num_input_channels_);
- float eig_m_norm_factor = std::sqrt(SumSquares(eig_m_));
- if (eig_m_norm_factor != 0.f) {
- eig_m_.Scale(1.f / eig_m_norm_factor);
- }
-
- float rxim = Norm(target_cov_mats_[i], eig_m_);
- float ratio_rxiw_rxim = 0.f;
- if (rxim > 0.f) {
- ratio_rxiw_rxim = rxiws_[i] / rxim;
- }
-
- complex_f rmw = abs(ConjugateDotProduct(delay_sum_masks_[i], eig_m_));
- rmw *= rmw;
- float rmw_r = rmw.real();
-
- new_mask_[i] = CalculatePostfilterMask(*interf_cov_mats_[i][0],
- rpsiws_[i][0],
- ratio_rxiw_rxim,
- rmw_r);
- for (size_t j = 1; j < interf_angles_radians_.size(); ++j) {
- float tmp_mask = CalculatePostfilterMask(*interf_cov_mats_[i][j],
- rpsiws_[i][j],
- ratio_rxiw_rxim,
- rmw_r);
- if (tmp_mask < new_mask_[i]) {
- new_mask_[i] = tmp_mask;
- }
- }
- }
-
- ApplyMaskTimeSmoothing();
- EstimateTargetPresence();
- ApplyLowFrequencyCorrection();
- ApplyHighFrequencyCorrection();
- ApplyMaskFrequencySmoothing();
- ApplyMasks(input, output);
-}
-
-float NonlinearBeamformer::CalculatePostfilterMask(
- const ComplexMatrixF& interf_cov_mat,
- float rpsiw,
- float ratio_rxiw_rxim,
- float rmw_r) {
- float rpsim = Norm(interf_cov_mat, eig_m_);
-
- float ratio = 0.f;
- if (rpsim > 0.f) {
- ratio = rpsiw / rpsim;
- }
-
- return (1.f - std::min(kCutOffConstant, ratio / rmw_r)) /
- (1.f - std::min(kCutOffConstant, ratio / ratio_rxiw_rxim));
-}
-
-void NonlinearBeamformer::ApplyMasks(const complex_f* const* input,
- complex_f* const* output) {
- complex_f* output_channel = output[0];
- for (size_t f_ix = 0; f_ix < kNumFreqBins; ++f_ix) {
- output_channel[f_ix] = complex_f(0.f, 0.f);
-
- const complex_f* delay_sum_mask_els =
- normalized_delay_sum_masks_[f_ix].elements()[0];
- for (int c_ix = 0; c_ix < num_input_channels_; ++c_ix) {
- output_channel[f_ix] += input[c_ix][f_ix] * delay_sum_mask_els[c_ix];
- }
-
- output_channel[f_ix] *= kCompensationGain * final_mask_[f_ix];
- }
-}
-
-// Smooth new_mask_ into time_smooth_mask_.
-void NonlinearBeamformer::ApplyMaskTimeSmoothing() {
- for (size_t i = low_mean_start_bin_; i <= high_mean_end_bin_; ++i) {
- time_smooth_mask_[i] = kMaskTimeSmoothAlpha * new_mask_[i] +
- (1 - kMaskTimeSmoothAlpha) * time_smooth_mask_[i];
- }
-}
-
-// Copy time_smooth_mask_ to final_mask_ and smooth over frequency.
-void NonlinearBeamformer::ApplyMaskFrequencySmoothing() {
- // Smooth over frequency in both directions. The "frequency correction"
- // regions have constant value, but we enter them to smooth over the jump
- // that exists at the boundary. However, this does mean when smoothing "away"
- // from the region that we only need to use the last element.
- //
- // Upward smoothing:
- // low_mean_start_bin_
- // v
- // |------|------------|------|
- // ^------------------>^
- //
- // Downward smoothing:
- // high_mean_end_bin_
- // v
- // |------|------------|------|
- // ^<------------------^
- std::copy(time_smooth_mask_, time_smooth_mask_ + kNumFreqBins, final_mask_);
- for (size_t i = low_mean_start_bin_; i < kNumFreqBins; ++i) {
- final_mask_[i] = kMaskFrequencySmoothAlpha * final_mask_[i] +
- (1 - kMaskFrequencySmoothAlpha) * final_mask_[i - 1];
- }
- for (size_t i = high_mean_end_bin_ + 1; i > 0; --i) {
- final_mask_[i - 1] = kMaskFrequencySmoothAlpha * final_mask_[i - 1] +
- (1 - kMaskFrequencySmoothAlpha) * final_mask_[i];
- }
-}
-
-// Apply low frequency correction to time_smooth_mask_.
-void NonlinearBeamformer::ApplyLowFrequencyCorrection() {
- const float low_frequency_mask =
- MaskRangeMean(low_mean_start_bin_, low_mean_end_bin_ + 1);
- std::fill(time_smooth_mask_, time_smooth_mask_ + low_mean_start_bin_,
- low_frequency_mask);
-}
-
-// Apply high frequency correction to time_smooth_mask_. Update
-// high_pass_postfilter_mask_ to use for the high frequency time-domain bands.
-void NonlinearBeamformer::ApplyHighFrequencyCorrection() {
- high_pass_postfilter_mask_ =
- MaskRangeMean(high_mean_start_bin_, high_mean_end_bin_ + 1);
- std::fill(time_smooth_mask_ + high_mean_end_bin_ + 1,
- time_smooth_mask_ + kNumFreqBins, high_pass_postfilter_mask_);
-}
-
-// Compute mean over the given range of time_smooth_mask_, [first, last).
-float NonlinearBeamformer::MaskRangeMean(size_t first, size_t last) {
- RTC_DCHECK_GT(last, first);
- const float sum = std::accumulate(time_smooth_mask_ + first,
- time_smooth_mask_ + last, 0.f);
- return sum / (last - first);
-}
-
-void NonlinearBeamformer::EstimateTargetPresence() {
- const size_t quantile = static_cast<size_t>(
- (high_mean_end_bin_ - low_mean_start_bin_) * kMaskQuantile +
- low_mean_start_bin_);
- std::nth_element(new_mask_ + low_mean_start_bin_, new_mask_ + quantile,
- new_mask_ + high_mean_end_bin_ + 1);
- if (new_mask_[quantile] > kMaskTargetThreshold) {
- is_target_present_ = true;
- interference_blocks_count_ = 0;
- } else {
- is_target_present_ = interference_blocks_count_++ < hold_target_blocks_;
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h b/webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h
deleted file mode 100644
index 4289cce..0000000
--- a/webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
-
-// MSVC++ requires this to be set before any other includes to get M_PI.
-#define _USE_MATH_DEFINES
-
-#include <math.h>
-#include <vector>
-
-#include "webrtc/common_audio/lapped_transform.h"
-#include "webrtc/common_audio/channel_buffer.h"
-#include "webrtc/modules/audio_processing/beamformer/beamformer.h"
-#include "webrtc/modules/audio_processing/beamformer/complex_matrix.h"
-#include "webrtc/system_wrappers/include/scoped_vector.h"
-
-namespace webrtc {
-
-// Enhances sound sources coming directly in front of a uniform linear array
-// and suppresses sound sources coming from all other directions. Operates on
-// multichannel signals and produces single-channel output.
-//
-// The implemented nonlinear postfilter algorithm taken from "A Robust Nonlinear
-// Beamforming Postprocessor" by Bastiaan Kleijn.
-class NonlinearBeamformer
- : public Beamformer<float>,
- public LappedTransform::Callback {
- public:
- static const float kHalfBeamWidthRadians;
-
- explicit NonlinearBeamformer(
- const std::vector<Point>& array_geometry,
- SphericalPointf target_direction =
- SphericalPointf(static_cast<float>(M_PI) / 2.f, 0.f, 1.f));
-
- // Sample rate corresponds to the lower band.
- // Needs to be called before the NonlinearBeamformer can be used.
- void Initialize(int chunk_size_ms, int sample_rate_hz) override;
-
- // Process one time-domain chunk of audio. The audio is expected to be split
- // into frequency bands inside the ChannelBuffer. The number of frames and
- // channels must correspond to the constructor parameters. The same
- // ChannelBuffer can be passed in as |input| and |output|.
- void ProcessChunk(const ChannelBuffer<float>& input,
- ChannelBuffer<float>* output) override;
-
- void AimAt(const SphericalPointf& target_direction) override;
-
- bool IsInBeam(const SphericalPointf& spherical_point) override;
-
- // After processing each block |is_target_present_| is set to true if the
- // target signal es present and to false otherwise. This methods can be called
- // to know if the data is target signal or interference and process it
- // accordingly.
- bool is_target_present() override { return is_target_present_; }
-
- protected:
- // Process one frequency-domain block of audio. This is where the fun
- // happens. Implements LappedTransform::Callback.
- void ProcessAudioBlock(const complex<float>* const* input,
- int num_input_channels,
- size_t num_freq_bins,
- int num_output_channels,
- complex<float>* const* output) override;
-
- private:
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
- FRIEND_TEST_ALL_PREFIXES(NonlinearBeamformerTest,
- InterfAnglesTakeAmbiguityIntoAccount);
-#endif
-
- typedef Matrix<float> MatrixF;
- typedef ComplexMatrix<float> ComplexMatrixF;
- typedef complex<float> complex_f;
-
- void InitLowFrequencyCorrectionRanges();
- void InitHighFrequencyCorrectionRanges();
- void InitInterfAngles();
- void InitDelaySumMasks();
- void InitTargetCovMats();
- void InitDiffuseCovMats();
- void InitInterfCovMats();
- void NormalizeCovMats();
-
- // Calculates postfilter masks that minimize the mean squared error of our
- // estimation of the desired signal.
- float CalculatePostfilterMask(const ComplexMatrixF& interf_cov_mat,
- float rpsiw,
- float ratio_rxiw_rxim,
- float rmxi_r);
-
- // Prevents the postfilter masks from degenerating too quickly (a cause of
- // musical noise).
- void ApplyMaskTimeSmoothing();
- void ApplyMaskFrequencySmoothing();
-
- // The postfilter masks are unreliable at low frequencies. Calculates a better
- // mask by averaging mid-low frequency values.
- void ApplyLowFrequencyCorrection();
-
- // Postfilter masks are also unreliable at high frequencies. Average mid-high
- // frequency masks to calculate a single mask per block which can be applied
- // in the time-domain. Further, we average these block-masks over a chunk,
- // resulting in one postfilter mask per audio chunk. This allows us to skip
- // both transforming and blocking the high-frequency signal.
- void ApplyHighFrequencyCorrection();
-
- // Compute the means needed for the above frequency correction.
- float MaskRangeMean(size_t start_bin, size_t end_bin);
-
- // Applies both sets of masks to |input| and store in |output|.
- void ApplyMasks(const complex_f* const* input, complex_f* const* output);
-
- void EstimateTargetPresence();
-
- static const size_t kFftSize = 256;
- static const size_t kNumFreqBins = kFftSize / 2 + 1;
-
- // Deals with the fft transform and blocking.
- size_t chunk_length_;
- rtc::scoped_ptr<LappedTransform> lapped_transform_;
- float window_[kFftSize];
-
- // Parameters exposed to the user.
- const int num_input_channels_;
- int sample_rate_hz_;
-
- const std::vector<Point> array_geometry_;
- // The normal direction of the array if it has one and it is in the xy-plane.
- const rtc::Maybe<Point> array_normal_;
-
- // Minimum spacing between microphone pairs.
- const float min_mic_spacing_;
-
- // Calculated based on user-input and constants in the .cc file.
- size_t low_mean_start_bin_;
- size_t low_mean_end_bin_;
- size_t high_mean_start_bin_;
- size_t high_mean_end_bin_;
-
- // Quickly varying mask updated every block.
- float new_mask_[kNumFreqBins];
- // Time smoothed mask.
- float time_smooth_mask_[kNumFreqBins];
- // Time and frequency smoothed mask.
- float final_mask_[kNumFreqBins];
-
- float target_angle_radians_;
- // Angles of the interferer scenarios.
- std::vector<float> interf_angles_radians_;
- // The angle between the target and the interferer scenarios.
- const float away_radians_;
-
- // Array of length |kNumFreqBins|, Matrix of size |1| x |num_channels_|.
- ComplexMatrixF delay_sum_masks_[kNumFreqBins];
- ComplexMatrixF normalized_delay_sum_masks_[kNumFreqBins];
-
- // Arrays of length |kNumFreqBins|, Matrix of size |num_input_channels_| x
- // |num_input_channels_|.
- ComplexMatrixF target_cov_mats_[kNumFreqBins];
- ComplexMatrixF uniform_cov_mat_[kNumFreqBins];
- // Array of length |kNumFreqBins|, Matrix of size |num_input_channels_| x
- // |num_input_channels_|. ScopedVector has a size equal to the number of
- // interferer scenarios.
- ScopedVector<ComplexMatrixF> interf_cov_mats_[kNumFreqBins];
-
- // Of length |kNumFreqBins|.
- float wave_numbers_[kNumFreqBins];
-
- // Preallocated for ProcessAudioBlock()
- // Of length |kNumFreqBins|.
- float rxiws_[kNumFreqBins];
- // The vector has a size equal to the number of interferer scenarios.
- std::vector<float> rpsiws_[kNumFreqBins];
-
- // The microphone normalization factor.
- ComplexMatrixF eig_m_;
-
- // For processing the high-frequency input signal.
- float high_pass_postfilter_mask_;
-
- // True when the target signal is present.
- bool is_target_present_;
- // Number of blocks after which the data is considered interference if the
- // mask does not pass |kMaskSignalThreshold|.
- size_t hold_target_blocks_;
- // Number of blocks since the last mask that passed |kMaskSignalThreshold|.
- size_t interference_blocks_count_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
diff --git a/webrtc/modules/audio_processing/common.h b/webrtc/modules/audio_processing/common.h
index ed8a054..d8532c5 100644
--- a/webrtc/modules/audio_processing/common.h
+++ b/webrtc/modules/audio_processing/common.h
@@ -8,16 +8,15 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_COMMON_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_COMMON_H_
+#ifndef MODULES_AUDIO_PROCESSING_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_COMMON_H_
-#include <assert.h>
-
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "rtc_base/checks.h"
namespace webrtc {
-static inline int ChannelsFromLayout(AudioProcessing::ChannelLayout layout) {
+static inline size_t ChannelsFromLayout(AudioProcessing::ChannelLayout layout) {
switch (layout) {
case AudioProcessing::kMono:
case AudioProcessing::kMonoAndKeyboard:
@@ -26,10 +25,10 @@ static inline int ChannelsFromLayout(AudioProcessing::ChannelLayout layout) {
case AudioProcessing::kStereoAndKeyboard:
return 2;
}
- assert(false);
- return -1;
+ RTC_NOTREACHED();
+ return 0;
}
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_COMMON_H_
+#endif // MODULES_AUDIO_PROCESSING_COMMON_H_
diff --git a/webrtc/modules/audio_processing/debug.proto b/webrtc/modules/audio_processing/debug.proto
index 2272712..07cce23 100644
--- a/webrtc/modules/audio_processing/debug.proto
+++ b/webrtc/modules/audio_processing/debug.proto
@@ -12,6 +12,9 @@ message Init {
optional int32 num_reverse_channels = 5;
optional int32 reverse_sample_rate = 6;
optional int32 output_sample_rate = 7;
+ optional int32 reverse_output_sample_rate = 8;
+ optional int32 num_reverse_output_channels = 9;
+ optional int64 timestamp_ms = 10;
}
// May contain interleaved or deinterleaved data, but don't store both formats.
@@ -44,7 +47,6 @@ message Stream {
// Contains the configurations of various APM component. A Config message is
// added when any of the fields are changed.
message Config {
- // Next field number 17.
// Acoustic echo canceler.
optional bool aec_enabled = 1;
optional bool aec_delay_agnostic_enabled = 2;
@@ -53,8 +55,8 @@ message Config {
optional int32 aec_suppression_level = 5;
// Mobile AEC.
optional bool aecm_enabled = 6;
- optional bool aecm_comfort_noise_enabled = 7;
- optional int32 aecm_routing_mode = 8;
+ optional bool aecm_comfort_noise_enabled = 7 [deprecated = true];
+ optional int32 aecm_routing_mode = 8 [deprecated = true];
// Automatic gain controller.
optional bool agc_enabled = 9;
optional int32 agc_mode = 10;
@@ -67,6 +69,29 @@ message Config {
optional int32 ns_level = 15;
// Transient suppression.
optional bool transient_suppression_enabled = 16;
+ // Semicolon-separated string containing experimental feature
+ // descriptions.
+ optional string experiments_description = 17;
+ reserved 18; // Intelligibility enhancer enabled (deprecated).
+ // Pre amplifier.
+ optional bool pre_amplifier_enabled = 19;
+ optional float pre_amplifier_fixed_gain_factor = 20;
+
+ // Next field number 21.
+}
+
+message PlayoutAudioDeviceInfo {
+ optional int32 id = 1;
+ optional int32 max_volume = 2;
+}
+
+message RuntimeSetting {
+ optional float capture_pre_gain = 1;
+ optional float custom_render_processing_setting = 2;
+ optional float capture_fixed_post_gain = 3;
+ optional int32 playout_volume_change = 4;
+ optional PlayoutAudioDeviceInfo playout_audio_device_change = 5;
+ optional bool capture_output_used = 6;
}
message Event {
@@ -76,6 +101,7 @@ message Event {
STREAM = 2;
CONFIG = 3;
UNKNOWN_EVENT = 4;
+ RUNTIME_SETTING = 5;
}
required Type type = 1;
@@ -84,4 +110,5 @@ message Event {
optional ReverseStream reverse_stream = 3;
optional Stream stream = 4;
optional Config config = 5;
+ optional RuntimeSetting runtime_setting = 6;
}
diff --git a/webrtc/modules/audio_processing/echo_cancellation_impl.cc b/webrtc/modules/audio_processing/echo_cancellation_impl.cc
deleted file mode 100644
index 56ee9e0..0000000
--- a/webrtc/modules/audio_processing/echo_cancellation_impl.cc
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/echo_cancellation_impl.h"
-
-#include <assert.h>
-#include <string.h>
-
-extern "C" {
-#include "webrtc/modules/audio_processing/aec/aec_core.h"
-}
-#include "webrtc/modules/audio_processing/aec/include/echo_cancellation.h"
-#include "webrtc/modules/audio_processing/audio_buffer.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-
-namespace webrtc {
-
-typedef void Handle;
-
-namespace {
-int16_t MapSetting(EchoCancellation::SuppressionLevel level) {
- switch (level) {
- case EchoCancellation::kLowSuppression:
- return kAecNlpConservative;
- case EchoCancellation::kModerateSuppression:
- return kAecNlpModerate;
- case EchoCancellation::kHighSuppression:
- return kAecNlpAggressive;
- }
- assert(false);
- return -1;
-}
-
-AudioProcessing::Error MapError(int err) {
- switch (err) {
- case AEC_UNSUPPORTED_FUNCTION_ERROR:
- return AudioProcessing::kUnsupportedFunctionError;
- case AEC_BAD_PARAMETER_ERROR:
- return AudioProcessing::kBadParameterError;
- case AEC_BAD_PARAMETER_WARNING:
- return AudioProcessing::kBadStreamParameterWarning;
- default:
- // AEC_UNSPECIFIED_ERROR
- // AEC_UNINITIALIZED_ERROR
- // AEC_NULL_POINTER_ERROR
- return AudioProcessing::kUnspecifiedError;
- }
-}
-} // namespace
-
-EchoCancellationImpl::EchoCancellationImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit)
- : ProcessingComponent(),
- apm_(apm),
- crit_(crit),
- drift_compensation_enabled_(false),
- metrics_enabled_(false),
- suppression_level_(kModerateSuppression),
- stream_drift_samples_(0),
- was_stream_drift_set_(false),
- stream_has_echo_(false),
- delay_logging_enabled_(false),
- extended_filter_enabled_(false),
- delay_agnostic_enabled_(false) {
-}
-
-EchoCancellationImpl::~EchoCancellationImpl() {}
-
-int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
- }
-
- assert(audio->num_frames_per_band() <= 160);
- assert(audio->num_channels() == apm_->num_reverse_channels());
-
- int err = apm_->kNoError;
-
- // The ordering convention must be followed to pass to the correct AEC.
- size_t handle_index = 0;
- for (int i = 0; i < apm_->num_output_channels(); i++) {
- for (int j = 0; j < audio->num_channels(); j++) {
- Handle* my_handle = static_cast<Handle*>(handle(handle_index));
- err = WebRtcAec_BufferFarend(
- my_handle,
- audio->split_bands_const_f(j)[kBand0To8kHz],
- audio->num_frames_per_band());
-
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle); // TODO(ajm): warning possible?
- }
-
- handle_index++;
- }
- }
-
- return apm_->kNoError;
-}
-
-int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
- }
-
- if (!apm_->was_stream_delay_set()) {
- return apm_->kStreamParameterNotSetError;
- }
-
- if (drift_compensation_enabled_ && !was_stream_drift_set_) {
- return apm_->kStreamParameterNotSetError;
- }
-
- assert(audio->num_frames_per_band() <= 160);
- assert(audio->num_channels() == apm_->num_output_channels());
-
- int err = apm_->kNoError;
-
- // The ordering convention must be followed to pass to the correct AEC.
- size_t handle_index = 0;
- stream_has_echo_ = false;
- for (int i = 0; i < audio->num_channels(); i++) {
- for (int j = 0; j < apm_->num_reverse_channels(); j++) {
- Handle* my_handle = handle(handle_index);
- err = WebRtcAec_Process(
- my_handle,
- audio->split_bands_const_f(i),
- audio->num_bands(),
- audio->split_bands_f(i),
- audio->num_frames_per_band(),
- apm_->stream_delay_ms(),
- stream_drift_samples_);
-
- if (err != apm_->kNoError) {
- err = GetHandleError(my_handle);
- // TODO(ajm): Figure out how to return warnings properly.
- if (err != apm_->kBadStreamParameterWarning) {
- return err;
- }
- }
-
- int status = 0;
- err = WebRtcAec_get_echo_status(my_handle, &status);
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle);
- }
-
- if (status == 1) {
- stream_has_echo_ = true;
- }
-
- handle_index++;
- }
- }
-
- was_stream_drift_set_ = false;
- return apm_->kNoError;
-}
-
-int EchoCancellationImpl::Enable(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- // Ensure AEC and AECM are not both enabled.
- if (enable && apm_->echo_control_mobile()->is_enabled()) {
- return apm_->kBadParameterError;
- }
-
- return EnableComponent(enable);
-}
-
-bool EchoCancellationImpl::is_enabled() const {
- return is_component_enabled();
-}
-
-int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) {
- CriticalSectionScoped crit_scoped(crit_);
- if (MapSetting(level) == -1) {
- return apm_->kBadParameterError;
- }
-
- suppression_level_ = level;
- return Configure();
-}
-
-EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level()
- const {
- return suppression_level_;
-}
-
-int EchoCancellationImpl::enable_drift_compensation(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- drift_compensation_enabled_ = enable;
- return Configure();
-}
-
-bool EchoCancellationImpl::is_drift_compensation_enabled() const {
- return drift_compensation_enabled_;
-}
-
-void EchoCancellationImpl::set_stream_drift_samples(int drift) {
- was_stream_drift_set_ = true;
- stream_drift_samples_ = drift;
-}
-
-int EchoCancellationImpl::stream_drift_samples() const {
- return stream_drift_samples_;
-}
-
-int EchoCancellationImpl::enable_metrics(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- metrics_enabled_ = enable;
- return Configure();
-}
-
-bool EchoCancellationImpl::are_metrics_enabled() const {
- return metrics_enabled_;
-}
-
-// TODO(ajm): we currently just use the metrics from the first AEC. Think more
-// aboue the best way to extend this to multi-channel.
-int EchoCancellationImpl::GetMetrics(Metrics* metrics) {
- CriticalSectionScoped crit_scoped(crit_);
- if (metrics == NULL) {
- return apm_->kNullPointerError;
- }
-
- if (!is_component_enabled() || !metrics_enabled_) {
- return apm_->kNotEnabledError;
- }
-
- AecMetrics my_metrics;
- memset(&my_metrics, 0, sizeof(my_metrics));
- memset(metrics, 0, sizeof(Metrics));
-
- Handle* my_handle = static_cast<Handle*>(handle(0));
- int err = WebRtcAec_GetMetrics(my_handle, &my_metrics);
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle);
- }
-
- metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant;
- metrics->residual_echo_return_loss.average = my_metrics.rerl.average;
- metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max;
- metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min;
-
- metrics->echo_return_loss.instant = my_metrics.erl.instant;
- metrics->echo_return_loss.average = my_metrics.erl.average;
- metrics->echo_return_loss.maximum = my_metrics.erl.max;
- metrics->echo_return_loss.minimum = my_metrics.erl.min;
-
- metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant;
- metrics->echo_return_loss_enhancement.average = my_metrics.erle.average;
- metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max;
- metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min;
-
- metrics->a_nlp.instant = my_metrics.aNlp.instant;
- metrics->a_nlp.average = my_metrics.aNlp.average;
- metrics->a_nlp.maximum = my_metrics.aNlp.max;
- metrics->a_nlp.minimum = my_metrics.aNlp.min;
-
- return apm_->kNoError;
-}
-
-bool EchoCancellationImpl::stream_has_echo() const {
- return stream_has_echo_;
-}
-
-int EchoCancellationImpl::enable_delay_logging(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- delay_logging_enabled_ = enable;
- return Configure();
-}
-
-bool EchoCancellationImpl::is_delay_logging_enabled() const {
- return delay_logging_enabled_;
-}
-
-bool EchoCancellationImpl::is_delay_agnostic_enabled() const {
- return delay_agnostic_enabled_;
-}
-
-bool EchoCancellationImpl::is_extended_filter_enabled() const {
- return extended_filter_enabled_;
-}
-
-// TODO(bjornv): How should we handle the multi-channel case?
-int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) {
- float fraction_poor_delays = 0;
- return GetDelayMetrics(median, std, &fraction_poor_delays);
-}
-
-int EchoCancellationImpl::GetDelayMetrics(int* median, int* std,
- float* fraction_poor_delays) {
- CriticalSectionScoped crit_scoped(crit_);
- if (median == NULL) {
- return apm_->kNullPointerError;
- }
- if (std == NULL) {
- return apm_->kNullPointerError;
- }
-
- if (!is_component_enabled() || !delay_logging_enabled_) {
- return apm_->kNotEnabledError;
- }
-
- Handle* my_handle = static_cast<Handle*>(handle(0));
- if (WebRtcAec_GetDelayMetrics(my_handle, median, std, fraction_poor_delays) !=
- apm_->kNoError) {
- return GetHandleError(my_handle);
- }
-
- return apm_->kNoError;
-}
-
-struct AecCore* EchoCancellationImpl::aec_core() const {
- CriticalSectionScoped crit_scoped(crit_);
- if (!is_component_enabled()) {
- return NULL;
- }
- Handle* my_handle = static_cast<Handle*>(handle(0));
- return WebRtcAec_aec_core(my_handle);
-}
-
-int EchoCancellationImpl::Initialize() {
- int err = ProcessingComponent::Initialize();
- if (err != apm_->kNoError || !is_component_enabled()) {
- return err;
- }
-
- return apm_->kNoError;
-}
-
-void EchoCancellationImpl::SetExtraOptions(const Config& config) {
- extended_filter_enabled_ = config.Get<ExtendedFilter>().enabled;
- delay_agnostic_enabled_ = config.Get<DelayAgnostic>().enabled;
- Configure();
-}
-
-void* EchoCancellationImpl::CreateHandle() const {
- return WebRtcAec_Create();
-}
-
-void EchoCancellationImpl::DestroyHandle(void* handle) const {
- assert(handle != NULL);
- WebRtcAec_Free(static_cast<Handle*>(handle));
-}
-
-int EchoCancellationImpl::InitializeHandle(void* handle) const {
- assert(handle != NULL);
- // TODO(ajm): Drift compensation is disabled in practice. If restored, it
- // should be managed internally and not depend on the hardware sample rate.
- // For now, just hardcode a 48 kHz value.
- return WebRtcAec_Init(static_cast<Handle*>(handle),
- apm_->proc_sample_rate_hz(),
- 48000);
-}
-
-int EchoCancellationImpl::ConfigureHandle(void* handle) const {
- assert(handle != NULL);
- AecConfig config;
- config.metricsMode = metrics_enabled_;
- config.nlpMode = MapSetting(suppression_level_);
- config.skewMode = drift_compensation_enabled_;
- config.delay_logging = delay_logging_enabled_;
-
- WebRtcAec_enable_extended_filter(
- WebRtcAec_aec_core(static_cast<Handle*>(handle)),
- extended_filter_enabled_ ? 1 : 0);
- WebRtcAec_enable_delay_agnostic(
- WebRtcAec_aec_core(static_cast<Handle*>(handle)),
- delay_agnostic_enabled_ ? 1 : 0);
- return WebRtcAec_set_config(static_cast<Handle*>(handle), config);
-}
-
-int EchoCancellationImpl::num_handles_required() const {
- return apm_->num_output_channels() *
- apm_->num_reverse_channels();
-}
-
-int EchoCancellationImpl::GetHandleError(void* handle) const {
- assert(handle != NULL);
- return MapError(WebRtcAec_get_error_code(static_cast<Handle*>(handle)));
-}
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/echo_cancellation_impl.h b/webrtc/modules/audio_processing/echo_cancellation_impl.h
deleted file mode 100644
index 070dcab..0000000
--- a/webrtc/modules/audio_processing/echo_cancellation_impl.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_IMPL_H_
-
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/processing_component.h"
-
-namespace webrtc {
-
-class AudioBuffer;
-class CriticalSectionWrapper;
-
-class EchoCancellationImpl : public EchoCancellation,
- public ProcessingComponent {
- public:
- EchoCancellationImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit);
- virtual ~EchoCancellationImpl();
-
- int ProcessRenderAudio(const AudioBuffer* audio);
- int ProcessCaptureAudio(AudioBuffer* audio);
-
- // EchoCancellation implementation.
- bool is_enabled() const override;
- int stream_drift_samples() const override;
- SuppressionLevel suppression_level() const override;
- bool is_drift_compensation_enabled() const override;
-
- // ProcessingComponent implementation.
- int Initialize() override;
- void SetExtraOptions(const Config& config) override;
-
- bool is_delay_agnostic_enabled() const;
- bool is_extended_filter_enabled() const;
-
- private:
- // EchoCancellation implementation.
- int Enable(bool enable) override;
- int enable_drift_compensation(bool enable) override;
- void set_stream_drift_samples(int drift) override;
- int set_suppression_level(SuppressionLevel level) override;
- int enable_metrics(bool enable) override;
- bool are_metrics_enabled() const override;
- bool stream_has_echo() const override;
- int GetMetrics(Metrics* metrics) override;
- int enable_delay_logging(bool enable) override;
- bool is_delay_logging_enabled() const override;
- int GetDelayMetrics(int* median, int* std) override;
- int GetDelayMetrics(int* median,
- int* std,
- float* fraction_poor_delays) override;
- struct AecCore* aec_core() const override;
-
- // ProcessingComponent implementation.
- void* CreateHandle() const override;
- int InitializeHandle(void* handle) const override;
- int ConfigureHandle(void* handle) const override;
- void DestroyHandle(void* handle) const override;
- int num_handles_required() const override;
- int GetHandleError(void* handle) const override;
-
- const AudioProcessing* apm_;
- CriticalSectionWrapper* crit_;
- bool drift_compensation_enabled_;
- bool metrics_enabled_;
- SuppressionLevel suppression_level_;
- int stream_drift_samples_;
- bool was_stream_drift_set_;
- bool stream_has_echo_;
- bool delay_logging_enabled_;
- bool extended_filter_enabled_;
- bool delay_agnostic_enabled_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_IMPL_H_
diff --git a/webrtc/modules/audio_processing/echo_control_mobile_impl.cc b/webrtc/modules/audio_processing/echo_control_mobile_impl.cc
index 954aac7..8116608 100644
--- a/webrtc/modules/audio_processing/echo_control_mobile_impl.cc
+++ b/webrtc/modules/audio_processing/echo_control_mobile_impl.cc
@@ -8,35 +8,35 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/echo_control_mobile_impl.h"
+#include "modules/audio_processing/echo_control_mobile_impl.h"
-#include <assert.h>
#include <string.h>
-#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
-#include "webrtc/modules/audio_processing/audio_buffer.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/include/logging.h"
+#include <cstdint>
-namespace webrtc {
+#include "modules/audio_processing/aecm/echo_control_mobile.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/constructor_magic.h"
-typedef void Handle;
+namespace webrtc {
namespace {
-int16_t MapSetting(EchoControlMobile::RoutingMode mode) {
+int16_t MapSetting(EchoControlMobileImpl::RoutingMode mode) {
switch (mode) {
- case EchoControlMobile::kQuietEarpieceOrHeadset:
+ case EchoControlMobileImpl::kQuietEarpieceOrHeadset:
return 0;
- case EchoControlMobile::kEarpiece:
+ case EchoControlMobileImpl::kEarpiece:
return 1;
- case EchoControlMobile::kLoudEarpiece:
+ case EchoControlMobileImpl::kLoudEarpiece:
return 2;
- case EchoControlMobile::kSpeakerphone:
+ case EchoControlMobileImpl::kSpeakerphone:
return 3;
- case EchoControlMobile::kLoudSpeakerphone:
+ case EchoControlMobileImpl::kLoudSpeakerphone:
return 4;
}
- assert(false);
+ RTC_NOTREACHED();
return -1;
}
@@ -56,136 +56,183 @@ AudioProcessing::Error MapError(int err) {
return AudioProcessing::kUnspecifiedError;
}
}
+
} // namespace
-size_t EchoControlMobile::echo_path_size_bytes() {
- return WebRtcAecm_echo_path_size_bytes();
-}
+struct EchoControlMobileImpl::StreamProperties {
+ StreamProperties() = delete;
+ StreamProperties(int sample_rate_hz,
+ size_t num_reverse_channels,
+ size_t num_output_channels)
+ : sample_rate_hz(sample_rate_hz),
+ num_reverse_channels(num_reverse_channels),
+ num_output_channels(num_output_channels) {}
+
+ int sample_rate_hz;
+ size_t num_reverse_channels;
+ size_t num_output_channels;
+};
+
+class EchoControlMobileImpl::Canceller {
+ public:
+ Canceller() {
+ state_ = WebRtcAecm_Create();
+ RTC_CHECK(state_);
+ }
-EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit)
- : ProcessingComponent(),
- apm_(apm),
- crit_(crit),
- routing_mode_(kSpeakerphone),
- comfort_noise_enabled_(true),
- external_echo_path_(NULL) {}
-
-EchoControlMobileImpl::~EchoControlMobileImpl() {
- if (external_echo_path_ != NULL) {
- delete [] external_echo_path_;
- external_echo_path_ = NULL;
- }
-}
+ ~Canceller() {
+ RTC_DCHECK(state_);
+ WebRtcAecm_Free(state_);
+ }
-int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
+ void* state() {
+ RTC_DCHECK(state_);
+ return state_;
}
- assert(audio->num_frames_per_band() <= 160);
- assert(audio->num_channels() == apm_->num_reverse_channels());
+ void Initialize(int sample_rate_hz) {
+ RTC_DCHECK(state_);
+ int error = WebRtcAecm_Init(state_, sample_rate_hz);
+ RTC_DCHECK_EQ(AudioProcessing::kNoError, error);
+ }
- int err = apm_->kNoError;
+ private:
+ void* state_;
+ RTC_DISALLOW_COPY_AND_ASSIGN(Canceller);
+};
- // The ordering convention must be followed to pass to the correct AECM.
- size_t handle_index = 0;
- for (int i = 0; i < apm_->num_output_channels(); i++) {
- for (int j = 0; j < audio->num_channels(); j++) {
- Handle* my_handle = static_cast<Handle*>(handle(handle_index));
- err = WebRtcAecm_BufferFarend(
- my_handle,
- audio->split_bands_const(j)[kBand0To8kHz],
- audio->num_frames_per_band());
-
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle); // TODO(ajm): warning possible?
- }
+EchoControlMobileImpl::EchoControlMobileImpl()
+ : routing_mode_(kSpeakerphone), comfort_noise_enabled_(false) {}
- handle_index++;
- }
- }
+EchoControlMobileImpl::~EchoControlMobileImpl() {}
- return apm_->kNoError;
-}
+void EchoControlMobileImpl::ProcessRenderAudio(
+ rtc::ArrayView<const int16_t> packed_render_audio) {
+ RTC_DCHECK(stream_properties_);
+
+ size_t buffer_index = 0;
+ size_t num_frames_per_band =
+ packed_render_audio.size() / (stream_properties_->num_output_channels *
+ stream_properties_->num_reverse_channels);
+
+ for (auto& canceller : cancellers_) {
+ WebRtcAecm_BufferFarend(canceller->state(),
+ &packed_render_audio[buffer_index],
+ num_frames_per_band);
-int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
+ buffer_index += num_frames_per_band;
}
+}
+
+void EchoControlMobileImpl::PackRenderAudioBuffer(
+ const AudioBuffer* audio,
+ size_t num_output_channels,
+ size_t num_channels,
+ std::vector<int16_t>* packed_buffer) {
+ RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
+ audio->num_frames_per_band());
+ RTC_DCHECK_EQ(num_channels, audio->num_channels());
- if (!apm_->was_stream_delay_set()) {
- return apm_->kStreamParameterNotSetError;
+ // The ordering convention must be followed to pass to the correct AECM.
+ packed_buffer->clear();
+ int render_channel = 0;
+ for (size_t i = 0; i < num_output_channels; i++) {
+ for (size_t j = 0; j < audio->num_channels(); j++) {
+ std::array<int16_t, AudioBuffer::kMaxSplitFrameLength> data_to_buffer;
+ FloatS16ToS16(audio->split_bands_const(render_channel)[kBand0To8kHz],
+ audio->num_frames_per_band(), data_to_buffer.data());
+
+ // Buffer the samples in the render queue.
+ packed_buffer->insert(
+ packed_buffer->end(), data_to_buffer.data(),
+ data_to_buffer.data() + audio->num_frames_per_band());
+ render_channel = (render_channel + 1) % audio->num_channels();
+ }
}
+}
+
+size_t EchoControlMobileImpl::NumCancellersRequired(
+ size_t num_output_channels,
+ size_t num_reverse_channels) {
+ return num_output_channels * num_reverse_channels;
+}
- assert(audio->num_frames_per_band() <= 160);
- assert(audio->num_channels() == apm_->num_output_channels());
+int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio,
+ int stream_delay_ms) {
+ RTC_DCHECK(stream_properties_);
+ RTC_DCHECK_GE(160, audio->num_frames_per_band());
+ RTC_DCHECK_EQ(audio->num_channels(), stream_properties_->num_output_channels);
+ RTC_DCHECK_GE(cancellers_.size(), stream_properties_->num_reverse_channels *
+ audio->num_channels());
- int err = apm_->kNoError;
+ int err = AudioProcessing::kNoError;
// The ordering convention must be followed to pass to the correct AECM.
size_t handle_index = 0;
- for (int i = 0; i < audio->num_channels(); i++) {
+ for (size_t capture = 0; capture < audio->num_channels(); ++capture) {
// TODO(ajm): improve how this works, possibly inside AECM.
// This is kind of hacked up.
- const int16_t* noisy = audio->low_pass_reference(i);
- const int16_t* clean = audio->split_bands_const(i)[kBand0To8kHz];
+ RTC_DCHECK_LT(capture, low_pass_reference_.size());
+ const int16_t* noisy =
+ reference_copied_ ? low_pass_reference_[capture].data() : nullptr;
+
+ RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
+ audio->num_frames_per_band());
+
+ std::array<int16_t, AudioBuffer::kMaxSplitFrameLength> split_bands_data;
+ int16_t* split_bands = split_bands_data.data();
+ const int16_t* clean = split_bands_data.data();
+ if (audio->split_bands(capture)[kBand0To8kHz]) {
+ FloatS16ToS16(audio->split_bands(capture)[kBand0To8kHz],
+ audio->num_frames_per_band(), split_bands_data.data());
+ } else {
+ clean = nullptr;
+ split_bands = nullptr;
+ }
+
if (noisy == NULL) {
noisy = clean;
clean = NULL;
}
- for (int j = 0; j < apm_->num_reverse_channels(); j++) {
- Handle* my_handle = static_cast<Handle*>(handle(handle_index));
- err = WebRtcAecm_Process(
- my_handle,
- noisy,
- clean,
- audio->split_bands(i)[kBand0To8kHz],
- audio->num_frames_per_band(),
- apm_->stream_delay_ms());
-
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle); // TODO(ajm): warning possible?
+ for (size_t render = 0; render < stream_properties_->num_reverse_channels;
+ ++render) {
+ err = WebRtcAecm_Process(cancellers_[handle_index]->state(), noisy, clean,
+ split_bands, audio->num_frames_per_band(),
+ stream_delay_ms);
+
+ if (split_bands) {
+ S16ToFloatS16(split_bands, audio->num_frames_per_band(),
+ audio->split_bands(capture)[kBand0To8kHz]);
+ }
+
+ if (err != AudioProcessing::kNoError) {
+ return MapError(err);
}
- handle_index++;
+ ++handle_index;
+ }
+ for (size_t band = 1u; band < audio->num_bands(); ++band) {
+ memset(audio->split_bands_f(capture)[band], 0,
+ audio->num_frames_per_band() *
+ sizeof(audio->split_bands_f(capture)[band][0]));
}
}
-
- return apm_->kNoError;
-}
-
-int EchoControlMobileImpl::Enable(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- // Ensure AEC and AECM are not both enabled.
- if (enable && apm_->echo_cancellation()->is_enabled()) {
- return apm_->kBadParameterError;
- }
-
- return EnableComponent(enable);
-}
-
-bool EchoControlMobileImpl::is_enabled() const {
- return is_component_enabled();
+ return AudioProcessing::kNoError;
}
int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) {
- CriticalSectionScoped crit_scoped(crit_);
if (MapSetting(mode) == -1) {
- return apm_->kBadParameterError;
+ return AudioProcessing::kBadParameterError;
}
-
routing_mode_ = mode;
return Configure();
}
-EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode()
- const {
+EchoControlMobileImpl::RoutingMode EchoControlMobileImpl::routing_mode() const {
return routing_mode_;
}
int EchoControlMobileImpl::enable_comfort_noise(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
comfort_noise_enabled_ = enable;
return Configure();
}
@@ -194,101 +241,46 @@ bool EchoControlMobileImpl::is_comfort_noise_enabled() const {
return comfort_noise_enabled_;
}
-int EchoControlMobileImpl::SetEchoPath(const void* echo_path,
- size_t size_bytes) {
- CriticalSectionScoped crit_scoped(crit_);
- if (echo_path == NULL) {
- return apm_->kNullPointerError;
- }
- if (size_bytes != echo_path_size_bytes()) {
- // Size mismatch
- return apm_->kBadParameterError;
- }
-
- if (external_echo_path_ == NULL) {
- external_echo_path_ = new unsigned char[size_bytes];
- }
- memcpy(external_echo_path_, echo_path, size_bytes);
-
- return Initialize();
-}
-
-int EchoControlMobileImpl::GetEchoPath(void* echo_path,
- size_t size_bytes) const {
- CriticalSectionScoped crit_scoped(crit_);
- if (echo_path == NULL) {
- return apm_->kNullPointerError;
- }
- if (size_bytes != echo_path_size_bytes()) {
- // Size mismatch
- return apm_->kBadParameterError;
- }
- if (!is_component_enabled()) {
- return apm_->kNotEnabledError;
- }
-
- // Get the echo path from the first channel
- Handle* my_handle = static_cast<Handle*>(handle(0));
- if (WebRtcAecm_GetEchoPath(my_handle, echo_path, size_bytes) != 0) {
- return GetHandleError(my_handle);
- }
-
- return apm_->kNoError;
-}
-
-int EchoControlMobileImpl::Initialize() {
- if (!is_component_enabled()) {
- return apm_->kNoError;
- }
-
- if (apm_->proc_sample_rate_hz() > apm_->kSampleRate16kHz) {
- LOG(LS_ERROR) << "AECM only supports 16 kHz or lower sample rates";
- return apm_->kBadSampleRateError;
+void EchoControlMobileImpl::Initialize(int sample_rate_hz,
+ size_t num_reverse_channels,
+ size_t num_output_channels) {
+ low_pass_reference_.resize(num_output_channels);
+ for (auto& reference : low_pass_reference_) {
+ reference.fill(0);
}
- return ProcessingComponent::Initialize();
-}
+ stream_properties_.reset(new StreamProperties(
+ sample_rate_hz, num_reverse_channels, num_output_channels));
-void* EchoControlMobileImpl::CreateHandle() const {
- return WebRtcAecm_Create();
-}
+ // AECM only supports 16 kHz or lower sample rates.
+ RTC_DCHECK_LE(stream_properties_->sample_rate_hz,
+ AudioProcessing::kSampleRate16kHz);
-void EchoControlMobileImpl::DestroyHandle(void* handle) const {
- WebRtcAecm_Free(static_cast<Handle*>(handle));
-}
+ cancellers_.resize(
+ NumCancellersRequired(stream_properties_->num_output_channels,
+ stream_properties_->num_reverse_channels));
-int EchoControlMobileImpl::InitializeHandle(void* handle) const {
- assert(handle != NULL);
- Handle* my_handle = static_cast<Handle*>(handle);
- if (WebRtcAecm_Init(my_handle, apm_->proc_sample_rate_hz()) != 0) {
- return GetHandleError(my_handle);
- }
- if (external_echo_path_ != NULL) {
- if (WebRtcAecm_InitEchoPath(my_handle,
- external_echo_path_,
- echo_path_size_bytes()) != 0) {
- return GetHandleError(my_handle);
+ for (auto& canceller : cancellers_) {
+ if (!canceller) {
+ canceller.reset(new Canceller());
}
+ canceller->Initialize(sample_rate_hz);
}
-
- return apm_->kNoError;
+ Configure();
}
-int EchoControlMobileImpl::ConfigureHandle(void* handle) const {
+int EchoControlMobileImpl::Configure() {
AecmConfig config;
config.cngMode = comfort_noise_enabled_;
config.echoMode = MapSetting(routing_mode_);
-
- return WebRtcAecm_set_config(static_cast<Handle*>(handle), config);
-}
-
-int EchoControlMobileImpl::num_handles_required() const {
- return apm_->num_output_channels() *
- apm_->num_reverse_channels();
+ int error = AudioProcessing::kNoError;
+ for (auto& canceller : cancellers_) {
+ int handle_error = WebRtcAecm_set_config(canceller->state(), config);
+ if (handle_error != AudioProcessing::kNoError) {
+ error = handle_error;
+ }
+ }
+ return error;
}
-int EchoControlMobileImpl::GetHandleError(void* handle) const {
- assert(handle != NULL);
- return MapError(WebRtcAecm_get_error_code(static_cast<Handle*>(handle)));
-}
} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/echo_control_mobile_impl.h b/webrtc/modules/audio_processing/echo_control_mobile_impl.h
index da70225..23f3c06 100644
--- a/webrtc/modules/audio_processing/echo_control_mobile_impl.h
+++ b/webrtc/modules/audio_processing/echo_control_mobile_impl.h
@@ -8,57 +8,79 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_
+#ifndef MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_
+#define MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/processing_component.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
namespace webrtc {
class AudioBuffer;
-class CriticalSectionWrapper;
-class EchoControlMobileImpl : public EchoControlMobile,
- public ProcessingComponent {
+// The acoustic echo control for mobile (AECM) component is a low complexity
+// robust option intended for use on mobile devices.
+class EchoControlMobileImpl {
public:
- EchoControlMobileImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit);
- virtual ~EchoControlMobileImpl();
+ EchoControlMobileImpl();
+
+ ~EchoControlMobileImpl();
+
+ // Recommended settings for particular audio routes. In general, the louder
+ // the echo is expected to be, the higher this value should be set. The
+ // preferred setting may vary from device to device.
+ enum RoutingMode {
+ kQuietEarpieceOrHeadset,
+ kEarpiece,
+ kLoudEarpiece,
+ kSpeakerphone,
+ kLoudSpeakerphone
+ };
+
+ // Sets echo control appropriate for the audio routing |mode| on the device.
+ // It can and should be updated during a call if the audio routing changes.
+ int set_routing_mode(RoutingMode mode);
+ RoutingMode routing_mode() const;
- int ProcessRenderAudio(const AudioBuffer* audio);
- int ProcessCaptureAudio(AudioBuffer* audio);
+ // Comfort noise replaces suppressed background noise to maintain a
+ // consistent signal level.
+ int enable_comfort_noise(bool enable);
+ bool is_comfort_noise_enabled() const;
- // EchoControlMobile implementation.
- bool is_enabled() const override;
- RoutingMode routing_mode() const override;
- bool is_comfort_noise_enabled() const override;
+ void ProcessRenderAudio(rtc::ArrayView<const int16_t> packed_render_audio);
+ int ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms);
- // ProcessingComponent implementation.
- int Initialize() override;
+ void Initialize(int sample_rate_hz,
+ size_t num_reverse_channels,
+ size_t num_output_channels);
+
+ static void PackRenderAudioBuffer(const AudioBuffer* audio,
+ size_t num_output_channels,
+ size_t num_channels,
+ std::vector<int16_t>* packed_buffer);
+
+ static size_t NumCancellersRequired(size_t num_output_channels,
+ size_t num_reverse_channels);
private:
- // EchoControlMobile implementation.
- int Enable(bool enable) override;
- int set_routing_mode(RoutingMode mode) override;
- int enable_comfort_noise(bool enable) override;
- int SetEchoPath(const void* echo_path, size_t size_bytes) override;
- int GetEchoPath(void* echo_path, size_t size_bytes) const override;
-
- // ProcessingComponent implementation.
- void* CreateHandle() const override;
- int InitializeHandle(void* handle) const override;
- int ConfigureHandle(void* handle) const override;
- void DestroyHandle(void* handle) const override;
- int num_handles_required() const override;
- int GetHandleError(void* handle) const override;
-
- const AudioProcessing* apm_;
- CriticalSectionWrapper* crit_;
+ class Canceller;
+ struct StreamProperties;
+
+ int Configure();
+
RoutingMode routing_mode_;
bool comfort_noise_enabled_;
- unsigned char* external_echo_path_;
+
+ std::vector<std::unique_ptr<Canceller>> cancellers_;
+ std::unique_ptr<StreamProperties> stream_properties_;
+ std::vector<std::array<int16_t, 160>> low_pass_reference_;
+ bool reference_copied_ = false;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_
+#endif // MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_
diff --git a/webrtc/modules/audio_processing/echo_detector/circular_buffer.cc b/webrtc/modules/audio_processing/echo_detector/circular_buffer.cc
new file mode 100644
index 0000000..a6d10ed
--- /dev/null
+++ b/webrtc/modules/audio_processing/echo_detector/circular_buffer.cc
@@ -0,0 +1,49 @@
+/*
+ * 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/audio_processing/echo_detector/circular_buffer.h"
+
+#include <algorithm>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+CircularBuffer::CircularBuffer(size_t size) : buffer_(size) {}
+CircularBuffer::~CircularBuffer() = default;
+
+void CircularBuffer::Push(float value) {
+ buffer_[next_insertion_index_] = value;
+ ++next_insertion_index_;
+ next_insertion_index_ %= buffer_.size();
+ RTC_DCHECK_LT(next_insertion_index_, buffer_.size());
+ nr_elements_in_buffer_ = std::min(nr_elements_in_buffer_ + 1, buffer_.size());
+ RTC_DCHECK_LE(nr_elements_in_buffer_, buffer_.size());
+}
+
+absl::optional<float> CircularBuffer::Pop() {
+ if (nr_elements_in_buffer_ == 0) {
+ return absl::nullopt;
+ }
+ const size_t index =
+ (buffer_.size() + next_insertion_index_ - nr_elements_in_buffer_) %
+ buffer_.size();
+ RTC_DCHECK_LT(index, buffer_.size());
+ --nr_elements_in_buffer_;
+ return buffer_[index];
+}
+
+void CircularBuffer::Clear() {
+ std::fill(buffer_.begin(), buffer_.end(), 0.f);
+ next_insertion_index_ = 0;
+ nr_elements_in_buffer_ = 0;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/echo_detector/circular_buffer.h b/webrtc/modules/audio_processing/echo_detector/circular_buffer.h
new file mode 100644
index 0000000..db1aeae
--- /dev/null
+++ b/webrtc/modules/audio_processing/echo_detector/circular_buffer.h
@@ -0,0 +1,44 @@
+/*
+ * 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_AUDIO_PROCESSING_ECHO_DETECTOR_CIRCULAR_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_CIRCULAR_BUFFER_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "absl/types/optional.h"
+
+namespace webrtc {
+
+// Ring buffer containing floating point values.
+struct CircularBuffer {
+ public:
+ explicit CircularBuffer(size_t size);
+ ~CircularBuffer();
+
+ void Push(float value);
+ absl::optional<float> Pop();
+ size_t Size() const { return nr_elements_in_buffer_; }
+ // This function fills the buffer with zeros, but does not change its size.
+ void Clear();
+
+ private:
+ std::vector<float> buffer_;
+ size_t next_insertion_index_ = 0;
+ // This is the number of elements that have been pushed into the circular
+ // buffer, not the allocated buffer size.
+ size_t nr_elements_in_buffer_ = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_CIRCULAR_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.cc b/webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.cc
new file mode 100644
index 0000000..a857403
--- /dev/null
+++ b/webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.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/audio_processing/echo_detector/mean_variance_estimator.h"
+
+#include <math.h>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+// Parameter controlling the adaptation speed.
+constexpr float kAlpha = 0.001f;
+
+} // namespace
+
+void MeanVarianceEstimator::Update(float value) {
+ mean_ = (1.f - kAlpha) * mean_ + kAlpha * value;
+ variance_ =
+ (1.f - kAlpha) * variance_ + kAlpha * (value - mean_) * (value - mean_);
+ RTC_DCHECK(isfinite(mean_));
+ RTC_DCHECK(isfinite(variance_));
+}
+
+float MeanVarianceEstimator::std_deviation() const {
+ RTC_DCHECK_GE(variance_, 0.f);
+ return sqrtf(variance_);
+}
+
+float MeanVarianceEstimator::mean() const {
+ return mean_;
+}
+
+void MeanVarianceEstimator::Clear() {
+ mean_ = 0.f;
+ variance_ = 0.f;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.h b/webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.h
new file mode 100644
index 0000000..7f793df
--- /dev/null
+++ b/webrtc/modules/audio_processing/echo_detector/mean_variance_estimator.h
@@ -0,0 +1,33 @@
+/*
+ * 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_AUDIO_PROCESSING_ECHO_DETECTOR_MEAN_VARIANCE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MEAN_VARIANCE_ESTIMATOR_H_
+
+namespace webrtc {
+
+// This class iteratively estimates the mean and variance of a signal.
+class MeanVarianceEstimator {
+ public:
+ void Update(float value);
+ float std_deviation() const;
+ float mean() const;
+ void Clear();
+
+ private:
+ // Estimate of the expected value of the input values.
+ float mean_ = 0.f;
+ // Estimate of the variance of the input values.
+ float variance_ = 0.f;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MEAN_VARIANCE_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/echo_detector/moving_max.cc b/webrtc/modules/audio_processing/echo_detector/moving_max.cc
new file mode 100644
index 0000000..3054e98
--- /dev/null
+++ b/webrtc/modules/audio_processing/echo_detector/moving_max.cc
@@ -0,0 +1,52 @@
+/*
+ * 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/audio_processing/echo_detector/moving_max.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+// Parameter for controlling how fast the estimated maximum decays after the
+// previous maximum is no longer valid. With a value of 0.99, the maximum will
+// decay to 1% of its former value after 460 updates.
+constexpr float kDecayFactor = 0.99f;
+
+} // namespace
+
+MovingMax::MovingMax(size_t window_size) : window_size_(window_size) {
+ RTC_DCHECK_GT(window_size, 0);
+}
+
+MovingMax::~MovingMax() {}
+
+void MovingMax::Update(float value) {
+ if (counter_ >= window_size_ - 1) {
+ max_value_ *= kDecayFactor;
+ } else {
+ ++counter_;
+ }
+ if (value > max_value_) {
+ max_value_ = value;
+ counter_ = 0;
+ }
+}
+
+float MovingMax::max() const {
+ return max_value_;
+}
+
+void MovingMax::Clear() {
+ max_value_ = 0.f;
+ counter_ = 0;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/echo_detector/moving_max.h b/webrtc/modules/audio_processing/echo_detector/moving_max.h
new file mode 100644
index 0000000..f7d8ee8
--- /dev/null
+++ b/webrtc/modules/audio_processing/echo_detector/moving_max.h
@@ -0,0 +1,36 @@
+/*
+ * 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_AUDIO_PROCESSING_ECHO_DETECTOR_MOVING_MAX_H_
+#define MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MOVING_MAX_H_
+
+#include <stddef.h>
+
+namespace webrtc {
+
+class MovingMax {
+ public:
+ explicit MovingMax(size_t window_size);
+ ~MovingMax();
+
+ void Update(float value);
+ float max() const;
+ // Reset all of the state in this class.
+ void Clear();
+
+ private:
+ float max_value_ = 0.f;
+ size_t counter_ = 0;
+ size_t window_size_ = 1;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_MOVING_MAX_H_
diff --git a/webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.cc b/webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.cc
new file mode 100644
index 0000000..8ec9fe9
--- /dev/null
+++ b/webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.cc
@@ -0,0 +1,43 @@
+/*
+ * 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/audio_processing/echo_detector/normalized_covariance_estimator.h"
+
+#include <math.h>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace {
+
+// Parameter controlling the adaptation speed.
+constexpr float kAlpha = 0.001f;
+
+} // namespace
+
+void NormalizedCovarianceEstimator::Update(float x,
+ float x_mean,
+ float x_sigma,
+ float y,
+ float y_mean,
+ float y_sigma) {
+ covariance_ =
+ (1.f - kAlpha) * covariance_ + kAlpha * (x - x_mean) * (y - y_mean);
+ normalized_cross_correlation_ = covariance_ / (x_sigma * y_sigma + .0001f);
+ RTC_DCHECK(isfinite(covariance_));
+ RTC_DCHECK(isfinite(normalized_cross_correlation_));
+}
+
+void NormalizedCovarianceEstimator::Clear() {
+ covariance_ = 0.f;
+ normalized_cross_correlation_ = 0.f;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.h b/webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.h
new file mode 100644
index 0000000..e3c36d8
--- /dev/null
+++ b/webrtc/modules/audio_processing/echo_detector/normalized_covariance_estimator.h
@@ -0,0 +1,43 @@
+/*
+ * 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_AUDIO_PROCESSING_ECHO_DETECTOR_NORMALIZED_COVARIANCE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_NORMALIZED_COVARIANCE_ESTIMATOR_H_
+
+namespace webrtc {
+
+// This class iteratively estimates the normalized covariance between two
+// signals.
+class NormalizedCovarianceEstimator {
+ public:
+ void Update(float x,
+ float x_mean,
+ float x_var,
+ float y,
+ float y_mean,
+ float y_var);
+ // This function returns an estimate of the Pearson product-moment correlation
+ // coefficient of the two signals.
+ float normalized_cross_correlation() const {
+ return normalized_cross_correlation_;
+ }
+ float covariance() const { return covariance_; }
+ // This function resets the estimated values to zero.
+ void Clear();
+
+ private:
+ float normalized_cross_correlation_ = 0.f;
+ // Estimate of the covariance value.
+ float covariance_ = 0.f;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_ECHO_DETECTOR_NORMALIZED_COVARIANCE_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/gain_control_impl.cc b/webrtc/modules/audio_processing/gain_control_impl.cc
index 3b1537e..b5454c0 100644
--- a/webrtc/modules/audio_processing/gain_control_impl.cc
+++ b/webrtc/modules/audio_processing/gain_control_impl.cc
@@ -8,13 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/gain_control_impl.h"
+#include "modules/audio_processing/gain_control_impl.h"
-#include <assert.h>
+#include <cstdint>
-#include "webrtc/modules/audio_processing/audio_buffer.h"
-#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "absl/types/optional.h"
+#include "modules/audio_processing/agc/legacy/gain_control.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
namespace webrtc {
@@ -30,314 +35,361 @@ int16_t MapSetting(GainControl::Mode mode) {
case GainControl::kFixedDigital:
return kAgcModeFixedDigital;
}
- assert(false);
+ RTC_NOTREACHED();
return -1;
}
-} // namespace
-GainControlImpl::GainControlImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit)
- : ProcessingComponent(),
- apm_(apm),
- crit_(crit),
- mode_(kAdaptiveAnalog),
- minimum_capture_level_(0),
- maximum_capture_level_(255),
- limiter_enabled_(true),
- target_level_dbfs_(3),
- compression_gain_db_(9),
- analog_capture_level_(0),
- was_analog_level_set_(false),
- stream_is_saturated_(false) {}
-
-GainControlImpl::~GainControlImpl() {}
-
-int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
+// Checks whether the legacy digital gain application should be used.
+bool UseLegacyDigitalGainApplier() {
+ return field_trial::IsEnabled("WebRTC-UseLegacyDigitalGainApplier");
+}
+
+// Floating point variant of WebRtcAgc_Process.
+void ApplyDigitalGain(const int32_t gains[11],
+ size_t num_bands,
+ float* const* out) {
+ constexpr float kScaling = 1.f / 65536.f;
+ constexpr int kNumSubSections = 16;
+ constexpr float kOneByNumSubSections = 1.f / kNumSubSections;
+
+ float gains_scaled[11];
+ for (int k = 0; k < 11; ++k) {
+ gains_scaled[k] = gains[k] * kScaling;
}
- assert(audio->num_frames_per_band() <= 160);
+ for (size_t b = 0; b < num_bands; ++b) {
+ float* out_band = out[b];
+ for (int k = 0, sample = 0; k < 10; ++k) {
+ const float delta =
+ (gains_scaled[k + 1] - gains_scaled[k]) * kOneByNumSubSections;
+ float gain = gains_scaled[k];
+ for (int n = 0; n < kNumSubSections; ++n, ++sample) {
+ RTC_DCHECK_EQ(k * kNumSubSections + n, sample);
+ out_band[sample] *= gain;
+ out_band[sample] =
+ std::min(32767.f, std::max(-32768.f, out_band[sample]));
+ gain += delta;
+ }
+ }
+ }
+}
- for (int i = 0; i < num_handles(); i++) {
- Handle* my_handle = static_cast<Handle*>(handle(i));
- int err = WebRtcAgc_AddFarend(
- my_handle,
- audio->mixed_low_pass_data(),
- audio->num_frames_per_band());
+} // namespace
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle);
- }
+struct GainControlImpl::MonoAgcState {
+ MonoAgcState() {
+ state = WebRtcAgc_Create();
+ RTC_CHECK(state);
}
- return apm_->kNoError;
+ ~MonoAgcState() {
+ RTC_DCHECK(state);
+ WebRtcAgc_Free(state);
+ }
+
+ MonoAgcState(const MonoAgcState&) = delete;
+ MonoAgcState& operator=(const MonoAgcState&) = delete;
+ int32_t gains[11];
+ Handle* state;
+};
+
+int GainControlImpl::instance_counter_ = 0;
+
+GainControlImpl::GainControlImpl()
+ : data_dumper_(new ApmDataDumper(instance_counter_)),
+ use_legacy_gain_applier_(UseLegacyDigitalGainApplier()),
+ mode_(kAdaptiveAnalog),
+ minimum_capture_level_(0),
+ maximum_capture_level_(255),
+ limiter_enabled_(true),
+ target_level_dbfs_(3),
+ compression_gain_db_(9),
+ analog_capture_level_(0),
+ was_analog_level_set_(false),
+ stream_is_saturated_(false) {}
+
+GainControlImpl::~GainControlImpl() = default;
+
+void GainControlImpl::ProcessRenderAudio(
+ rtc::ArrayView<const int16_t> packed_render_audio) {
+ for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
+ WebRtcAgc_AddFarend(mono_agcs_[ch]->state, packed_render_audio.data(),
+ packed_render_audio.size());
+ }
}
-int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
+void GainControlImpl::PackRenderAudioBuffer(
+ const AudioBuffer& audio,
+ std::vector<int16_t>* packed_buffer) {
+ RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
+ std::array<int16_t, AudioBuffer::kMaxSplitFrameLength>
+ mixed_16_kHz_render_data;
+ rtc::ArrayView<const int16_t> mixed_16_kHz_render(
+ mixed_16_kHz_render_data.data(), audio.num_frames_per_band());
+ if (audio.num_channels() == 1) {
+ FloatS16ToS16(audio.split_bands_const(0)[kBand0To8kHz],
+ audio.num_frames_per_band(), mixed_16_kHz_render_data.data());
+ } else {
+ const int num_channels = static_cast<int>(audio.num_channels());
+ for (size_t i = 0; i < audio.num_frames_per_band(); ++i) {
+ int32_t sum = 0;
+ for (int ch = 0; ch < num_channels; ++ch) {
+ sum += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[ch][i]);
+ }
+ mixed_16_kHz_render_data[i] = sum / num_channels;
+ }
}
- assert(audio->num_frames_per_band() <= 160);
- assert(audio->num_channels() == num_handles());
+ packed_buffer->clear();
+ packed_buffer->insert(
+ packed_buffer->end(), mixed_16_kHz_render.data(),
+ (mixed_16_kHz_render.data() + audio.num_frames_per_band()));
+}
+
+int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
+ RTC_DCHECK(num_proc_channels_);
+ RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
+ RTC_DCHECK_EQ(audio.num_channels(), *num_proc_channels_);
+ RTC_DCHECK_LE(*num_proc_channels_, mono_agcs_.size());
- int err = apm_->kNoError;
+ int16_t split_band_data[AudioBuffer::kMaxNumBands]
+ [AudioBuffer::kMaxSplitFrameLength];
+ int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
+ split_band_data[0], split_band_data[1], split_band_data[2]};
if (mode_ == kAdaptiveAnalog) {
- capture_levels_.assign(num_handles(), analog_capture_level_);
- for (int i = 0; i < num_handles(); i++) {
- Handle* my_handle = static_cast<Handle*>(handle(i));
- err = WebRtcAgc_AddMic(
- my_handle,
- audio->split_bands(i),
- audio->num_bands(),
- audio->num_frames_per_band());
-
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle);
+ for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
+ capture_levels_[ch] = analog_capture_level_;
+
+ audio.ExportSplitChannelData(ch, split_bands);
+
+ int err =
+ WebRtcAgc_AddMic(mono_agcs_[ch]->state, split_bands,
+ audio.num_bands(), audio.num_frames_per_band());
+
+ if (err != AudioProcessing::kNoError) {
+ return AudioProcessing::kUnspecifiedError;
}
}
} else if (mode_ == kAdaptiveDigital) {
-
- for (int i = 0; i < num_handles(); i++) {
- Handle* my_handle = static_cast<Handle*>(handle(i));
+ for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
int32_t capture_level_out = 0;
- err = WebRtcAgc_VirtualMic(
- my_handle,
- audio->split_bands(i),
- audio->num_bands(),
- audio->num_frames_per_band(),
- analog_capture_level_,
- &capture_level_out);
+ audio.ExportSplitChannelData(ch, split_bands);
- capture_levels_[i] = capture_level_out;
+ int err =
+ WebRtcAgc_VirtualMic(mono_agcs_[ch]->state, split_bands,
+ audio.num_bands(), audio.num_frames_per_band(),
+ analog_capture_level_, &capture_level_out);
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle);
- }
+ capture_levels_[ch] = capture_level_out;
+ if (err != AudioProcessing::kNoError) {
+ return AudioProcessing::kUnspecifiedError;
+ }
}
}
- return apm_->kNoError;
+ return AudioProcessing::kNoError;
}
-int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
- }
-
+int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
+ bool stream_has_echo) {
if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
- return apm_->kStreamParameterNotSetError;
+ return AudioProcessing::kStreamParameterNotSetError;
}
- assert(audio->num_frames_per_band() <= 160);
- assert(audio->num_channels() == num_handles());
+ RTC_DCHECK(num_proc_channels_);
+ RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
+ audio->num_frames_per_band());
+ RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
stream_is_saturated_ = false;
- for (int i = 0; i < num_handles(); i++) {
- Handle* my_handle = static_cast<Handle*>(handle(i));
- int32_t capture_level_out = 0;
+ bool error_reported = false;
+ for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
+ int16_t split_band_data[AudioBuffer::kMaxNumBands]
+ [AudioBuffer::kMaxSplitFrameLength];
+ int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
+ split_band_data[0], split_band_data[1], split_band_data[2]};
+ audio->ExportSplitChannelData(ch, split_bands);
+
+ // The call to stream_has_echo() is ok from a deadlock perspective
+ // as the capture lock is allready held.
+ int32_t new_capture_level = 0;
uint8_t saturation_warning = 0;
+ int err_analyze = WebRtcAgc_Analyze(
+ mono_agcs_[ch]->state, split_bands, audio->num_bands(),
+ audio->num_frames_per_band(), capture_levels_[ch], &new_capture_level,
+ stream_has_echo, &saturation_warning, mono_agcs_[ch]->gains);
+ capture_levels_[ch] = new_capture_level;
+
+ error_reported = error_reported || err_analyze != AudioProcessing::kNoError;
+
+ stream_is_saturated_ = stream_is_saturated_ || saturation_warning == 1;
+ }
- int err = WebRtcAgc_Process(
- my_handle,
- audio->split_bands_const(i),
- audio->num_bands(),
- audio->num_frames_per_band(),
- audio->split_bands(i),
- capture_levels_[i],
- &capture_level_out,
- apm_->echo_cancellation()->stream_has_echo(),
- &saturation_warning);
-
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle);
+ // Choose the minimun gain for application
+ size_t index_to_apply = 0;
+ for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
+ if (mono_agcs_[index_to_apply]->gains[10] < mono_agcs_[ch]->gains[10]) {
+ index_to_apply = ch;
}
+ }
+
+ if (use_legacy_gain_applier_) {
+ for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
+ int16_t split_band_data[AudioBuffer::kMaxNumBands]
+ [AudioBuffer::kMaxSplitFrameLength];
+ int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
+ split_band_data[0], split_band_data[1], split_band_data[2]};
+ audio->ExportSplitChannelData(ch, split_bands);
- capture_levels_[i] = capture_level_out;
- if (saturation_warning == 1) {
- stream_is_saturated_ = true;
+ int err_process = WebRtcAgc_Process(
+ mono_agcs_[ch]->state, mono_agcs_[index_to_apply]->gains, split_bands,
+ audio->num_bands(), split_bands);
+ RTC_DCHECK_EQ(err_process, 0);
+
+ audio->ImportSplitChannelData(ch, split_bands);
+ }
+ } else {
+ for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
+ ApplyDigitalGain(mono_agcs_[index_to_apply]->gains, audio->num_bands(),
+ audio->split_bands(ch));
}
}
+ RTC_DCHECK_LT(0ul, *num_proc_channels_);
if (mode_ == kAdaptiveAnalog) {
- // Take the analog level to be the average across the handles.
- analog_capture_level_ = 0;
- for (int i = 0; i < num_handles(); i++) {
- analog_capture_level_ += capture_levels_[i];
+ // Take the analog level to be the minimum accross all channels.
+ analog_capture_level_ = capture_levels_[0];
+ for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
+ analog_capture_level_ =
+ std::min(analog_capture_level_, capture_levels_[ch]);
}
+ }
- analog_capture_level_ /= num_handles();
+ if (error_reported) {
+ return AudioProcessing::kUnspecifiedError;
}
was_analog_level_set_ = false;
- return apm_->kNoError;
+
+ return AudioProcessing::kNoError;
}
+
// TODO(ajm): ensure this is called under kAdaptiveAnalog.
int GainControlImpl::set_stream_analog_level(int level) {
- CriticalSectionScoped crit_scoped(crit_);
+ data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level);
+
was_analog_level_set_ = true;
if (level < minimum_capture_level_ || level > maximum_capture_level_) {
- return apm_->kBadParameterError;
+ return AudioProcessing::kBadParameterError;
}
analog_capture_level_ = level;
- return apm_->kNoError;
+ return AudioProcessing::kNoError;
}
-int GainControlImpl::stream_analog_level() {
- // TODO(ajm): enable this assertion?
- //assert(mode_ == kAdaptiveAnalog);
-
+int GainControlImpl::stream_analog_level() const {
+ data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
+ &analog_capture_level_);
return analog_capture_level_;
}
-int GainControlImpl::Enable(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- return EnableComponent(enable);
-}
-
-bool GainControlImpl::is_enabled() const {
- return is_component_enabled();
-}
-
int GainControlImpl::set_mode(Mode mode) {
- CriticalSectionScoped crit_scoped(crit_);
if (MapSetting(mode) == -1) {
- return apm_->kBadParameterError;
+ return AudioProcessing::kBadParameterError;
}
mode_ = mode;
- return Initialize();
+ RTC_DCHECK(num_proc_channels_);
+ RTC_DCHECK(sample_rate_hz_);
+ Initialize(*num_proc_channels_, *sample_rate_hz_);
+ return AudioProcessing::kNoError;
}
-GainControl::Mode GainControlImpl::mode() const {
- return mode_;
-}
-
-int GainControlImpl::set_analog_level_limits(int minimum,
- int maximum) {
- CriticalSectionScoped crit_scoped(crit_);
- if (minimum < 0) {
- return apm_->kBadParameterError;
- }
- if (maximum > 65535) {
- return apm_->kBadParameterError;
- }
-
- if (maximum < minimum) {
- return apm_->kBadParameterError;
+int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
+ if (minimum < 0 || maximum > 65535 || maximum < minimum) {
+ return AudioProcessing::kBadParameterError;
}
minimum_capture_level_ = minimum;
maximum_capture_level_ = maximum;
- return Initialize();
-}
-
-int GainControlImpl::analog_level_minimum() const {
- return minimum_capture_level_;
-}
-
-int GainControlImpl::analog_level_maximum() const {
- return maximum_capture_level_;
+ RTC_DCHECK(num_proc_channels_);
+ RTC_DCHECK(sample_rate_hz_);
+ Initialize(*num_proc_channels_, *sample_rate_hz_);
+ return AudioProcessing::kNoError;
}
-bool GainControlImpl::stream_is_saturated() const {
- return stream_is_saturated_;
-}
int GainControlImpl::set_target_level_dbfs(int level) {
- CriticalSectionScoped crit_scoped(crit_);
if (level > 31 || level < 0) {
- return apm_->kBadParameterError;
+ return AudioProcessing::kBadParameterError;
}
-
target_level_dbfs_ = level;
return Configure();
}
-int GainControlImpl::target_level_dbfs() const {
- return target_level_dbfs_;
-}
-
int GainControlImpl::set_compression_gain_db(int gain) {
- CriticalSectionScoped crit_scoped(crit_);
if (gain < 0 || gain > 90) {
- return apm_->kBadParameterError;
+ RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << gain << ") failed.";
+ return AudioProcessing::kBadParameterError;
}
-
compression_gain_db_ = gain;
return Configure();
}
-int GainControlImpl::compression_gain_db() const {
- return compression_gain_db_;
-}
-
int GainControlImpl::enable_limiter(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
limiter_enabled_ = enable;
return Configure();
}
-bool GainControlImpl::is_limiter_enabled() const {
- return limiter_enabled_;
-}
+void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
+ data_dumper_->InitiateNewSetOfRecordings();
-int GainControlImpl::Initialize() {
- int err = ProcessingComponent::Initialize();
- if (err != apm_->kNoError || !is_component_enabled()) {
- return err;
- }
+ RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
+ sample_rate_hz == 48000);
- capture_levels_.assign(num_handles(), analog_capture_level_);
- return apm_->kNoError;
-}
+ num_proc_channels_ = num_proc_channels;
+ sample_rate_hz_ = sample_rate_hz;
-void* GainControlImpl::CreateHandle() const {
- return WebRtcAgc_Create();
-}
+ mono_agcs_.resize(*num_proc_channels_);
+ capture_levels_.resize(*num_proc_channels_);
+ for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
+ if (!mono_agcs_[ch]) {
+ mono_agcs_[ch].reset(new MonoAgcState());
+ }
-void GainControlImpl::DestroyHandle(void* handle) const {
- WebRtcAgc_Free(static_cast<Handle*>(handle));
-}
+ int error = WebRtcAgc_Init(mono_agcs_[ch]->state, minimum_capture_level_,
+ maximum_capture_level_, MapSetting(mode_),
+ *sample_rate_hz_);
+ RTC_DCHECK_EQ(error, 0);
+ capture_levels_[ch] = analog_capture_level_;
+ }
-int GainControlImpl::InitializeHandle(void* handle) const {
- return WebRtcAgc_Init(static_cast<Handle*>(handle),
- minimum_capture_level_,
- maximum_capture_level_,
- MapSetting(mode_),
- apm_->proc_sample_rate_hz());
+ Configure();
}
-int GainControlImpl::ConfigureHandle(void* handle) const {
+int GainControlImpl::Configure() {
WebRtcAgcConfig config;
// TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
// change the interface.
- //assert(target_level_dbfs_ <= 0);
- //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
+ // RTC_DCHECK_LE(target_level_dbfs_, 0);
+ // config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
- config.compressionGaindB =
- static_cast<int16_t>(compression_gain_db_);
+ config.compressionGaindB = static_cast<int16_t>(compression_gain_db_);
config.limiterEnable = limiter_enabled_;
- return WebRtcAgc_set_config(static_cast<Handle*>(handle), config);
-}
-
-int GainControlImpl::num_handles_required() const {
- return apm_->num_output_channels();
-}
-
-int GainControlImpl::GetHandleError(void* handle) const {
- // The AGC has no get_error() function.
- // (Despite listing errors in its interface...)
- assert(handle != NULL);
- return apm_->kUnspecifiedError;
+ int error = AudioProcessing::kNoError;
+ for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
+ int error_ch = WebRtcAgc_set_config(mono_agcs_[ch]->state, config);
+ if (error_ch != AudioProcessing::kNoError) {
+ error = error_ch;
+ }
+ }
+ return error;
}
} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/gain_control_impl.h b/webrtc/modules/audio_processing/gain_control_impl.h
index f24d200..b65d697 100644
--- a/webrtc/modules/audio_processing/gain_control_impl.h
+++ b/webrtc/modules/audio_processing/gain_control_impl.h
@@ -8,75 +8,85 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_
+#ifndef MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_
+#define MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
#include <vector>
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/processing_component.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "modules/audio_processing/agc/gain_control.h"
namespace webrtc {
+class ApmDataDumper;
class AudioBuffer;
-class CriticalSectionWrapper;
-class GainControlImpl : public GainControl,
- public ProcessingComponent {
+class GainControlImpl : public GainControl {
public:
- GainControlImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit);
- virtual ~GainControlImpl();
+ GainControlImpl();
+ GainControlImpl(const GainControlImpl&) = delete;
+ GainControlImpl& operator=(const GainControlImpl&) = delete;
- int ProcessRenderAudio(AudioBuffer* audio);
- int AnalyzeCaptureAudio(AudioBuffer* audio);
- int ProcessCaptureAudio(AudioBuffer* audio);
+ ~GainControlImpl() override;
- // ProcessingComponent implementation.
- int Initialize() override;
+ void ProcessRenderAudio(rtc::ArrayView<const int16_t> packed_render_audio);
+ int AnalyzeCaptureAudio(const AudioBuffer& audio);
+ int ProcessCaptureAudio(AudioBuffer* audio, bool stream_has_echo);
- // GainControl implementation.
- bool is_enabled() const override;
- int stream_analog_level() override;
- bool is_limiter_enabled() const override;
- Mode mode() const override;
+ void Initialize(size_t num_proc_channels, int sample_rate_hz);
+
+ static void PackRenderAudioBuffer(const AudioBuffer& audio,
+ std::vector<int16_t>* packed_buffer);
- private:
// GainControl implementation.
- int Enable(bool enable) override;
- int set_stream_analog_level(int level) override;
+ int stream_analog_level() const override;
+ bool is_limiter_enabled() const override { return limiter_enabled_; }
+ Mode mode() const override { return mode_; }
int set_mode(Mode mode) override;
- int set_target_level_dbfs(int level) override;
- int target_level_dbfs() const override;
+ int compression_gain_db() const override { return compression_gain_db_; }
+ int set_analog_level_limits(int minimum, int maximum) override;
int set_compression_gain_db(int gain) override;
- int compression_gain_db() const override;
+ int set_target_level_dbfs(int level) override;
int enable_limiter(bool enable) override;
- int set_analog_level_limits(int minimum, int maximum) override;
- int analog_level_minimum() const override;
- int analog_level_maximum() const override;
- bool stream_is_saturated() const override;
-
- // ProcessingComponent implementation.
- void* CreateHandle() const override;
- int InitializeHandle(void* handle) const override;
- int ConfigureHandle(void* handle) const override;
- void DestroyHandle(void* handle) const override;
- int num_handles_required() const override;
- int GetHandleError(void* handle) const override;
-
- const AudioProcessing* apm_;
- CriticalSectionWrapper* crit_;
+ int set_stream_analog_level(int level) override;
+
+ private:
+ struct MonoAgcState;
+
+ // GainControl implementation.
+ int target_level_dbfs() const override { return target_level_dbfs_; }
+ int analog_level_minimum() const override { return minimum_capture_level_; }
+ int analog_level_maximum() const override { return maximum_capture_level_; }
+ bool stream_is_saturated() const override { return stream_is_saturated_; }
+
+ int Configure();
+
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+
+ const bool use_legacy_gain_applier_;
Mode mode_;
int minimum_capture_level_;
int maximum_capture_level_;
bool limiter_enabled_;
int target_level_dbfs_;
int compression_gain_db_;
- std::vector<int> capture_levels_;
- int analog_capture_level_;
+ int analog_capture_level_ = 0;
bool was_analog_level_set_;
bool stream_is_saturated_;
+
+ std::vector<std::unique_ptr<MonoAgcState>> mono_agcs_;
+ std::vector<int> capture_levels_;
+
+ absl::optional<size_t> num_proc_channels_;
+ absl::optional<int> sample_rate_hz_;
+
+ static int instance_counter_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_
+#endif // MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_
diff --git a/webrtc/modules/audio_processing/gain_controller2.cc b/webrtc/modules/audio_processing/gain_controller2.cc
new file mode 100644
index 0000000..8e71d40
--- /dev/null
+++ b/webrtc/modules/audio_processing/gain_controller2.cc
@@ -0,0 +1,138 @@
+/*
+ * 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/audio_processing/gain_controller2.h"
+
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/include/audio_frame_view.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+
+int GainController2::instance_count_ = 0;
+
+GainController2::GainController2()
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ gain_applier_(/*hard_clip_samples=*/false,
+ /*initial_gain_factor=*/0.f),
+ limiter_(static_cast<size_t>(48000), data_dumper_.get(), "Agc2") {
+ if (config_.adaptive_digital.enabled) {
+ adaptive_agc_.reset(new AdaptiveAgc(data_dumper_.get()));
+ }
+}
+
+GainController2::~GainController2() = default;
+
+void GainController2::Initialize(int sample_rate_hz) {
+ RTC_DCHECK(sample_rate_hz == AudioProcessing::kSampleRate8kHz ||
+ sample_rate_hz == AudioProcessing::kSampleRate16kHz ||
+ sample_rate_hz == AudioProcessing::kSampleRate32kHz ||
+ sample_rate_hz == AudioProcessing::kSampleRate48kHz);
+ limiter_.SetSampleRate(sample_rate_hz);
+ data_dumper_->InitiateNewSetOfRecordings();
+ data_dumper_->DumpRaw("sample_rate_hz", sample_rate_hz);
+}
+
+void GainController2::Process(AudioBuffer* audio) {
+ AudioFrameView<float> float_frame(audio->channels(), audio->num_channels(),
+ audio->num_frames());
+ // Apply fixed gain first, then the adaptive one.
+ gain_applier_.ApplyGain(float_frame);
+ if (adaptive_agc_) {
+ adaptive_agc_->Process(float_frame, limiter_.LastAudioLevel());
+ }
+ limiter_.Process(float_frame);
+}
+
+void GainController2::NotifyAnalogLevel(int level) {
+ if (analog_level_ != level && adaptive_agc_) {
+ adaptive_agc_->Reset();
+ }
+ analog_level_ = level;
+}
+
+void GainController2::ApplyConfig(
+ const AudioProcessing::Config::GainController2& config) {
+ RTC_DCHECK(Validate(config))
+ << " the invalid config was " << ToString(config);
+
+ config_ = config;
+ if (config.fixed_digital.gain_db != config_.fixed_digital.gain_db) {
+ // Reset the limiter to quickly react on abrupt level changes caused by
+ // large changes of the fixed gain.
+ limiter_.Reset();
+ }
+ gain_applier_.SetGainFactor(DbToRatio(config_.fixed_digital.gain_db));
+ if (config_.adaptive_digital.enabled) {
+ adaptive_agc_.reset(new AdaptiveAgc(data_dumper_.get(), config_));
+ } else {
+ adaptive_agc_.reset();
+ }
+}
+
+bool GainController2::Validate(
+ const AudioProcessing::Config::GainController2& config) {
+ return config.fixed_digital.gain_db >= 0.f &&
+ config.fixed_digital.gain_db < 50.f &&
+ config.adaptive_digital.extra_saturation_margin_db >= 0.f &&
+ config.adaptive_digital.extra_saturation_margin_db <= 100.f;
+}
+
+std::string GainController2::ToString(
+ const AudioProcessing::Config::GainController2& config) {
+ rtc::StringBuilder ss;
+ std::string adaptive_digital_level_estimator;
+ using LevelEstimatorType =
+ AudioProcessing::Config::GainController2::LevelEstimator;
+ switch (config.adaptive_digital.level_estimator) {
+ case LevelEstimatorType::kRms:
+ adaptive_digital_level_estimator = "RMS";
+ break;
+ case LevelEstimatorType::kPeak:
+ adaptive_digital_level_estimator = "peak";
+ break;
+ }
+ // clang-format off
+ // clang formatting doesn't respect custom nested style.
+ ss << "{"
+ "enabled: " << (config.enabled ? "true" : "false") << ", "
+ "fixed_digital: {gain_db: " << config.fixed_digital.gain_db << "}, "
+ "adaptive_digital: {"
+ "enabled: "
+ << (config.adaptive_digital.enabled ? "true" : "false") << ", "
+ "level_estimator: {"
+ "type: " << adaptive_digital_level_estimator << ", "
+ "adjacent_speech_frames_threshold: "
+ << config.adaptive_digital
+ .level_estimator_adjacent_speech_frames_threshold << ", "
+ "initial_saturation_margin_db: "
+ << config.adaptive_digital.initial_saturation_margin_db << ", "
+ "extra_saturation_margin_db: "
+ << config.adaptive_digital.extra_saturation_margin_db << "}, "
+ "gain_applier: {"
+ "adjacent_speech_frames_threshold: "
+ << config.adaptive_digital
+ .gain_applier_adjacent_speech_frames_threshold << ", "
+ "max_gain_change_db_per_second: "
+ << config.adaptive_digital.max_gain_change_db_per_second << ", "
+ "max_output_noise_level_dbfs: "
+ << config.adaptive_digital.max_output_noise_level_dbfs << "}"
+ "}"
+ "}";
+ // clang-format on
+ return ss.Release();
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/gain_controller2.h b/webrtc/modules/audio_processing/gain_controller2.h
new file mode 100644
index 0000000..7ed310e
--- /dev/null
+++ b/webrtc/modules/audio_processing/gain_controller2.h
@@ -0,0 +1,58 @@
+/*
+ * 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_AUDIO_PROCESSING_GAIN_CONTROLLER2_H_
+#define MODULES_AUDIO_PROCESSING_GAIN_CONTROLLER2_H_
+
+#include <memory>
+#include <string>
+
+#include "modules/audio_processing/agc2/adaptive_agc.h"
+#include "modules/audio_processing/agc2/gain_applier.h"
+#include "modules/audio_processing/agc2/limiter.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+class AudioBuffer;
+
+// Gain Controller 2 aims to automatically adjust levels by acting on the
+// microphone gain and/or applying digital gain.
+class GainController2 {
+ public:
+ GainController2();
+ ~GainController2();
+
+ void Initialize(int sample_rate_hz);
+ void Process(AudioBuffer* audio);
+ void NotifyAnalogLevel(int level);
+
+ void ApplyConfig(const AudioProcessing::Config::GainController2& config);
+ static bool Validate(const AudioProcessing::Config::GainController2& config);
+ static std::string ToString(
+ const AudioProcessing::Config::GainController2& config);
+
+ private:
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ AudioProcessing::Config::GainController2 config_;
+ GainApplier gain_applier_;
+ std::unique_ptr<AdaptiveAgc> adaptive_agc_;
+ Limiter limiter_;
+ int analog_level_ = -1;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(GainController2);
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_GAIN_CONTROLLER2_H_
diff --git a/webrtc/modules/audio_processing/high_pass_filter.cc b/webrtc/modules/audio_processing/high_pass_filter.cc
new file mode 100644
index 0000000..bff7209
--- /dev/null
+++ b/webrtc/modules/audio_processing/high_pass_filter.cc
@@ -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.
+ */
+
+#include "modules/audio_processing/high_pass_filter.h"
+
+#include "api/array_view.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+// [B,A] = butter(2,100/8000,'high')
+constexpr CascadedBiQuadFilter::BiQuadCoefficients
+ kHighPassFilterCoefficients16kHz = {{0.97261f, -1.94523f, 0.97261f},
+ {-1.94448f, 0.94598f}};
+
+// [B,A] = butter(2,100/16000,'high')
+constexpr CascadedBiQuadFilter::BiQuadCoefficients
+ kHighPassFilterCoefficients32kHz = {{0.98621f, -1.97242f, 0.98621f},
+ {-1.97223f, 0.97261f}};
+
+// [B,A] = butter(2,100/24000,'high')
+constexpr CascadedBiQuadFilter::BiQuadCoefficients
+ kHighPassFilterCoefficients48kHz = {{0.99079f, -1.98157f, 0.99079f},
+ {-1.98149f, 0.98166f}};
+
+constexpr size_t kNumberOfHighPassBiQuads = 1;
+
+const CascadedBiQuadFilter::BiQuadCoefficients& ChooseCoefficients(
+ int sample_rate_hz) {
+ switch (sample_rate_hz) {
+ case 16000:
+ return kHighPassFilterCoefficients16kHz;
+ case 32000:
+ return kHighPassFilterCoefficients32kHz;
+ case 48000:
+ return kHighPassFilterCoefficients48kHz;
+ default:
+ RTC_NOTREACHED();
+ }
+ RTC_NOTREACHED();
+ return kHighPassFilterCoefficients16kHz;
+}
+
+} // namespace
+
+HighPassFilter::HighPassFilter(int sample_rate_hz, size_t num_channels)
+ : sample_rate_hz_(sample_rate_hz) {
+ filters_.resize(num_channels);
+ const auto& coefficients = ChooseCoefficients(sample_rate_hz_);
+ for (size_t k = 0; k < filters_.size(); ++k) {
+ filters_[k].reset(
+ new CascadedBiQuadFilter(coefficients, kNumberOfHighPassBiQuads));
+ }
+}
+
+HighPassFilter::~HighPassFilter() = default;
+
+void HighPassFilter::Process(AudioBuffer* audio, bool use_split_band_data) {
+ RTC_DCHECK(audio);
+ RTC_DCHECK_EQ(filters_.size(), audio->num_channels());
+ if (use_split_band_data) {
+ for (size_t k = 0; k < audio->num_channels(); ++k) {
+ rtc::ArrayView<float> channel_data = rtc::ArrayView<float>(
+ audio->split_bands(k)[0], audio->num_frames_per_band());
+ filters_[k]->Process(channel_data);
+ }
+ } else {
+ for (size_t k = 0; k < audio->num_channels(); ++k) {
+ rtc::ArrayView<float> channel_data =
+ rtc::ArrayView<float>(&audio->channels()[k][0], audio->num_frames());
+ filters_[k]->Process(channel_data);
+ }
+ }
+}
+
+void HighPassFilter::Process(std::vector<std::vector<float>>* audio) {
+ RTC_DCHECK_EQ(filters_.size(), audio->size());
+ for (size_t k = 0; k < audio->size(); ++k) {
+ filters_[k]->Process((*audio)[k]);
+ }
+}
+
+void HighPassFilter::Reset() {
+ for (size_t k = 0; k < filters_.size(); ++k) {
+ filters_[k]->Reset();
+ }
+}
+
+void HighPassFilter::Reset(size_t num_channels) {
+ const size_t old_num_channels = filters_.size();
+ filters_.resize(num_channels);
+ if (filters_.size() < old_num_channels) {
+ Reset();
+ } else {
+ for (size_t k = 0; k < old_num_channels; ++k) {
+ filters_[k]->Reset();
+ }
+ const auto& coefficients = ChooseCoefficients(sample_rate_hz_);
+ for (size_t k = old_num_channels; k < filters_.size(); ++k) {
+ filters_[k].reset(
+ new CascadedBiQuadFilter(coefficients, kNumberOfHighPassBiQuads));
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/high_pass_filter.h b/webrtc/modules/audio_processing/high_pass_filter.h
new file mode 100644
index 0000000..7e7c370
--- /dev/null
+++ b/webrtc/modules/audio_processing/high_pass_filter.h
@@ -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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/utility/cascaded_biquad_filter.h"
+
+namespace webrtc {
+
+class AudioBuffer;
+
+class HighPassFilter {
+ public:
+ HighPassFilter(int sample_rate_hz, size_t num_channels);
+ ~HighPassFilter();
+ HighPassFilter(const HighPassFilter&) = delete;
+ HighPassFilter& operator=(const HighPassFilter&) = delete;
+
+ void Process(AudioBuffer* audio, bool use_split_band_data);
+ void Process(std::vector<std::vector<float>>* audio);
+ void Reset();
+ void Reset(size_t num_channels);
+
+ int sample_rate_hz() const { return sample_rate_hz_; }
+ size_t num_channels() const { return filters_.size(); }
+
+ private:
+ const int sample_rate_hz_;
+ std::vector<std::unique_ptr<CascadedBiQuadFilter>> filters_;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_H_
diff --git a/webrtc/modules/audio_processing/high_pass_filter_impl.cc b/webrtc/modules/audio_processing/high_pass_filter_impl.cc
deleted file mode 100644
index 29e4820..0000000
--- a/webrtc/modules/audio_processing/high_pass_filter_impl.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/high_pass_filter_impl.h"
-
-#include <assert.h>
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/audio_buffer.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/typedefs.h"
-
-
-namespace webrtc {
-namespace {
-const int16_t kFilterCoefficients8kHz[5] =
- {3798, -7596, 3798, 7807, -3733};
-
-const int16_t kFilterCoefficients[5] =
- {4012, -8024, 4012, 8002, -3913};
-
-struct FilterState {
- int16_t y[4];
- int16_t x[2];
- const int16_t* ba;
-};
-
-int InitializeFilter(FilterState* hpf, int sample_rate_hz) {
- assert(hpf != NULL);
-
- if (sample_rate_hz == AudioProcessing::kSampleRate8kHz) {
- hpf->ba = kFilterCoefficients8kHz;
- } else {
- hpf->ba = kFilterCoefficients;
- }
-
- WebRtcSpl_MemSetW16(hpf->x, 0, 2);
- WebRtcSpl_MemSetW16(hpf->y, 0, 4);
-
- return AudioProcessing::kNoError;
-}
-
-int Filter(FilterState* hpf, int16_t* data, size_t length) {
- assert(hpf != NULL);
-
- int32_t tmp_int32 = 0;
- int16_t* y = hpf->y;
- int16_t* x = hpf->x;
- const int16_t* ba = hpf->ba;
-
- for (size_t i = 0; i < length; i++) {
- // y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2]
- // + -a[1] * y[i-1] + -a[2] * y[i-2];
-
- tmp_int32 = y[1] * ba[3]; // -a[1] * y[i-1] (low part)
- tmp_int32 += y[3] * ba[4]; // -a[2] * y[i-2] (low part)
- tmp_int32 = (tmp_int32 >> 15);
- tmp_int32 += y[0] * ba[3]; // -a[1] * y[i-1] (high part)
- tmp_int32 += y[2] * ba[4]; // -a[2] * y[i-2] (high part)
- tmp_int32 = (tmp_int32 << 1);
-
- tmp_int32 += data[i] * ba[0]; // b[0]*x[0]
- tmp_int32 += x[0] * ba[1]; // b[1]*x[i-1]
- tmp_int32 += x[1] * ba[2]; // b[2]*x[i-2]
-
- // Update state (input part)
- x[1] = x[0];
- x[0] = data[i];
-
- // Update state (filtered part)
- y[2] = y[0];
- y[3] = y[1];
- y[0] = static_cast<int16_t>(tmp_int32 >> 13);
- y[1] = static_cast<int16_t>(
- (tmp_int32 - (static_cast<int32_t>(y[0]) << 13)) << 2);
-
- // Rounding in Q12, i.e. add 2^11
- tmp_int32 += 2048;
-
- // Saturate (to 2^27) so that the HP filtered signal does not overflow
- tmp_int32 = WEBRTC_SPL_SAT(static_cast<int32_t>(134217727),
- tmp_int32,
- static_cast<int32_t>(-134217728));
-
- // Convert back to Q0 and use rounding.
- data[i] = (int16_t)(tmp_int32 >> 12);
- }
-
- return AudioProcessing::kNoError;
-}
-} // namespace
-
-typedef FilterState Handle;
-
-HighPassFilterImpl::HighPassFilterImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit)
- : ProcessingComponent(),
- apm_(apm),
- crit_(crit) {}
-
-HighPassFilterImpl::~HighPassFilterImpl() {}
-
-int HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) {
- int err = apm_->kNoError;
-
- if (!is_component_enabled()) {
- return apm_->kNoError;
- }
-
- assert(audio->num_frames_per_band() <= 160);
-
- for (int i = 0; i < num_handles(); i++) {
- Handle* my_handle = static_cast<Handle*>(handle(i));
- err = Filter(my_handle,
- audio->split_bands(i)[kBand0To8kHz],
- audio->num_frames_per_band());
-
- if (err != apm_->kNoError) {
- return GetHandleError(my_handle);
- }
- }
-
- return apm_->kNoError;
-}
-
-int HighPassFilterImpl::Enable(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- return EnableComponent(enable);
-}
-
-bool HighPassFilterImpl::is_enabled() const {
- return is_component_enabled();
-}
-
-void* HighPassFilterImpl::CreateHandle() const {
- return new FilterState;
-}
-
-void HighPassFilterImpl::DestroyHandle(void* handle) const {
- delete static_cast<Handle*>(handle);
-}
-
-int HighPassFilterImpl::InitializeHandle(void* handle) const {
- return InitializeFilter(static_cast<Handle*>(handle),
- apm_->proc_sample_rate_hz());
-}
-
-int HighPassFilterImpl::ConfigureHandle(void* /*handle*/) const {
- return apm_->kNoError; // Not configurable.
-}
-
-int HighPassFilterImpl::num_handles_required() const {
- return apm_->num_output_channels();
-}
-
-int HighPassFilterImpl::GetHandleError(void* handle) const {
- // The component has no detailed errors.
- assert(handle != NULL);
- return apm_->kUnspecifiedError;
-}
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/high_pass_filter_impl.h b/webrtc/modules/audio_processing/high_pass_filter_impl.h
deleted file mode 100644
index 90b393e..0000000
--- a/webrtc/modules/audio_processing/high_pass_filter_impl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_IMPL_H_
-
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/processing_component.h"
-
-namespace webrtc {
-
-class AudioBuffer;
-class CriticalSectionWrapper;
-
-class HighPassFilterImpl : public HighPassFilter,
- public ProcessingComponent {
- public:
- HighPassFilterImpl(const AudioProcessing* apm, CriticalSectionWrapper* crit);
- virtual ~HighPassFilterImpl();
-
- int ProcessCaptureAudio(AudioBuffer* audio);
-
- // HighPassFilter implementation.
- bool is_enabled() const override;
-
- private:
- // HighPassFilter implementation.
- int Enable(bool enable) override;
-
- // ProcessingComponent implementation.
- void* CreateHandle() const override;
- int InitializeHandle(void* handle) const override;
- int ConfigureHandle(void* handle) const override;
- void DestroyHandle(void* handle) const override;
- int num_handles_required() const override;
- int GetHandleError(void* handle) const override;
-
- const AudioProcessing* apm_;
- CriticalSectionWrapper* crit_;
-};
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_IMPL_H_
diff --git a/webrtc/modules/audio_processing/include/aec_dump.cc b/webrtc/modules/audio_processing/include/aec_dump.cc
new file mode 100644
index 0000000..67809d0
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/aec_dump.cc
@@ -0,0 +1,41 @@
+/*
+ * 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/audio_processing/include/aec_dump.h"
+
+namespace webrtc {
+InternalAPMConfig::InternalAPMConfig() = default;
+InternalAPMConfig::InternalAPMConfig(const InternalAPMConfig&) = default;
+InternalAPMConfig::InternalAPMConfig(InternalAPMConfig&&) = default;
+InternalAPMConfig& InternalAPMConfig::operator=(const InternalAPMConfig&) =
+ default;
+
+bool InternalAPMConfig::operator==(const InternalAPMConfig& other) {
+ return aec_enabled == other.aec_enabled &&
+ aec_delay_agnostic_enabled == other.aec_delay_agnostic_enabled &&
+ aec_drift_compensation_enabled ==
+ other.aec_drift_compensation_enabled &&
+ aec_extended_filter_enabled == other.aec_extended_filter_enabled &&
+ aec_suppression_level == other.aec_suppression_level &&
+ aecm_enabled == other.aecm_enabled &&
+ aecm_comfort_noise_enabled == other.aecm_comfort_noise_enabled &&
+ aecm_routing_mode == other.aecm_routing_mode &&
+ agc_enabled == other.agc_enabled && agc_mode == other.agc_mode &&
+ agc_limiter_enabled == other.agc_limiter_enabled &&
+ hpf_enabled == other.hpf_enabled && ns_enabled == other.ns_enabled &&
+ ns_level == other.ns_level &&
+ transient_suppression_enabled == other.transient_suppression_enabled &&
+ noise_robust_agc_enabled == other.noise_robust_agc_enabled &&
+ pre_amplifier_enabled == other.pre_amplifier_enabled &&
+ pre_amplifier_fixed_gain_factor ==
+ other.pre_amplifier_fixed_gain_factor &&
+ experiments_description == other.experiments_description;
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/include/aec_dump.h b/webrtc/modules/audio_processing/include/aec_dump.h
new file mode 100644
index 0000000..ed5acb0
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/aec_dump.h
@@ -0,0 +1,114 @@
+/*
+ * 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_AUDIO_PROCESSING_INCLUDE_AEC_DUMP_H_
+#define MODULES_AUDIO_PROCESSING_INCLUDE_AEC_DUMP_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "modules/audio_processing/include/audio_frame_view.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "rtc_base/deprecation.h"
+
+namespace webrtc {
+
+// Struct for passing current config from APM without having to
+// include protobuf headers.
+struct InternalAPMConfig {
+ InternalAPMConfig();
+ InternalAPMConfig(const InternalAPMConfig&);
+ InternalAPMConfig(InternalAPMConfig&&);
+
+ InternalAPMConfig& operator=(const InternalAPMConfig&);
+ InternalAPMConfig& operator=(InternalAPMConfig&&) = delete;
+
+ bool operator==(const InternalAPMConfig& other);
+
+ bool aec_enabled = false;
+ bool aec_delay_agnostic_enabled = false;
+ bool aec_drift_compensation_enabled = false;
+ bool aec_extended_filter_enabled = false;
+ int aec_suppression_level = 0;
+ bool aecm_enabled = false;
+ bool aecm_comfort_noise_enabled = false;
+ int aecm_routing_mode = 0;
+ bool agc_enabled = false;
+ int agc_mode = 0;
+ bool agc_limiter_enabled = false;
+ bool hpf_enabled = false;
+ bool ns_enabled = false;
+ int ns_level = 0;
+ bool transient_suppression_enabled = false;
+ bool noise_robust_agc_enabled = false;
+ bool pre_amplifier_enabled = false;
+ float pre_amplifier_fixed_gain_factor = 1.f;
+ std::string experiments_description = "";
+};
+
+// An interface for recording configuration and input/output streams
+// of the Audio Processing Module. The recordings are called
+// 'aec-dumps' and are stored in a protobuf format defined in
+// debug.proto.
+// The Write* methods are always safe to call concurrently or
+// otherwise for all implementing subclasses. The intended mode of
+// operation is to create a protobuf object from the input, and send
+// it away to be written to file asynchronously.
+class AecDump {
+ public:
+ struct AudioProcessingState {
+ int delay;
+ int drift;
+ int level;
+ bool keypress;
+ };
+
+ virtual ~AecDump() = default;
+
+ // Logs Event::Type INIT message.
+ virtual void WriteInitMessage(const ProcessingConfig& api_format,
+ int64_t time_now_ms) = 0;
+ RTC_DEPRECATED void WriteInitMessage(const ProcessingConfig& api_format) {
+ WriteInitMessage(api_format, 0);
+ }
+
+ // Logs Event::Type STREAM message. To log an input/output pair,
+ // call the AddCapture* and AddAudioProcessingState methods followed
+ // by a WriteCaptureStreamMessage call.
+ virtual void AddCaptureStreamInput(
+ const AudioFrameView<const float>& src) = 0;
+ virtual void AddCaptureStreamOutput(
+ const AudioFrameView<const float>& src) = 0;
+ virtual void AddCaptureStreamInput(const int16_t* const data,
+ int num_channels,
+ int samples_per_channel) = 0;
+ virtual void AddCaptureStreamOutput(const int16_t* const data,
+ int num_channels,
+ int samples_per_channel) = 0;
+ virtual void AddAudioProcessingState(const AudioProcessingState& state) = 0;
+ virtual void WriteCaptureStreamMessage() = 0;
+
+ // Logs Event::Type REVERSE_STREAM message.
+ virtual void WriteRenderStreamMessage(const int16_t* const data,
+ int num_channels,
+ int samples_per_channel) = 0;
+ virtual void WriteRenderStreamMessage(
+ const AudioFrameView<const float>& src) = 0;
+
+ virtual void WriteRuntimeSetting(
+ const AudioProcessing::RuntimeSetting& runtime_setting) = 0;
+
+ // Logs Event::Type CONFIG message.
+ virtual void WriteConfig(const InternalAPMConfig& config) = 0;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_INCLUDE_AEC_DUMP_H_
diff --git a/webrtc/modules/audio_processing/include/audio_frame_proxies.cc b/webrtc/modules/audio_processing/include/audio_frame_proxies.cc
new file mode 100644
index 0000000..b960e72
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/audio_frame_proxies.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/include/audio_frame_proxies.h"
+
+#include "api/audio/audio_frame.h"
+#include "modules/audio_processing/include/audio_processing.h"
+
+namespace webrtc {
+
+int ProcessAudioFrame(AudioProcessing* ap, AudioFrame* frame) {
+ if (!frame || !ap) {
+ return AudioProcessing::Error::kNullPointerError;
+ }
+
+ StreamConfig input_config(frame->sample_rate_hz_, frame->num_channels_,
+ /*has_keyboard=*/false);
+ StreamConfig output_config(frame->sample_rate_hz_, frame->num_channels_,
+ /*has_keyboard=*/false);
+ RTC_DCHECK_EQ(frame->samples_per_channel(), input_config.num_frames());
+
+ int result = ap->ProcessStream(frame->data(), input_config, output_config,
+ frame->mutable_data());
+
+ AudioProcessingStats stats = ap->GetStatistics();
+
+ if (stats.voice_detected) {
+ frame->vad_activity_ = *stats.voice_detected
+ ? AudioFrame::VADActivity::kVadActive
+ : AudioFrame::VADActivity::kVadPassive;
+ }
+
+ return result;
+}
+
+int ProcessReverseAudioFrame(AudioProcessing* ap, AudioFrame* frame) {
+ if (!frame || !ap) {
+ return AudioProcessing::Error::kNullPointerError;
+ }
+
+ // Must be a native rate.
+ if (frame->sample_rate_hz_ != AudioProcessing::NativeRate::kSampleRate8kHz &&
+ frame->sample_rate_hz_ != AudioProcessing::NativeRate::kSampleRate16kHz &&
+ frame->sample_rate_hz_ != AudioProcessing::NativeRate::kSampleRate32kHz &&
+ frame->sample_rate_hz_ != AudioProcessing::NativeRate::kSampleRate48kHz) {
+ return AudioProcessing::Error::kBadSampleRateError;
+ }
+
+ if (frame->num_channels_ <= 0) {
+ return AudioProcessing::Error::kBadNumberChannelsError;
+ }
+
+ StreamConfig input_config(frame->sample_rate_hz_, frame->num_channels_,
+ /*has_keyboard=*/false);
+ StreamConfig output_config(frame->sample_rate_hz_, frame->num_channels_,
+ /*has_keyboard=*/false);
+
+ int result = ap->ProcessReverseStream(frame->data(), input_config,
+ output_config, frame->mutable_data());
+ return result;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/include/audio_frame_proxies.h b/webrtc/modules/audio_processing/include/audio_frame_proxies.h
new file mode 100644
index 0000000..2d0f5b5
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/audio_frame_proxies.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_PROXIES_H_
+#define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_PROXIES_H_
+
+namespace webrtc {
+
+class AudioFrame;
+class AudioProcessing;
+
+// Processes a 10 ms |frame| of the primary audio stream using the provided
+// AudioProcessing object. On the client-side, this is the near-end (or
+// captured) audio. The |sample_rate_hz_|, |num_channels_|, and
+// |samples_per_channel_| members of |frame| must be valid. If changed from the
+// previous call to this function, it will trigger an initialization of the
+// provided AudioProcessing object.
+// The function returns any error codes passed from the AudioProcessing
+// ProcessStream method.
+int ProcessAudioFrame(AudioProcessing* ap, AudioFrame* frame);
+
+// Processes a 10 ms |frame| of the reverse direction audio stream using the
+// provided AudioProcessing object. The frame may be modified. On the
+// client-side, this is the far-end (or to be rendered) audio. The
+// |sample_rate_hz_|, |num_channels_|, and |samples_per_channel_| members of
+// |frame| must be valid. If changed from the previous call to this function, it
+// will trigger an initialization of the provided AudioProcessing object.
+// The function returns any error codes passed from the AudioProcessing
+// ProcessReverseStream method.
+int ProcessReverseAudioFrame(AudioProcessing* ap, AudioFrame* frame);
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_PROXIES_H_
diff --git a/webrtc/modules/audio_processing/include/audio_frame_view.h b/webrtc/modules/audio_processing/include/audio_frame_view.h
new file mode 100644
index 0000000..ab5779a
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/audio_frame_view.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_VIEW_H_
+#define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_VIEW_H_
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+// Class to pass audio data in T** format, where T is a numeric type.
+template <class T>
+class AudioFrameView {
+ public:
+ // |num_channels| and |channel_size| describe the T**
+ // |audio_samples|. |audio_samples| is assumed to point to a
+ // two-dimensional |num_channels * channel_size| array of floats.
+ AudioFrameView(T* const* audio_samples,
+ size_t num_channels,
+ size_t channel_size)
+ : audio_samples_(audio_samples),
+ num_channels_(num_channels),
+ channel_size_(channel_size) {}
+
+ // Implicit cast to allow converting Frame<float> to
+ // Frame<const float>.
+ template <class U>
+ AudioFrameView(AudioFrameView<U> other)
+ : audio_samples_(other.data()),
+ num_channels_(other.num_channels()),
+ channel_size_(other.samples_per_channel()) {}
+
+ AudioFrameView() = delete;
+
+ size_t num_channels() const { return num_channels_; }
+
+ size_t samples_per_channel() const { return channel_size_; }
+
+ rtc::ArrayView<T> channel(size_t idx) {
+ RTC_DCHECK_LE(0, idx);
+ RTC_DCHECK_LE(idx, num_channels_);
+ return rtc::ArrayView<T>(audio_samples_[idx], channel_size_);
+ }
+
+ rtc::ArrayView<const T> channel(size_t idx) const {
+ RTC_DCHECK_LE(0, idx);
+ RTC_DCHECK_LE(idx, num_channels_);
+ return rtc::ArrayView<const T>(audio_samples_[idx], channel_size_);
+ }
+
+ T* const* data() { return audio_samples_; }
+
+ private:
+ T* const* audio_samples_;
+ size_t num_channels_;
+ size_t channel_size_;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_FRAME_VIEW_H_
diff --git a/webrtc/modules/audio_processing/include/audio_processing.cc b/webrtc/modules/audio_processing/include/audio_processing.cc
new file mode 100644
index 0000000..8854415
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/audio_processing.cc
@@ -0,0 +1,124 @@
+/*
+ * 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/audio_processing/include/audio_processing.h"
+
+#include "rtc_base/strings/string_builder.h"
+#include "rtc_base/system/arch.h"
+
+namespace webrtc {
+namespace {
+
+std::string NoiseSuppressionLevelToString(
+ const AudioProcessing::Config::NoiseSuppression::Level& level) {
+ switch (level) {
+ case AudioProcessing::Config::NoiseSuppression::Level::kLow:
+ return "Low";
+ case AudioProcessing::Config::NoiseSuppression::Level::kModerate:
+ return "Moderate";
+ case AudioProcessing::Config::NoiseSuppression::Level::kHigh:
+ return "High";
+ case AudioProcessing::Config::NoiseSuppression::Level::kVeryHigh:
+ return "VeryHigh";
+ }
+}
+
+std::string GainController1ModeToString(
+ const AudioProcessing::Config::GainController1::Mode& mode) {
+ switch (mode) {
+ case AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog:
+ return "AdaptiveAnalog";
+ case AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital:
+ return "AdaptiveDigital";
+ case AudioProcessing::Config::GainController1::Mode::kFixedDigital:
+ return "FixedDigital";
+ }
+}
+
+std::string GainController2LevelEstimatorToString(
+ const AudioProcessing::Config::GainController2::LevelEstimator& level) {
+ switch (level) {
+ case AudioProcessing::Config::GainController2::LevelEstimator::kRms:
+ return "Rms";
+ case AudioProcessing::Config::GainController2::LevelEstimator::kPeak:
+ return "Peak";
+ }
+}
+
+int GetDefaultMaxInternalRate() {
+#ifdef WEBRTC_ARCH_ARM_FAMILY
+ return 32000;
+#else
+ return 48000;
+#endif
+}
+
+} // namespace
+
+constexpr int AudioProcessing::kNativeSampleRatesHz[];
+
+void CustomProcessing::SetRuntimeSetting(
+ AudioProcessing::RuntimeSetting setting) {}
+
+AudioProcessing::Config::Pipeline::Pipeline()
+ : maximum_internal_processing_rate(GetDefaultMaxInternalRate()) {}
+
+std::string AudioProcessing::Config::ToString() const {
+ char buf[1024];
+ rtc::SimpleStringBuilder builder(buf);
+ builder << "AudioProcessing::Config{ "
+ "pipeline: {"
+ "maximum_internal_processing_rate: "
+ << pipeline.maximum_internal_processing_rate
+ << ", multi_channel_render: " << pipeline.multi_channel_render
+ << ", "
+ ", multi_channel_capture: "
+ << pipeline.multi_channel_capture
+ << "}, "
+ "pre_amplifier: { enabled: "
+ << pre_amplifier.enabled
+ << ", fixed_gain_factor: " << pre_amplifier.fixed_gain_factor
+ << " }, high_pass_filter: { enabled: " << high_pass_filter.enabled
+ << " }, echo_canceller: { enabled: " << echo_canceller.enabled
+ << ", mobile_mode: " << echo_canceller.mobile_mode
+ << ", enforce_high_pass_filtering: "
+ << echo_canceller.enforce_high_pass_filtering
+ << " }, noise_suppression: { enabled: " << noise_suppression.enabled
+ << ", level: "
+ << NoiseSuppressionLevelToString(noise_suppression.level)
+ << " }, transient_suppression: { enabled: "
+ << transient_suppression.enabled
+ << " }, voice_detection: { enabled: " << voice_detection.enabled
+ << " }, gain_controller1: { enabled: " << gain_controller1.enabled
+ << ", mode: " << GainController1ModeToString(gain_controller1.mode)
+ << ", target_level_dbfs: " << gain_controller1.target_level_dbfs
+ << ", compression_gain_db: " << gain_controller1.compression_gain_db
+ << ", enable_limiter: " << gain_controller1.enable_limiter
+ << ", analog_level_minimum: " << gain_controller1.analog_level_minimum
+ << ", analog_level_maximum: " << gain_controller1.analog_level_maximum
+ << " }, gain_controller2: { enabled: " << gain_controller2.enabled
+ << ", fixed_digital: { gain_db: "
+ << gain_controller2.fixed_digital.gain_db
+ << " }, adaptive_digital: { enabled: "
+ << gain_controller2.adaptive_digital.enabled << ", level_estimator: "
+ << GainController2LevelEstimatorToString(
+ gain_controller2.adaptive_digital.level_estimator)
+ << ", use_saturation_protector: "
+ << gain_controller2.adaptive_digital.use_saturation_protector
+ << ", extra_saturation_margin_db: "
+ << gain_controller2.adaptive_digital.extra_saturation_margin_db
+ << " } }, residual_echo_detector: { enabled: "
+ << residual_echo_detector.enabled
+ << " }, level_estimation: { enabled: " << level_estimation.enabled
+ << " } }";
+ return builder.str();
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/include/audio_processing.h b/webrtc/modules/audio_processing/include/audio_processing.h
index c8ddc6a..d09e2ba 100644
--- a/webrtc/modules/audio_processing/include/audio_processing.h
+++ b/webrtc/modules/audio_processing/include/audio_processing.h
@@ -8,139 +8,109 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_
+#ifndef MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_
+#define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_
// MSVC++ requires this to be set before any other includes to get M_PI.
+#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
+#endif
#include <math.h>
#include <stddef.h> // size_t
-#include <stdio.h> // FILE
-#include <vector>
+#include <stdio.h> // FILE
+#include <string.h>
-#include "webrtc/base/arraysize.h"
-#include "webrtc/base/platform_file.h"
-#include "webrtc/common.h"
-#include "webrtc/modules/audio_processing/beamformer/array_util.h"
-#include "webrtc/typedefs.h"
+#include <vector>
-struct AecCore;
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
+#include "api/audio/echo_control.h"
+#include "api/scoped_refptr.h"
+#include "modules/audio_processing/include/audio_processing_statistics.h"
+#include "modules/audio_processing/include/config.h"
+#include "rtc_base/arraysize.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/deprecation.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/system/file_wrapper.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace rtc {
+class TaskQueue;
+} // namespace rtc
namespace webrtc {
-class AudioFrame;
-
-template<typename T>
-class Beamformer;
+class AecDump;
+class AudioBuffer;
class StreamConfig;
class ProcessingConfig;
-class EchoCancellation;
-class EchoControlMobile;
-class GainControl;
-class HighPassFilter;
-class LevelEstimator;
-class NoiseSuppression;
-class VoiceDetection;
-
-// Use to enable the extended filter mode in the AEC, along with robustness
-// measures around the reported system delays. It comes with a significant
-// increase in AEC complexity, but is much more robust to unreliable reported
-// delays.
-//
-// Detailed changes to the algorithm:
-// - The filter length is changed from 48 to 128 ms. This comes with tuning of
-// several parameters: i) filter adaptation stepsize and error threshold;
-// ii) non-linear processing smoothing and overdrive.
-// - Option to ignore the reported delays on platforms which we deem
-// sufficiently unreliable. See WEBRTC_UNTRUSTED_DELAY in echo_cancellation.c.
-// - Faster startup times by removing the excessive "startup phase" processing
-// of reported delays.
-// - Much more conservative adjustments to the far-end read pointer. We smooth
-// the delay difference more heavily, and back off from the difference more.
-// Adjustments force a readaptation of the filter, so they should be avoided
-// except when really necessary.
-struct ExtendedFilter {
- ExtendedFilter() : enabled(false) {}
- explicit ExtendedFilter(bool enabled) : enabled(enabled) {}
- bool enabled;
-};
-
-// Enables delay-agnostic echo cancellation. This feature relies on internally
-// estimated delays between the process and reverse streams, thus not relying
-// on reported system delays. This configuration only applies to
-// EchoCancellation and not EchoControlMobile. It can be set in the constructor
-// or using AudioProcessing::SetExtraOptions().
-struct DelayAgnostic {
- DelayAgnostic() : enabled(false) {}
- explicit DelayAgnostic(bool enabled) : enabled(enabled) {}
- bool enabled;
-};
+class EchoDetector;
+class CustomAudioAnalyzer;
+class CustomProcessing;
// Use to enable experimental gain control (AGC). At startup the experimental
// AGC moves the microphone volume up to |startup_min_volume| if the current
// microphone volume is set too low. The value is clamped to its operating range
// [12, 255]. Here, 255 maps to 100%.
//
-// Must be provided through AudioProcessing::Create(Confg&).
+// Must be provided through AudioProcessingBuilder().Create(config).
#if defined(WEBRTC_CHROMIUM_BUILD)
static const int kAgcStartupMinVolume = 85;
#else
static const int kAgcStartupMinVolume = 0;
#endif // defined(WEBRTC_CHROMIUM_BUILD)
+static constexpr int kClippedLevelMin = 70;
+
+// To be deprecated: Please instead use the flag in the
+// AudioProcessing::Config::AnalogGainController.
+// TODO(webrtc:5298): Remove.
struct ExperimentalAgc {
- ExperimentalAgc() : enabled(true), startup_min_volume(kAgcStartupMinVolume) {}
- explicit ExperimentalAgc(bool enabled)
- : enabled(enabled), startup_min_volume(kAgcStartupMinVolume) {}
+ ExperimentalAgc() = default;
+ explicit ExperimentalAgc(bool enabled) : enabled(enabled) {}
+ ExperimentalAgc(bool enabled,
+ bool enabled_agc2_level_estimator,
+ bool digital_adaptive_disabled)
+ : enabled(enabled),
+ enabled_agc2_level_estimator(enabled_agc2_level_estimator),
+ digital_adaptive_disabled(digital_adaptive_disabled) {}
+ // Deprecated constructor: will be removed.
+ ExperimentalAgc(bool enabled,
+ bool enabled_agc2_level_estimator,
+ bool digital_adaptive_disabled,
+ bool analyze_before_aec)
+ : enabled(enabled),
+ enabled_agc2_level_estimator(enabled_agc2_level_estimator),
+ digital_adaptive_disabled(digital_adaptive_disabled) {}
ExperimentalAgc(bool enabled, int startup_min_volume)
: enabled(enabled), startup_min_volume(startup_min_volume) {}
- bool enabled;
- int startup_min_volume;
+ ExperimentalAgc(bool enabled, int startup_min_volume, int clipped_level_min)
+ : enabled(enabled),
+ startup_min_volume(startup_min_volume),
+ clipped_level_min(clipped_level_min) {}
+ static const ConfigOptionID identifier = ConfigOptionID::kExperimentalAgc;
+ bool enabled = true;
+ int startup_min_volume = kAgcStartupMinVolume;
+ // Lowest microphone level that will be applied in response to clipping.
+ int clipped_level_min = kClippedLevelMin;
+ bool enabled_agc2_level_estimator = false;
+ bool digital_adaptive_disabled = false;
};
+// To be deprecated: Please instead use the flag in the
+// AudioProcessing::Config::TransientSuppression.
+//
// Use to enable experimental noise suppression. It can be set in the
-// constructor or using AudioProcessing::SetExtraOptions().
+// constructor.
+// TODO(webrtc:5298): Remove.
struct ExperimentalNs {
ExperimentalNs() : enabled(false) {}
explicit ExperimentalNs(bool enabled) : enabled(enabled) {}
- bool enabled;
-};
-
-// Use to enable beamforming. Must be provided through the constructor. It will
-// have no impact if used with AudioProcessing::SetExtraOptions().
-struct Beamforming {
- Beamforming()
- : enabled(false),
- array_geometry(),
- target_direction(
- SphericalPointf(static_cast<float>(M_PI) / 2.f, 0.f, 1.f)) {}
- Beamforming(bool enabled, const std::vector<Point>& array_geometry)
- : Beamforming(enabled,
- array_geometry,
- SphericalPointf(static_cast<float>(M_PI) / 2.f, 0.f, 1.f)) {
- }
- Beamforming(bool enabled,
- const std::vector<Point>& array_geometry,
- SphericalPointf target_direction)
- : enabled(enabled),
- array_geometry(array_geometry),
- target_direction(target_direction) {}
- const bool enabled;
- const std::vector<Point> array_geometry;
- const SphericalPointf target_direction;
-};
-
-// Use to enable intelligibility enhancer in audio processing. Must be provided
-// though the constructor. It will have no impact if used with
-// AudioProcessing::SetExtraOptions().
-//
-// Note: If enabled and the reverse stream has more than one output channel,
-// the reverse stream will become an upmixed mono signal.
-struct Intelligibility {
- Intelligibility() : enabled(false) {}
- explicit Intelligibility(bool enabled) : enabled(enabled) {}
+ static const ConfigOptionID identifier = ConfigOptionID::kExperimentalNs;
bool enabled;
};
@@ -149,11 +119,11 @@ struct Intelligibility {
//
// APM operates on two audio streams on a frame-by-frame basis. Frames of the
// primary stream, on which all processing is applied, are passed to
-// |ProcessStream()|. Frames of the reverse direction stream, which are used for
-// analysis by some components, are passed to |AnalyzeReverseStream()|. On the
-// client-side, this will typically be the near-end (capture) and far-end
-// (render) streams, respectively. APM should be placed in the signal chain as
-// close to the audio hardware abstraction layer (HAL) as possible.
+// |ProcessStream()|. Frames of the reverse direction stream are passed to
+// |ProcessReverseStream()|. On the client-side, this will typically be the
+// near-end (capture) and far-end (render) streams, respectively. APM should be
+// placed in the signal chain as close to the audio hardware abstraction layer
+// (HAL) as possible.
//
// On the server-side, the reverse stream will normally not be used, with
// processing occurring on each incoming stream.
@@ -178,36 +148,43 @@ struct Intelligibility {
// data.
//
// Usage example, omitting error checking:
-// AudioProcessing* apm = AudioProcessing::Create(0);
+// AudioProcessing* apm = AudioProcessingBuilder().Create();
//
-// apm->high_pass_filter()->Enable(true);
+// AudioProcessing::Config config;
+// config.echo_canceller.enabled = true;
+// config.echo_canceller.mobile_mode = false;
//
-// apm->echo_cancellation()->enable_drift_compensation(false);
-// apm->echo_cancellation()->Enable(true);
+// config.gain_controller1.enabled = true;
+// config.gain_controller1.mode =
+// AudioProcessing::Config::GainController1::kAdaptiveAnalog;
+// config.gain_controller1.analog_level_minimum = 0;
+// config.gain_controller1.analog_level_maximum = 255;
//
-// apm->noise_reduction()->set_level(kHighSuppression);
-// apm->noise_reduction()->Enable(true);
+// config.gain_controller2.enabled = true;
+//
+// config.high_pass_filter.enabled = true;
//
-// apm->gain_control()->set_analog_level_limits(0, 255);
-// apm->gain_control()->set_mode(kAdaptiveAnalog);
-// apm->gain_control()->Enable(true);
+// config.voice_detection.enabled = true;
//
-// apm->voice_detection()->Enable(true);
+// apm->ApplyConfig(config)
+//
+// apm->noise_reduction()->set_level(kHighSuppression);
+// apm->noise_reduction()->Enable(true);
//
// // Start a voice call...
//
// // ... Render frame arrives bound for the audio HAL ...
-// apm->AnalyzeReverseStream(render_frame);
+// apm->ProcessReverseStream(render_frame);
//
// // ... Capture frame arrives from the audio HAL ...
// // Call required set_stream_ functions.
// apm->set_stream_delay_ms(delay_ms);
-// apm->gain_control()->set_stream_analog_level(analog_level);
+// apm->set_stream_analog_level(analog_level);
//
// apm->ProcessStream(capture_frame);
//
// // Call required stream_ functions.
-// analog_level = apm->gain_control()->stream_analog_level();
+// analog_level = apm->recommended_stream_analog_level();
// has_voice = apm->stream_has_voice();
//
// // Repeate render and capture processing for the duration of the call...
@@ -217,31 +194,298 @@ struct Intelligibility {
// // Close the application...
// delete apm;
//
-class AudioProcessing {
+class RTC_EXPORT AudioProcessing : public rtc::RefCountInterface {
public:
+ // The struct below constitutes the new parameter scheme for the audio
+ // processing. It is being introduced gradually and until it is fully
+ // introduced, it is prone to change.
+ // TODO(peah): Remove this comment once the new config scheme is fully rolled
+ // out.
+ //
+ // The parameters and behavior of the audio processing module are controlled
+ // by changing the default values in the AudioProcessing::Config struct.
+ // The config is applied by passing the struct to the ApplyConfig method.
+ //
+ // This config is intended to be used during setup, and to enable/disable
+ // top-level processing effects. Use during processing may cause undesired
+ // submodule resets, affecting the audio quality. Use the RuntimeSetting
+ // construct for runtime configuration.
+ struct RTC_EXPORT Config {
+
+ // Sets the properties of the audio processing pipeline.
+ struct RTC_EXPORT Pipeline {
+ Pipeline();
+
+ // Maximum allowed processing rate used internally. May only be set to
+ // 32000 or 48000 and any differing values will be treated as 48000. The
+ // default rate is currently selected based on the CPU architecture, but
+ // that logic may change.
+ int maximum_internal_processing_rate;
+ // Allow multi-channel processing of render audio.
+ bool multi_channel_render = false;
+ // Allow multi-channel processing of capture audio when AEC3 is active
+ // or a custom AEC is injected..
+ bool multi_channel_capture = false;
+ } pipeline;
+
+ // Enabled the pre-amplifier. It amplifies the capture signal
+ // before any other processing is done.
+ struct PreAmplifier {
+ bool enabled = false;
+ float fixed_gain_factor = 1.f;
+ } pre_amplifier;
+
+ struct HighPassFilter {
+ bool enabled = false;
+ bool apply_in_full_band = true;
+ } high_pass_filter;
+
+ struct EchoCanceller {
+ bool enabled = false;
+ bool mobile_mode = false;
+ bool export_linear_aec_output = false;
+ // Enforce the highpass filter to be on (has no effect for the mobile
+ // mode).
+ bool enforce_high_pass_filtering = true;
+ } echo_canceller;
+
+ // Enables background noise suppression.
+ struct NoiseSuppression {
+ bool enabled = false;
+ enum Level { kLow, kModerate, kHigh, kVeryHigh };
+ Level level = kModerate;
+ bool analyze_linear_aec_output_when_available = false;
+ } noise_suppression;
+
+ // Enables transient suppression.
+ struct TransientSuppression {
+ bool enabled = false;
+ } transient_suppression;
+
+ // Enables reporting of |voice_detected| in webrtc::AudioProcessingStats.
+ struct VoiceDetection {
+ bool enabled = false;
+ } voice_detection;
+
+ // Enables automatic gain control (AGC) functionality.
+ // The automatic gain control (AGC) component brings the signal to an
+ // appropriate range. This is done by applying a digital gain directly and,
+ // in the analog mode, prescribing an analog gain to be applied at the audio
+ // HAL.
+ // Recommended to be enabled on the client-side.
+ struct GainController1 {
+ bool enabled = false;
+ enum Mode {
+ // Adaptive mode intended for use if an analog volume control is
+ // available on the capture device. It will require the user to provide
+ // coupling between the OS mixer controls and AGC through the
+ // stream_analog_level() functions.
+ // It consists of an analog gain prescription for the audio device and a
+ // digital compression stage.
+ kAdaptiveAnalog,
+ // Adaptive mode intended for situations in which an analog volume
+ // control is unavailable. It operates in a similar fashion to the
+ // adaptive analog mode, but with scaling instead applied in the digital
+ // domain. As with the analog mode, it additionally uses a digital
+ // compression stage.
+ kAdaptiveDigital,
+ // Fixed mode which enables only the digital compression stage also used
+ // by the two adaptive modes.
+ // It is distinguished from the adaptive modes by considering only a
+ // short time-window of the input signal. It applies a fixed gain
+ // through most of the input level range, and compresses (gradually
+ // reduces gain with increasing level) the input signal at higher
+ // levels. This mode is preferred on embedded devices where the capture
+ // signal level is predictable, so that a known gain can be applied.
+ kFixedDigital
+ };
+ Mode mode = kAdaptiveAnalog;
+ // Sets the target peak level (or envelope) of the AGC in dBFs (decibels
+ // from digital full-scale). The convention is to use positive values. For
+ // instance, passing in a value of 3 corresponds to -3 dBFs, or a target
+ // level 3 dB below full-scale. Limited to [0, 31].
+ int target_level_dbfs = 3;
+ // Sets the maximum gain the digital compression stage may apply, in dB. A
+ // higher number corresponds to greater compression, while a value of 0
+ // will leave the signal uncompressed. Limited to [0, 90].
+ // For updates after APM setup, use a RuntimeSetting instead.
+ int compression_gain_db = 9;
+ // When enabled, the compression stage will hard limit the signal to the
+ // target level. Otherwise, the signal will be compressed but not limited
+ // above the target level.
+ bool enable_limiter = true;
+ // Sets the minimum and maximum analog levels of the audio capture device.
+ // Must be set if an analog mode is used. Limited to [0, 65535].
+ int analog_level_minimum = 0;
+ int analog_level_maximum = 255;
+
+ // Enables the analog gain controller functionality.
+ struct AnalogGainController {
+ bool enabled = true;
+ int startup_min_volume = kAgcStartupMinVolume;
+ // Lowest analog microphone level that will be applied in response to
+ // clipping.
+ int clipped_level_min = kClippedLevelMin;
+ bool enable_agc2_level_estimator = false;
+ bool enable_digital_adaptive = true;
+ } analog_gain_controller;
+ } gain_controller1;
+
+ // Enables the next generation AGC functionality. This feature replaces the
+ // standard methods of gain control in the previous AGC. Enabling this
+ // submodule enables an adaptive digital AGC followed by a limiter. By
+ // setting |fixed_gain_db|, the limiter can be turned into a compressor that
+ // first applies a fixed gain. The adaptive digital AGC can be turned off by
+ // setting |adaptive_digital_mode=false|.
+ struct GainController2 {
+ enum LevelEstimator { kRms, kPeak };
+ bool enabled = false;
+ struct {
+ float gain_db = 0.f;
+ } fixed_digital;
+ struct {
+ bool enabled = false;
+ float vad_probability_attack = 1.f;
+ LevelEstimator level_estimator = kRms;
+ int level_estimator_adjacent_speech_frames_threshold = 1;
+ // TODO(crbug.com/webrtc/7494): Remove `use_saturation_protector`.
+ bool use_saturation_protector = true;
+ float initial_saturation_margin_db = 20.f;
+ float extra_saturation_margin_db = 2.f;
+ int gain_applier_adjacent_speech_frames_threshold = 1;
+ float max_gain_change_db_per_second = 3.f;
+ float max_output_noise_level_dbfs = -50.f;
+ } adaptive_digital;
+ } gain_controller2;
+
+ struct ResidualEchoDetector {
+ bool enabled = true;
+ } residual_echo_detector;
+
+ // Enables reporting of |output_rms_dbfs| in webrtc::AudioProcessingStats.
+ struct LevelEstimation {
+ bool enabled = false;
+ } level_estimation;
+
+ std::string ToString() const;
+ };
+
// TODO(mgraczyk): Remove once all methods that use ChannelLayout are gone.
enum ChannelLayout {
kMono,
// Left, right.
kStereo,
- // Mono, keyboard mic.
+ // Mono, keyboard, and mic.
kMonoAndKeyboard,
- // Left, right, keyboard mic.
+ // Left, right, keyboard, and mic.
kStereoAndKeyboard
};
- // Creates an APM instance. Use one instance for every primary audio stream
- // requiring processing. On the client-side, this would typically be one
- // instance for the near-end stream, and additional instances for each far-end
- // stream which requires processing. On the server-side, this would typically
- // be one instance for every incoming stream.
- static AudioProcessing* Create();
- // Allows passing in an optional configuration at create-time.
- static AudioProcessing* Create(const Config& config);
- // Only for testing.
- static AudioProcessing* Create(const Config& config,
- Beamformer<float>* beamformer);
- virtual ~AudioProcessing() {}
+ // Specifies the properties of a setting to be passed to AudioProcessing at
+ // runtime.
+ class RuntimeSetting {
+ public:
+ enum class Type {
+ kNotSpecified,
+ kCapturePreGain,
+ kCaptureCompressionGain,
+ kCaptureFixedPostGain,
+ kPlayoutVolumeChange,
+ kCustomRenderProcessingRuntimeSetting,
+ kPlayoutAudioDeviceChange,
+ kCaptureOutputUsed
+ };
+
+ // Play-out audio device properties.
+ struct PlayoutAudioDeviceInfo {
+ int id; // Identifies the audio device.
+ int max_volume; // Maximum play-out volume.
+ };
+
+ RuntimeSetting() : type_(Type::kNotSpecified), value_(0.f) {}
+ ~RuntimeSetting() = default;
+
+ static RuntimeSetting CreateCapturePreGain(float gain) {
+ RTC_DCHECK_GE(gain, 1.f) << "Attenuation is not allowed.";
+ return {Type::kCapturePreGain, gain};
+ }
+
+ // Corresponds to Config::GainController1::compression_gain_db, but for
+ // runtime configuration.
+ static RuntimeSetting CreateCompressionGainDb(int gain_db) {
+ RTC_DCHECK_GE(gain_db, 0);
+ RTC_DCHECK_LE(gain_db, 90);
+ return {Type::kCaptureCompressionGain, static_cast<float>(gain_db)};
+ }
+
+ // Corresponds to Config::GainController2::fixed_digital::gain_db, but for
+ // runtime configuration.
+ static RuntimeSetting CreateCaptureFixedPostGain(float gain_db) {
+ RTC_DCHECK_GE(gain_db, 0.f);
+ RTC_DCHECK_LE(gain_db, 90.f);
+ return {Type::kCaptureFixedPostGain, gain_db};
+ }
+
+ // Creates a runtime setting to notify play-out (aka render) audio device
+ // changes.
+ static RuntimeSetting CreatePlayoutAudioDeviceChange(
+ PlayoutAudioDeviceInfo audio_device) {
+ return {Type::kPlayoutAudioDeviceChange, audio_device};
+ }
+
+ // Creates a runtime setting to notify play-out (aka render) volume changes.
+ // |volume| is the unnormalized volume, the maximum of which
+ static RuntimeSetting CreatePlayoutVolumeChange(int volume) {
+ return {Type::kPlayoutVolumeChange, volume};
+ }
+
+ static RuntimeSetting CreateCustomRenderSetting(float payload) {
+ return {Type::kCustomRenderProcessingRuntimeSetting, payload};
+ }
+
+ static RuntimeSetting CreateCaptureOutputUsedSetting(bool payload) {
+ return {Type::kCaptureOutputUsed, payload};
+ }
+
+ Type type() const { return type_; }
+ // Getters do not return a value but instead modify the argument to protect
+ // from implicit casting.
+ void GetFloat(float* value) const {
+ RTC_DCHECK(value);
+ *value = value_.float_value;
+ }
+ void GetInt(int* value) const {
+ RTC_DCHECK(value);
+ *value = value_.int_value;
+ }
+ void GetBool(bool* value) const {
+ RTC_DCHECK(value);
+ *value = value_.bool_value;
+ }
+ void GetPlayoutAudioDeviceInfo(PlayoutAudioDeviceInfo* value) const {
+ RTC_DCHECK(value);
+ *value = value_.playout_audio_device_info;
+ }
+
+ private:
+ RuntimeSetting(Type id, float value) : type_(id), value_(value) {}
+ RuntimeSetting(Type id, int value) : type_(id), value_(value) {}
+ RuntimeSetting(Type id, PlayoutAudioDeviceInfo value)
+ : type_(id), value_(value) {}
+ Type type_;
+ union U {
+ U() {}
+ U(int value) : int_value(value) {}
+ U(float value) : float_value(value) {}
+ U(PlayoutAudioDeviceInfo value) : playout_audio_device_info(value) {}
+ float float_value;
+ int int_value;
+ bool bool_value;
+ PlayoutAudioDeviceInfo playout_audio_device_info;
+ } value_;
+ };
+
+ ~AudioProcessing() override {}
// Initializes internal states, while retaining all user settings. This
// should be called before beginning to process a new audio stream. However,
@@ -250,8 +494,9 @@ class AudioProcessing {
//
// It is also not necessary to call if the audio parameters (sample
// rate and number of channels) have changed. Passing updated parameters
- // directly to |ProcessStream()| and |AnalyzeReverseStream()| is permissible.
+ // directly to |ProcessStream()| and |ProcessReverseStream()| is permissible.
// If the parameters are known at init-time though, they may be provided.
+ // TODO(webrtc:5298): Change to return void.
virtual int Initialize() = 0;
// The int16 interfaces require:
@@ -268,24 +513,25 @@ class AudioProcessing {
// Initialize with unpacked parameters. See Initialize() above for details.
//
// TODO(mgraczyk): Remove once clients are updated to use the new interface.
- virtual int Initialize(int input_sample_rate_hz,
- int output_sample_rate_hz,
- int reverse_sample_rate_hz,
- ChannelLayout input_layout,
- ChannelLayout output_layout,
- ChannelLayout reverse_layout) = 0;
+ virtual int Initialize(int capture_input_sample_rate_hz,
+ int capture_output_sample_rate_hz,
+ int render_sample_rate_hz,
+ ChannelLayout capture_input_layout,
+ ChannelLayout capture_output_layout,
+ ChannelLayout render_input_layout) = 0;
- // Pass down additional options which don't have explicit setters. This
- // ensures the options are applied immediately.
- virtual void SetExtraOptions(const Config& config) = 0;
+ // TODO(peah): This method is a temporary solution used to take control
+ // over the parameters in the audio processing module and is likely to change.
+ virtual void ApplyConfig(const Config& config) = 0;
// TODO(ajm): Only intended for internal use. Make private and friend the
// necessary classes?
virtual int proc_sample_rate_hz() const = 0;
virtual int proc_split_sample_rate_hz() const = 0;
- virtual int num_input_channels() const = 0;
- virtual int num_output_channels() const = 0;
- virtual int num_reverse_channels() const = 0;
+ virtual size_t num_input_channels() const = 0;
+ virtual size_t num_proc_channels() const = 0;
+ virtual size_t num_output_channels() const = 0;
+ virtual size_t num_reverse_channels() const = 0;
// Set to true when the output of AudioProcessing will be muted or in some
// other way not used. Ideally, the captured audio would still be processed,
@@ -293,34 +539,16 @@ class AudioProcessing {
// Default false.
virtual void set_output_will_be_muted(bool muted) = 0;
- // Processes a 10 ms |frame| of the primary audio stream. On the client-side,
- // this is the near-end (or captured) audio.
- //
- // If needed for enabled functionality, any function with the set_stream_ tag
- // must be called prior to processing the current frame. Any getter function
- // with the stream_ tag which is needed should be called after processing.
- //
- // The |sample_rate_hz_|, |num_channels_|, and |samples_per_channel_|
- // members of |frame| must be valid. If changed from the previous call to this
- // method, it will trigger an initialization.
- virtual int ProcessStream(AudioFrame* frame) = 0;
+ // Enqueue a runtime setting.
+ virtual void SetRuntimeSetting(RuntimeSetting setting) = 0;
- // Accepts deinterleaved float audio with the range [-1, 1]. Each element
- // of |src| points to a channel buffer, arranged according to
- // |input_layout|. At output, the channels will be arranged according to
- // |output_layout| at |output_sample_rate_hz| in |dest|.
- //
- // The output layout must have one channel or as many channels as the input.
- // |src| and |dest| may use the same memory, if desired.
- //
- // TODO(mgraczyk): Remove once clients are updated to use the new interface.
- virtual int ProcessStream(const float* const* src,
- size_t samples_per_channel,
- int input_sample_rate_hz,
- ChannelLayout input_layout,
- int output_sample_rate_hz,
- ChannelLayout output_layout,
- float* const* dest) = 0;
+ // Accepts and produces a 10 ms frame interleaved 16 bit integer audio as
+ // specified in |input_config| and |output_config|. |src| and |dest| may use
+ // the same memory, if desired.
+ virtual int ProcessStream(const int16_t* const src,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
+ int16_t* const dest) = 0;
// Accepts deinterleaved float audio with the range [-1, 1]. Each element of
// |src| points to a channel buffer, arranged according to |input_stream|. At
@@ -334,116 +562,106 @@ class AudioProcessing {
const StreamConfig& output_config,
float* const* dest) = 0;
- // Analyzes a 10 ms |frame| of the reverse direction audio stream. The frame
- // will not be modified. On the client-side, this is the far-end (or to be
- // rendered) audio.
- //
- // It is only necessary to provide this if echo processing is enabled, as the
- // reverse stream forms the echo reference signal. It is recommended, but not
- // necessary, to provide if gain control is enabled. On the server-side this
- // typically will not be used. If you're not sure what to pass in here,
- // chances are you don't need to use it.
- //
- // The |sample_rate_hz_|, |num_channels_|, and |samples_per_channel_|
- // members of |frame| must be valid. |sample_rate_hz_| must correspond to
- // |input_sample_rate_hz()|
- //
- // TODO(ajm): add const to input; requires an implementation fix.
- // DEPRECATED: Use |ProcessReverseStream| instead.
- // TODO(ekm): Remove once all users have updated to |ProcessReverseStream|.
- virtual int AnalyzeReverseStream(AudioFrame* frame) = 0;
-
- // Same as |AnalyzeReverseStream|, but may modify |frame| if intelligibility
- // is enabled.
- virtual int ProcessReverseStream(AudioFrame* frame) = 0;
-
- // Accepts deinterleaved float audio with the range [-1, 1]. Each element
- // of |data| points to a channel buffer, arranged according to |layout|.
- // TODO(mgraczyk): Remove once clients are updated to use the new interface.
- virtual int AnalyzeReverseStream(const float* const* data,
- size_t samples_per_channel,
- int rev_sample_rate_hz,
- ChannelLayout layout) = 0;
+ // Accepts and produces a 10 ms frame of interleaved 16 bit integer audio for
+ // the reverse direction audio stream as specified in |input_config| and
+ // |output_config|. |src| and |dest| may use the same memory, if desired.
+ virtual int ProcessReverseStream(const int16_t* const src,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
+ int16_t* const dest) = 0;
// Accepts deinterleaved float audio with the range [-1, 1]. Each element of
// |data| points to a channel buffer, arranged according to |reverse_config|.
virtual int ProcessReverseStream(const float* const* src,
- const StreamConfig& reverse_input_config,
- const StreamConfig& reverse_output_config,
+ const StreamConfig& input_config,
+ const StreamConfig& output_config,
float* const* dest) = 0;
+ // Accepts deinterleaved float audio with the range [-1, 1]. Each element
+ // of |data| points to a channel buffer, arranged according to
+ // |reverse_config|.
+ virtual int AnalyzeReverseStream(const float* const* data,
+ const StreamConfig& reverse_config) = 0;
+
+ // Returns the most recently produced 10 ms of the linear AEC output at a rate
+ // of 16 kHz. If there is more than one capture channel, a mono representation
+ // of the input is returned. Returns true/false to indicate whether an output
+ // returned.
+ virtual bool GetLinearAecOutput(
+ rtc::ArrayView<std::array<float, 160>> linear_output) const = 0;
+
+ // This must be called prior to ProcessStream() if and only if adaptive analog
+ // gain control is enabled, to pass the current analog level from the audio
+ // HAL. Must be within the range provided in Config::GainController1.
+ virtual void set_stream_analog_level(int level) = 0;
+
+ // When an analog mode is set, this should be called after ProcessStream()
+ // to obtain the recommended new analog level for the audio HAL. It is the
+ // user's responsibility to apply this level.
+ virtual int recommended_stream_analog_level() const = 0;
+
// This must be called if and only if echo processing is enabled.
//
- // Sets the |delay| in ms between AnalyzeReverseStream() receiving a far-end
+ // Sets the |delay| in ms between ProcessReverseStream() receiving a far-end
// frame and ProcessStream() receiving a near-end frame containing the
// corresponding echo. On the client-side this can be expressed as
// delay = (t_render - t_analyze) + (t_process - t_capture)
// where,
- // - t_analyze is the time a frame is passed to AnalyzeReverseStream() and
+ // - t_analyze is the time a frame is passed to ProcessReverseStream() and
// t_render is the time the first sample of the same frame is rendered by
// the audio hardware.
// - t_capture is the time the first sample of a frame is captured by the
- // audio hardware and t_pull is the time the same frame is passed to
+ // audio hardware and t_process is the time the same frame is passed to
// ProcessStream().
virtual int set_stream_delay_ms(int delay) = 0;
virtual int stream_delay_ms() const = 0;
- virtual bool was_stream_delay_set() const = 0;
// Call to signal that a key press occurred (true) or did not occur (false)
// with this chunk of audio.
virtual void set_stream_key_pressed(bool key_pressed) = 0;
- // Sets a delay |offset| in ms to add to the values passed in through
- // set_stream_delay_ms(). May be positive or negative.
- //
- // Note that this could cause an otherwise valid value passed to
- // set_stream_delay_ms() to return an error.
- virtual void set_delay_offset_ms(int offset) = 0;
- virtual int delay_offset_ms() const = 0;
-
- // Starts recording debugging information to a file specified by |filename|,
- // a NULL-terminated string. If there is an ongoing recording, the old file
- // will be closed, and recording will continue in the newly specified file.
- // An already existing file will be overwritten without warning.
- static const size_t kMaxFilenameSize = 1024;
- virtual int StartDebugRecording(const char filename[kMaxFilenameSize]) = 0;
-
- // Same as above but uses an existing file handle. Takes ownership
- // of |handle| and closes it at StopDebugRecording().
- virtual int StartDebugRecording(FILE* handle) = 0;
-
- // Same as above but uses an existing PlatformFile handle. Takes ownership
- // of |handle| and closes it at StopDebugRecording().
- // TODO(xians): Make this interface pure virtual.
- virtual int StartDebugRecordingForPlatformFile(rtc::PlatformFile handle) {
- return -1;
- }
-
- // Stops recording debugging information, and closes the file. Recording
- // cannot be resumed in the same file (without overwriting it).
- virtual int StopDebugRecording() = 0;
-
- // Use to send UMA histograms at end of a call. Note that all histogram
- // specific member variables are reset.
- virtual void UpdateHistogramsOnCallEnd() = 0;
-
- // These provide access to the component interfaces and should never return
- // NULL. The pointers will be valid for the lifetime of the APM instance.
- // The memory for these objects is entirely managed internally.
- virtual EchoCancellation* echo_cancellation() const = 0;
- virtual EchoControlMobile* echo_control_mobile() const = 0;
- virtual GainControl* gain_control() const = 0;
- virtual HighPassFilter* high_pass_filter() const = 0;
- virtual LevelEstimator* level_estimator() const = 0;
- virtual NoiseSuppression* noise_suppression() const = 0;
- virtual VoiceDetection* voice_detection() const = 0;
-
- struct Statistic {
- int instant; // Instantaneous value.
- int average; // Long-term average.
- int maximum; // Long-term maximum.
- int minimum; // Long-term minimum.
- };
+ // Creates and attaches an webrtc::AecDump for recording debugging
+ // information.
+ // The |worker_queue| may not be null and must outlive the created
+ // AecDump instance. |max_log_size_bytes == -1| means the log size
+ // will be unlimited. |handle| may not be null. The AecDump takes
+ // responsibility for |handle| and closes it in the destructor. A
+ // return value of true indicates that the file has been
+ // sucessfully opened, while a value of false indicates that
+ // opening the file failed.
+ virtual bool CreateAndAttachAecDump(const std::string& file_name,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) = 0;
+ virtual bool CreateAndAttachAecDump(FILE* handle,
+ int64_t max_log_size_bytes,
+ rtc::TaskQueue* worker_queue) = 0;
+
+ // TODO(webrtc:5298) Deprecated variant.
+ // Attaches provided webrtc::AecDump for recording debugging
+ // information. Log file and maximum file size logic is supposed to
+ // be handled by implementing instance of AecDump. Calling this
+ // method when another AecDump is attached resets the active AecDump
+ // with a new one. This causes the d-tor of the earlier AecDump to
+ // be called. The d-tor call may block until all pending logging
+ // tasks are completed.
+ virtual void AttachAecDump(std::unique_ptr<AecDump> aec_dump) = 0;
+
+ // If no AecDump is attached, this has no effect. If an AecDump is
+ // attached, it's destructor is called. The d-tor may block until
+ // all pending logging tasks are completed.
+ virtual void DetachAecDump() = 0;
+
+ // Get audio processing statistics.
+ virtual AudioProcessingStats GetStatistics() = 0;
+ // TODO(webrtc:5298) Deprecated variant. The |has_remote_tracks| argument
+ // should be set if there are active remote tracks (this would usually be true
+ // during a call). If there are no remote tracks some of the stats will not be
+ // set by AudioProcessing, because they only make sense if there is at least
+ // one remote track.
+ virtual AudioProcessingStats GetStatistics(bool has_remote_tracks) = 0;
+
+ // Returns the last applied configuration.
+ virtual AudioProcessing::Config GetConfig() const = 0;
enum Error {
// Fatal errors.
@@ -467,6 +685,7 @@ class AudioProcessing {
kBadStreamParameterWarning = -13
};
+ // Native rates supported by the integer interfaces.
enum NativeRate {
kSampleRate8kHz = 8000,
kSampleRate16kHz = 16000,
@@ -474,14 +693,67 @@ class AudioProcessing {
kSampleRate48kHz = 48000
};
- static const int kNativeSampleRatesHz[];
- static const size_t kNumNativeSampleRates;
- static const int kMaxNativeSampleRateHz;
- static const int kMaxAECMSampleRateHz;
+ // TODO(kwiberg): We currently need to support a compiler (Visual C++) that
+ // complains if we don't explicitly state the size of the array here. Remove
+ // the size when that's no longer the case.
+ static constexpr int kNativeSampleRatesHz[4] = {
+ kSampleRate8kHz, kSampleRate16kHz, kSampleRate32kHz, kSampleRate48kHz};
+ static constexpr size_t kNumNativeSampleRates =
+ arraysize(kNativeSampleRatesHz);
+ static constexpr int kMaxNativeSampleRateHz =
+ kNativeSampleRatesHz[kNumNativeSampleRates - 1];
static const int kChunkSizeMs = 10;
};
+class RTC_EXPORT AudioProcessingBuilder {
+ public:
+ AudioProcessingBuilder();
+ ~AudioProcessingBuilder();
+ // The AudioProcessingBuilder takes ownership of the echo_control_factory.
+ AudioProcessingBuilder& SetEchoControlFactory(
+ std::unique_ptr<EchoControlFactory> echo_control_factory) {
+ echo_control_factory_ = std::move(echo_control_factory);
+ return *this;
+ }
+ // The AudioProcessingBuilder takes ownership of the capture_post_processing.
+ AudioProcessingBuilder& SetCapturePostProcessing(
+ std::unique_ptr<CustomProcessing> capture_post_processing) {
+ capture_post_processing_ = std::move(capture_post_processing);
+ return *this;
+ }
+ // The AudioProcessingBuilder takes ownership of the render_pre_processing.
+ AudioProcessingBuilder& SetRenderPreProcessing(
+ std::unique_ptr<CustomProcessing> render_pre_processing) {
+ render_pre_processing_ = std::move(render_pre_processing);
+ return *this;
+ }
+ // The AudioProcessingBuilder takes ownership of the echo_detector.
+ AudioProcessingBuilder& SetEchoDetector(
+ rtc::scoped_refptr<EchoDetector> echo_detector) {
+ echo_detector_ = std::move(echo_detector);
+ return *this;
+ }
+ // The AudioProcessingBuilder takes ownership of the capture_analyzer.
+ AudioProcessingBuilder& SetCaptureAnalyzer(
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer) {
+ capture_analyzer_ = std::move(capture_analyzer);
+ return *this;
+ }
+ // This creates an APM instance using the previously set components. Calling
+ // the Create function resets the AudioProcessingBuilder to its initial state.
+ AudioProcessing* Create();
+ AudioProcessing* Create(const webrtc::Config& config);
+
+ private:
+ std::unique_ptr<EchoControlFactory> echo_control_factory_;
+ std::unique_ptr<CustomProcessing> capture_post_processing_;
+ std::unique_ptr<CustomProcessing> render_pre_processing_;
+ rtc::scoped_refptr<EchoDetector> echo_detector_;
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer_;
+ RTC_DISALLOW_COPY_AND_ASSIGN(AudioProcessingBuilder);
+};
+
class StreamConfig {
public:
// sample_rate_hz: The sampling rate of the stream.
@@ -497,7 +769,7 @@ class StreamConfig {
// is true, the last channel in any corresponding list of
// channels is the keyboard channel.
StreamConfig(int sample_rate_hz = 0,
- int num_channels = 0,
+ size_t num_channels = 0,
bool has_keyboard = false)
: sample_rate_hz_(sample_rate_hz),
num_channels_(num_channels),
@@ -508,14 +780,14 @@ class StreamConfig {
sample_rate_hz_ = value;
num_frames_ = calculate_frames(value);
}
- void set_num_channels(int value) { num_channels_ = value; }
+ void set_num_channels(size_t value) { num_channels_ = value; }
void set_has_keyboard(bool value) { has_keyboard_ = value; }
int sample_rate_hz() const { return sample_rate_hz_; }
// The number of channels in the stream, not including the keyboard channel if
// present.
- int num_channels() const { return num_channels_; }
+ size_t num_channels() const { return num_channels_; }
bool has_keyboard() const { return has_keyboard_; }
size_t num_frames() const { return num_frames_; }
@@ -531,12 +803,12 @@ class StreamConfig {
private:
static size_t calculate_frames(int sample_rate_hz) {
- return static_cast<size_t>(
- AudioProcessing::kChunkSizeMs * sample_rate_hz / 1000);
+ return static_cast<size_t>(AudioProcessing::kChunkSizeMs * sample_rate_hz /
+ 1000);
}
int sample_rate_hz_;
- int num_channels_;
+ size_t num_channels_;
bool has_keyboard_;
size_t num_frames_;
};
@@ -589,365 +861,64 @@ class ProcessingConfig {
StreamConfig streams[StreamName::kNumStreamNames];
};
-// The acoustic echo cancellation (AEC) component provides better performance
-// than AECM but also requires more processing power and is dependent on delay
-// stability and reporting accuracy. As such it is well-suited and recommended
-// for PC and IP phone applications.
-//
-// Not recommended to be enabled on the server-side.
-class EchoCancellation {
- public:
- // EchoCancellation and EchoControlMobile may not be enabled simultaneously.
- // Enabling one will disable the other.
- virtual int Enable(bool enable) = 0;
- virtual bool is_enabled() const = 0;
-
- // Differences in clock speed on the primary and reverse streams can impact
- // the AEC performance. On the client-side, this could be seen when different
- // render and capture devices are used, particularly with webcams.
- //
- // This enables a compensation mechanism, and requires that
- // set_stream_drift_samples() be called.
- virtual int enable_drift_compensation(bool enable) = 0;
- virtual bool is_drift_compensation_enabled() const = 0;
-
- // Sets the difference between the number of samples rendered and captured by
- // the audio devices since the last call to |ProcessStream()|. Must be called
- // if drift compensation is enabled, prior to |ProcessStream()|.
- virtual void set_stream_drift_samples(int drift) = 0;
- virtual int stream_drift_samples() const = 0;
-
- enum SuppressionLevel {
- kLowSuppression,
- kModerateSuppression,
- kHighSuppression
- };
-
- // Sets the aggressiveness of the suppressor. A higher level trades off
- // double-talk performance for increased echo suppression.
- virtual int set_suppression_level(SuppressionLevel level) = 0;
- virtual SuppressionLevel suppression_level() const = 0;
-
- // Returns false if the current frame almost certainly contains no echo
- // and true if it _might_ contain echo.
- virtual bool stream_has_echo() const = 0;
-
- // Enables the computation of various echo metrics. These are obtained
- // through |GetMetrics()|.
- virtual int enable_metrics(bool enable) = 0;
- virtual bool are_metrics_enabled() const = 0;
-
- // Each statistic is reported in dB.
- // P_far: Far-end (render) signal power.
- // P_echo: Near-end (capture) echo signal power.
- // P_out: Signal power at the output of the AEC.
- // P_a: Internal signal power at the point before the AEC's non-linear
- // processor.
- struct Metrics {
- // RERL = ERL + ERLE
- AudioProcessing::Statistic residual_echo_return_loss;
-
- // ERL = 10log_10(P_far / P_echo)
- AudioProcessing::Statistic echo_return_loss;
-
- // ERLE = 10log_10(P_echo / P_out)
- AudioProcessing::Statistic echo_return_loss_enhancement;
-
- // (Pre non-linear processing suppression) A_NLP = 10log_10(P_echo / P_a)
- AudioProcessing::Statistic a_nlp;
- };
-
- // TODO(ajm): discuss the metrics update period.
- virtual int GetMetrics(Metrics* metrics) = 0;
-
- // Enables computation and logging of delay values. Statistics are obtained
- // through |GetDelayMetrics()|.
- virtual int enable_delay_logging(bool enable) = 0;
- virtual bool is_delay_logging_enabled() const = 0;
-
- // The delay metrics consists of the delay |median| and the delay standard
- // deviation |std|. It also consists of the fraction of delay estimates
- // |fraction_poor_delays| that can make the echo cancellation perform poorly.
- // The values are aggregated until the first call to |GetDelayMetrics()| and
- // afterwards aggregated and updated every second.
- // Note that if there are several clients pulling metrics from
- // |GetDelayMetrics()| during a session the first call from any of them will
- // change to one second aggregation window for all.
- // TODO(bjornv): Deprecated, remove.
- virtual int GetDelayMetrics(int* median, int* std) = 0;
- virtual int GetDelayMetrics(int* median, int* std,
- float* fraction_poor_delays) = 0;
-
- // Returns a pointer to the low level AEC component. In case of multiple
- // channels, the pointer to the first one is returned. A NULL pointer is
- // returned when the AEC component is disabled or has not been initialized
- // successfully.
- virtual struct AecCore* aec_core() const = 0;
-
- protected:
- virtual ~EchoCancellation() {}
-};
-
-// The acoustic echo control for mobile (AECM) component is a low complexity
-// robust option intended for use on mobile devices.
-//
-// Not recommended to be enabled on the server-side.
-class EchoControlMobile {
+// Experimental interface for a custom analysis submodule.
+class CustomAudioAnalyzer {
public:
- // EchoCancellation and EchoControlMobile may not be enabled simultaneously.
- // Enabling one will disable the other.
- virtual int Enable(bool enable) = 0;
- virtual bool is_enabled() const = 0;
-
- // Recommended settings for particular audio routes. In general, the louder
- // the echo is expected to be, the higher this value should be set. The
- // preferred setting may vary from device to device.
- enum RoutingMode {
- kQuietEarpieceOrHeadset,
- kEarpiece,
- kLoudEarpiece,
- kSpeakerphone,
- kLoudSpeakerphone
- };
-
- // Sets echo control appropriate for the audio routing |mode| on the device.
- // It can and should be updated during a call if the audio routing changes.
- virtual int set_routing_mode(RoutingMode mode) = 0;
- virtual RoutingMode routing_mode() const = 0;
-
- // Comfort noise replaces suppressed background noise to maintain a
- // consistent signal level.
- virtual int enable_comfort_noise(bool enable) = 0;
- virtual bool is_comfort_noise_enabled() const = 0;
-
- // A typical use case is to initialize the component with an echo path from a
- // previous call. The echo path is retrieved using |GetEchoPath()|, typically
- // at the end of a call. The data can then be stored for later use as an
- // initializer before the next call, using |SetEchoPath()|.
- //
- // Controlling the echo path this way requires the data |size_bytes| to match
- // the internal echo path size. This size can be acquired using
- // |echo_path_size_bytes()|. |SetEchoPath()| causes an entire reset, worth
- // noting if it is to be called during an ongoing call.
- //
- // It is possible that version incompatibilities may result in a stored echo
- // path of the incorrect size. In this case, the stored path should be
- // discarded.
- virtual int SetEchoPath(const void* echo_path, size_t size_bytes) = 0;
- virtual int GetEchoPath(void* echo_path, size_t size_bytes) const = 0;
-
- // The returned path size is guaranteed not to change for the lifetime of
- // the application.
- static size_t echo_path_size_bytes();
-
- protected:
- virtual ~EchoControlMobile() {}
+ // (Re-) Initializes the submodule.
+ virtual void Initialize(int sample_rate_hz, int num_channels) = 0;
+ // Analyzes the given capture or render signal.
+ virtual void Analyze(const AudioBuffer* audio) = 0;
+ // Returns a string representation of the module state.
+ virtual std::string ToString() const = 0;
+
+ virtual ~CustomAudioAnalyzer() {}
};
-// The automatic gain control (AGC) component brings the signal to an
-// appropriate range. This is done by applying a digital gain directly and, in
-// the analog mode, prescribing an analog gain to be applied at the audio HAL.
-//
-// Recommended to be enabled on the client-side.
-class GainControl {
+// Interface for a custom processing submodule.
+class CustomProcessing {
public:
- virtual int Enable(bool enable) = 0;
- virtual bool is_enabled() const = 0;
-
- // When an analog mode is set, this must be called prior to |ProcessStream()|
- // to pass the current analog level from the audio HAL. Must be within the
- // range provided to |set_analog_level_limits()|.
- virtual int set_stream_analog_level(int level) = 0;
-
- // When an analog mode is set, this should be called after |ProcessStream()|
- // to obtain the recommended new analog level for the audio HAL. It is the
- // users responsibility to apply this level.
- virtual int stream_analog_level() = 0;
-
- enum Mode {
- // Adaptive mode intended for use if an analog volume control is available
- // on the capture device. It will require the user to provide coupling
- // between the OS mixer controls and AGC through the |stream_analog_level()|
- // functions.
- //
- // It consists of an analog gain prescription for the audio device and a
- // digital compression stage.
- kAdaptiveAnalog,
-
- // Adaptive mode intended for situations in which an analog volume control
- // is unavailable. It operates in a similar fashion to the adaptive analog
- // mode, but with scaling instead applied in the digital domain. As with
- // the analog mode, it additionally uses a digital compression stage.
- kAdaptiveDigital,
-
- // Fixed mode which enables only the digital compression stage also used by
- // the two adaptive modes.
- //
- // It is distinguished from the adaptive modes by considering only a
- // short time-window of the input signal. It applies a fixed gain through
- // most of the input level range, and compresses (gradually reduces gain
- // with increasing level) the input signal at higher levels. This mode is
- // preferred on embedded devices where the capture signal level is
- // predictable, so that a known gain can be applied.
- kFixedDigital
- };
-
- virtual int set_mode(Mode mode) = 0;
- virtual Mode mode() const = 0;
-
- // Sets the target peak |level| (or envelope) of the AGC in dBFs (decibels
- // from digital full-scale). The convention is to use positive values. For
- // instance, passing in a value of 3 corresponds to -3 dBFs, or a target
- // level 3 dB below full-scale. Limited to [0, 31].
- //
- // TODO(ajm): use a negative value here instead, if/when VoE will similarly
- // update its interface.
- virtual int set_target_level_dbfs(int level) = 0;
- virtual int target_level_dbfs() const = 0;
-
- // Sets the maximum |gain| the digital compression stage may apply, in dB. A
- // higher number corresponds to greater compression, while a value of 0 will
- // leave the signal uncompressed. Limited to [0, 90].
- virtual int set_compression_gain_db(int gain) = 0;
- virtual int compression_gain_db() const = 0;
-
- // When enabled, the compression stage will hard limit the signal to the
- // target level. Otherwise, the signal will be compressed but not limited
- // above the target level.
- virtual int enable_limiter(bool enable) = 0;
- virtual bool is_limiter_enabled() const = 0;
-
- // Sets the |minimum| and |maximum| analog levels of the audio capture device.
- // Must be set if and only if an analog mode is used. Limited to [0, 65535].
- virtual int set_analog_level_limits(int minimum,
- int maximum) = 0;
- virtual int analog_level_minimum() const = 0;
- virtual int analog_level_maximum() const = 0;
-
- // Returns true if the AGC has detected a saturation event (period where the
- // signal reaches digital full-scale) in the current frame and the analog
- // level cannot be reduced.
- //
- // This could be used as an indicator to reduce or disable analog mic gain at
- // the audio HAL.
- virtual bool stream_is_saturated() const = 0;
-
- protected:
- virtual ~GainControl() {}
+ // (Re-)Initializes the submodule.
+ virtual void Initialize(int sample_rate_hz, int num_channels) = 0;
+ // Processes the given capture or render signal.
+ virtual void Process(AudioBuffer* audio) = 0;
+ // Returns a string representation of the module state.
+ virtual std::string ToString() const = 0;
+ // Handles RuntimeSettings. TODO(webrtc:9262): make pure virtual
+ // after updating dependencies.
+ virtual void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting);
+
+ virtual ~CustomProcessing() {}
};
-// A filtering component which removes DC offset and low-frequency noise.
-// Recommended to be enabled on the client-side.
-class HighPassFilter {
+// Interface for an echo detector submodule.
+class EchoDetector : public rtc::RefCountInterface {
public:
- virtual int Enable(bool enable) = 0;
- virtual bool is_enabled() const = 0;
+ // (Re-)Initializes the submodule.
+ virtual void Initialize(int capture_sample_rate_hz,
+ int num_capture_channels,
+ int render_sample_rate_hz,
+ int num_render_channels) = 0;
- protected:
- virtual ~HighPassFilter() {}
-};
-
-// An estimation component used to retrieve level metrics.
-class LevelEstimator {
- public:
- virtual int Enable(bool enable) = 0;
- virtual bool is_enabled() const = 0;
+ // Analysis (not changing) of the render signal.
+ virtual void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) = 0;
- // Returns the root mean square (RMS) level in dBFs (decibels from digital
- // full-scale), or alternately dBov. It is computed over all primary stream
- // frames since the last call to RMS(). The returned value is positive but
- // should be interpreted as negative. It is constrained to [0, 127].
- //
- // The computation follows: https://tools.ietf.org/html/rfc6465
- // with the intent that it can provide the RTP audio level indication.
- //
- // Frames passed to ProcessStream() with an |_energy| of zero are considered
- // to have been muted. The RMS of the frame will be interpreted as -127.
- virtual int RMS() = 0;
+ // Analysis (not changing) of the capture signal.
+ virtual void AnalyzeCaptureAudio(
+ rtc::ArrayView<const float> capture_audio) = 0;
- protected:
- virtual ~LevelEstimator() {}
-};
+ // Pack an AudioBuffer into a vector<float>.
+ static void PackRenderAudioBuffer(AudioBuffer* audio,
+ std::vector<float>* packed_buffer);
-// The noise suppression (NS) component attempts to remove noise while
-// retaining speech. Recommended to be enabled on the client-side.
-//
-// Recommended to be enabled on the client-side.
-class NoiseSuppression {
- public:
- virtual int Enable(bool enable) = 0;
- virtual bool is_enabled() const = 0;
-
- // Determines the aggressiveness of the suppression. Increasing the level
- // will reduce the noise level at the expense of a higher speech distortion.
- enum Level {
- kLow,
- kModerate,
- kHigh,
- kVeryHigh
+ struct Metrics {
+ absl::optional<double> echo_likelihood;
+ absl::optional<double> echo_likelihood_recent_max;
};
- virtual int set_level(Level level) = 0;
- virtual Level level() const = 0;
-
- // Returns the internally computed prior speech probability of current frame
- // averaged over output channels. This is not supported in fixed point, for
- // which |kUnsupportedFunctionError| is returned.
- virtual float speech_probability() const = 0;
-
- protected:
- virtual ~NoiseSuppression() {}
+ // Collect current metrics from the echo detector.
+ virtual Metrics GetMetrics() const = 0;
};
-// The voice activity detection (VAD) component analyzes the stream to
-// determine if voice is present. A facility is also provided to pass in an
-// external VAD decision.
-//
-// In addition to |stream_has_voice()| the VAD decision is provided through the
-// |AudioFrame| passed to |ProcessStream()|. The |vad_activity_| member will be
-// modified to reflect the current decision.
-class VoiceDetection {
- public:
- virtual int Enable(bool enable) = 0;
- virtual bool is_enabled() const = 0;
-
- // Returns true if voice is detected in the current frame. Should be called
- // after |ProcessStream()|.
- virtual bool stream_has_voice() const = 0;
-
- // Some of the APM functionality requires a VAD decision. In the case that
- // a decision is externally available for the current frame, it can be passed
- // in here, before |ProcessStream()| is called.
- //
- // VoiceDetection does _not_ need to be enabled to use this. If it happens to
- // be enabled, detection will be skipped for any frame in which an external
- // VAD decision is provided.
- virtual int set_stream_has_voice(bool has_voice) = 0;
-
- // Specifies the likelihood that a frame will be declared to contain voice.
- // A higher value makes it more likely that speech will not be clipped, at
- // the expense of more noise being detected as voice.
- enum Likelihood {
- kVeryLowLikelihood,
- kLowLikelihood,
- kModerateLikelihood,
- kHighLikelihood
- };
-
- virtual int set_likelihood(Likelihood likelihood) = 0;
- virtual Likelihood likelihood() const = 0;
-
- // Sets the |size| of the frames in ms on which the VAD will operate. Larger
- // frames will improve detection accuracy, but reduce the frequency of
- // updates.
- //
- // This does not impact the size of frames passed to |ProcessStream()|.
- virtual int set_frame_size_ms(int size) = 0;
- virtual int frame_size_ms() const = 0;
-
- protected:
- virtual ~VoiceDetection() {}
-};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_
+#endif // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_H_
diff --git a/webrtc/modules/audio_processing/include/audio_processing_statistics.cc b/webrtc/modules/audio_processing/include/audio_processing_statistics.cc
new file mode 100644
index 0000000..7139ee5
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/audio_processing_statistics.cc
@@ -0,0 +1,22 @@
+/*
+ * Copyright 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/audio_processing/include/audio_processing_statistics.h"
+
+namespace webrtc {
+
+AudioProcessingStats::AudioProcessingStats() = default;
+
+AudioProcessingStats::AudioProcessingStats(const AudioProcessingStats& other) =
+ default;
+
+AudioProcessingStats::~AudioProcessingStats() = default;
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/include/audio_processing_statistics.h b/webrtc/modules/audio_processing/include/audio_processing_statistics.h
new file mode 100644
index 0000000..87babee
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/audio_processing_statistics.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 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_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_STATISTICS_H_
+#define MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_STATISTICS_H_
+
+#include <stdint.h>
+
+#include "absl/types/optional.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace webrtc {
+// This version of the stats uses Optionals, it will replace the regular
+// AudioProcessingStatistics struct.
+struct RTC_EXPORT AudioProcessingStats {
+ AudioProcessingStats();
+ AudioProcessingStats(const AudioProcessingStats& other);
+ ~AudioProcessingStats();
+
+ // The root mean square (RMS) level in dBFS (decibels from digital
+ // full-scale) of the last capture frame, after processing. It is
+ // constrained to [-127, 0].
+ // The computation follows: https://tools.ietf.org/html/rfc6465
+ // with the intent that it can provide the RTP audio level indication.
+ // Only reported if level estimation is enabled in AudioProcessing::Config.
+ absl::optional<int> output_rms_dbfs;
+
+ // True if voice is detected in the last capture frame, after processing.
+ // It is conservative in flagging audio as speech, with low likelihood of
+ // incorrectly flagging a frame as voice.
+ // Only reported if voice detection is enabled in AudioProcessing::Config.
+ absl::optional<bool> voice_detected;
+
+ // AEC Statistics.
+ // ERL = 10log_10(P_far / P_echo)
+ absl::optional<double> echo_return_loss;
+ // ERLE = 10log_10(P_echo / P_out)
+ absl::optional<double> echo_return_loss_enhancement;
+ // Fraction of time that the AEC linear filter is divergent, in a 1-second
+ // non-overlapped aggregation window.
+ absl::optional<double> divergent_filter_fraction;
+
+ // The delay metrics consists of the delay median and standard deviation. It
+ // also consists of the fraction of delay estimates that can make the echo
+ // cancellation perform poorly. The values are aggregated until the first
+ // call to |GetStatistics()| and afterwards aggregated and updated every
+ // second. Note that if there are several clients pulling metrics from
+ // |GetStatistics()| during a session the first call from any of them will
+ // change to one second aggregation window for all.
+ absl::optional<int32_t> delay_median_ms;
+ absl::optional<int32_t> delay_standard_deviation_ms;
+
+ // Residual echo detector likelihood.
+ absl::optional<double> residual_echo_likelihood;
+ // Maximum residual echo likelihood from the last time period.
+ absl::optional<double> residual_echo_likelihood_recent_max;
+
+ // The instantaneous delay estimate produced in the AEC. The unit is in
+ // milliseconds and the value is the instantaneous value at the time of the
+ // call to |GetStatistics()|.
+ absl::optional<int32_t> delay_ms;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_INCLUDE_AUDIO_PROCESSING_STATISTICS_H_
diff --git a/webrtc/modules/audio_processing/include/config.cc b/webrtc/modules/audio_processing/include/config.cc
new file mode 100644
index 0000000..14240db
--- /dev/null
+++ b/webrtc/modules/audio_processing/include/config.cc
@@ -0,0 +1,23 @@
+/*
+ * 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/audio_processing/include/config.h"
+
+namespace webrtc {
+
+Config::Config() {}
+
+Config::~Config() {
+ for (OptionMap::iterator it = options_.begin(); it != options_.end(); ++it) {
+ delete it->second;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common.h b/webrtc/modules/audio_processing/include/config.h
index dda045e..7fab178 100644
--- a/webrtc/common.h
+++ b/webrtc/modules/audio_processing/include/config.h
@@ -8,15 +8,35 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_COMMON_H_
-#define WEBRTC_COMMON_H_
+#ifndef MODULES_AUDIO_PROCESSING_INCLUDE_CONFIG_H_
+#define MODULES_AUDIO_PROCESSING_INCLUDE_CONFIG_H_
#include <map>
-#include "webrtc/base/basictypes.h"
+#include "rtc_base/system/rtc_export.h"
namespace webrtc {
+// Only add new values to the end of the enumeration and never remove (only
+// deprecate) to maintain binary compatibility.
+enum class ConfigOptionID {
+ kMyExperimentForTest,
+ kAlgo1CostFunctionForTest,
+ kTemporalLayersFactory, // Deprecated
+ kNetEqCapacityConfig, // Deprecated
+ kNetEqFastAccelerate, // Deprecated
+ kVoicePacing, // Deprecated
+ kExtendedFilter, // Deprecated
+ kDelayAgnostic, // Deprecated
+ kExperimentalAgc,
+ kExperimentalNs,
+ kBeamforming, // Deprecated
+ kIntelligibility, // Deprecated
+ kEchoCanceller3, // Deprecated
+ kAecRefinedAdaptiveFilter, // Deprecated
+ kLevelControl // Deprecated
+};
+
// Class Config is designed to ease passing a set of options across webrtc code.
// Options are identified by typename in order to avoid incorrect casts.
//
@@ -37,70 +57,58 @@ namespace webrtc {
// config.Set<Algo1_CostFunction>(new SqrCost());
//
// Note: This class is thread-compatible (like STL containers).
-class Config {
+class RTC_EXPORT Config {
public:
// Returns the option if set or a default constructed one.
// Callers that access options too often are encouraged to cache the result.
// Returned references are owned by this.
//
// Requires std::is_default_constructible<T>
- template<typename T> const T& Get() const;
+ template <typename T>
+ const T& Get() const;
// Set the option, deleting any previous instance of the same.
// This instance gets ownership of the newly set value.
- template<typename T> void Set(T* value);
-
- Config() {}
- ~Config() {
- // Note: this method is inline so webrtc public API depends only
- // on the headers.
- for (OptionMap::iterator it = options_.begin();
- it != options_.end(); ++it) {
- delete it->second;
- }
- }
+ template <typename T>
+ void Set(T* value);
- private:
- typedef void* OptionIdentifier;
+ Config();
+ ~Config();
+ private:
struct BaseOption {
virtual ~BaseOption() {}
};
- template<typename T>
+ template <typename T>
struct Option : BaseOption {
- explicit Option(T* v): value(v) {}
- ~Option() {
- delete value;
- }
+ explicit Option(T* v) : value(v) {}
+ ~Option() { delete value; }
T* value;
};
- // Own implementation of rtti-subset to avoid depending on rtti and its costs.
- template<typename T>
- static OptionIdentifier identifier() {
- static char id_placeholder;
- return &id_placeholder;
+ template <typename T>
+ static ConfigOptionID identifier() {
+ return T::identifier;
}
// Used to instantiate a default constructed object that doesn't needs to be
// owned. This allows Get<T> to be implemented without requiring explicitly
// locks.
- template<typename T>
+ template <typename T>
static const T& default_value() {
- RTC_DEFINE_STATIC_LOCAL(const T, def, ());
- return def;
+ static const T* const def = new T();
+ return *def;
}
- typedef std::map<OptionIdentifier, BaseOption*> OptionMap;
+ typedef std::map<ConfigOptionID, BaseOption*> OptionMap;
OptionMap options_;
- // RTC_DISALLOW_COPY_AND_ASSIGN
Config(const Config&);
void operator=(const Config&);
};
-template<typename T>
+template <typename T>
const T& Config::Get() const {
OptionMap::const_iterator it = options_.find(identifier<T>());
if (it != options_.end()) {
@@ -112,13 +120,12 @@ const T& Config::Get() const {
return default_value<T>();
}
-template<typename T>
+template <typename T>
void Config::Set(T* value) {
BaseOption*& it = options_[identifier<T>()];
delete it;
it = new Option<T>(value);
}
-
} // namespace webrtc
-#endif // WEBRTC_COMMON_H_
+#endif // MODULES_AUDIO_PROCESSING_INCLUDE_CONFIG_H_
diff --git a/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc b/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
deleted file mode 100644
index d014ce0..0000000
--- a/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-//
-// Implements core class for intelligibility enhancer.
-//
-// Details of the model and algorithm can be found in the original paper:
-// http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=6882788
-//
-
-#include "webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h"
-
-#include <math.h>
-#include <stdlib.h>
-#include <algorithm>
-#include <numeric>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/window_generator.h"
-
-namespace webrtc {
-
-namespace {
-
-const size_t kErbResolution = 2;
-const int kWindowSizeMs = 2;
-const int kChunkSizeMs = 10; // Size provided by APM.
-const float kClipFreq = 200.0f;
-const float kConfigRho = 0.02f; // Default production and interpretation SNR.
-const float kKbdAlpha = 1.5f;
-const float kLambdaBot = -1.0f; // Extreme values in bisection
-const float kLambdaTop = -10e-18f; // search for lamda.
-
-} // namespace
-
-using std::complex;
-using std::max;
-using std::min;
-using VarianceType = intelligibility::VarianceArray::StepType;
-
-IntelligibilityEnhancer::TransformCallback::TransformCallback(
- IntelligibilityEnhancer* parent,
- IntelligibilityEnhancer::AudioSource source)
- : parent_(parent), source_(source) {
-}
-
-void IntelligibilityEnhancer::TransformCallback::ProcessAudioBlock(
- const complex<float>* const* in_block,
- int in_channels,
- size_t frames,
- int /* out_channels */,
- complex<float>* const* out_block) {
- RTC_DCHECK_EQ(parent_->freqs_, frames);
- for (int i = 0; i < in_channels; ++i) {
- parent_->DispatchAudio(source_, in_block[i], out_block[i]);
- }
-}
-
-IntelligibilityEnhancer::IntelligibilityEnhancer()
- : IntelligibilityEnhancer(IntelligibilityEnhancer::Config()) {
-}
-
-IntelligibilityEnhancer::IntelligibilityEnhancer(const Config& config)
- : freqs_(RealFourier::ComplexLength(
- RealFourier::FftOrder(config.sample_rate_hz * kWindowSizeMs / 1000))),
- window_size_(static_cast<size_t>(1 << RealFourier::FftOrder(freqs_))),
- chunk_length_(
- static_cast<size_t>(config.sample_rate_hz * kChunkSizeMs / 1000)),
- bank_size_(GetBankSize(config.sample_rate_hz, kErbResolution)),
- sample_rate_hz_(config.sample_rate_hz),
- erb_resolution_(kErbResolution),
- num_capture_channels_(config.num_capture_channels),
- num_render_channels_(config.num_render_channels),
- analysis_rate_(config.analysis_rate),
- active_(true),
- clear_variance_(freqs_,
- config.var_type,
- config.var_window_size,
- config.var_decay_rate),
- noise_variance_(freqs_,
- config.var_type,
- config.var_window_size,
- config.var_decay_rate),
- filtered_clear_var_(new float[bank_size_]),
- filtered_noise_var_(new float[bank_size_]),
- filter_bank_(bank_size_),
- center_freqs_(new float[bank_size_]),
- rho_(new float[bank_size_]),
- gains_eq_(new float[bank_size_]),
- gain_applier_(freqs_, config.gain_change_limit),
- temp_render_out_buffer_(chunk_length_, num_render_channels_),
- temp_capture_out_buffer_(chunk_length_, num_capture_channels_),
- kbd_window_(new float[window_size_]),
- render_callback_(this, AudioSource::kRenderStream),
- capture_callback_(this, AudioSource::kCaptureStream),
- block_count_(0),
- analysis_step_(0) {
- RTC_DCHECK_LE(config.rho, 1.0f);
-
- CreateErbBank();
-
- // Assumes all rho equal.
- for (size_t i = 0; i < bank_size_; ++i) {
- rho_[i] = config.rho * config.rho;
- }
-
- float freqs_khz = kClipFreq / 1000.0f;
- size_t erb_index = static_cast<size_t>(ceilf(
- 11.17f * logf((freqs_khz + 0.312f) / (freqs_khz + 14.6575f)) + 43.0f));
- start_freq_ = std::max(static_cast<size_t>(1), erb_index * erb_resolution_);
-
- WindowGenerator::KaiserBesselDerived(kKbdAlpha, window_size_,
- kbd_window_.get());
- render_mangler_.reset(new LappedTransform(
- num_render_channels_, num_render_channels_, chunk_length_,
- kbd_window_.get(), window_size_, window_size_ / 2, &render_callback_));
- capture_mangler_.reset(new LappedTransform(
- num_capture_channels_, num_capture_channels_, chunk_length_,
- kbd_window_.get(), window_size_, window_size_ / 2, &capture_callback_));
-}
-
-void IntelligibilityEnhancer::ProcessRenderAudio(float* const* audio,
- int sample_rate_hz,
- int num_channels) {
- RTC_CHECK_EQ(sample_rate_hz_, sample_rate_hz);
- RTC_CHECK_EQ(num_render_channels_, num_channels);
-
- if (active_) {
- render_mangler_->ProcessChunk(audio, temp_render_out_buffer_.channels());
- }
-
- if (active_) {
- for (int i = 0; i < num_render_channels_; ++i) {
- memcpy(audio[i], temp_render_out_buffer_.channels()[i],
- chunk_length_ * sizeof(**audio));
- }
- }
-}
-
-void IntelligibilityEnhancer::AnalyzeCaptureAudio(float* const* audio,
- int sample_rate_hz,
- int num_channels) {
- RTC_CHECK_EQ(sample_rate_hz_, sample_rate_hz);
- RTC_CHECK_EQ(num_capture_channels_, num_channels);
-
- capture_mangler_->ProcessChunk(audio, temp_capture_out_buffer_.channels());
-}
-
-void IntelligibilityEnhancer::DispatchAudio(
- IntelligibilityEnhancer::AudioSource source,
- const complex<float>* in_block,
- complex<float>* out_block) {
- switch (source) {
- case kRenderStream:
- ProcessClearBlock(in_block, out_block);
- break;
- case kCaptureStream:
- ProcessNoiseBlock(in_block, out_block);
- break;
- }
-}
-
-void IntelligibilityEnhancer::ProcessClearBlock(const complex<float>* in_block,
- complex<float>* out_block) {
- if (block_count_ < 2) {
- memset(out_block, 0, freqs_ * sizeof(*out_block));
- ++block_count_;
- return;
- }
-
- // TODO(ekm): Use VAD to |Step| and |AnalyzeClearBlock| only if necessary.
- if (true) {
- clear_variance_.Step(in_block, false);
- if (block_count_ % analysis_rate_ == analysis_rate_ - 1) {
- const float power_target = std::accumulate(
- clear_variance_.variance(), clear_variance_.variance() + freqs_, 0.f);
- AnalyzeClearBlock(power_target);
- ++analysis_step_;
- }
- ++block_count_;
- }
-
- if (active_) {
- gain_applier_.Apply(in_block, out_block);
- }
-}
-
-void IntelligibilityEnhancer::AnalyzeClearBlock(float power_target) {
- FilterVariance(clear_variance_.variance(), filtered_clear_var_.get());
- FilterVariance(noise_variance_.variance(), filtered_noise_var_.get());
-
- SolveForGainsGivenLambda(kLambdaTop, start_freq_, gains_eq_.get());
- const float power_top =
- DotProduct(gains_eq_.get(), filtered_clear_var_.get(), bank_size_);
- SolveForGainsGivenLambda(kLambdaBot, start_freq_, gains_eq_.get());
- const float power_bot =
- DotProduct(gains_eq_.get(), filtered_clear_var_.get(), bank_size_);
- if (power_target >= power_bot && power_target <= power_top) {
- SolveForLambda(power_target, power_bot, power_top);
- UpdateErbGains();
- } // Else experiencing variance underflow, so do nothing.
-}
-
-void IntelligibilityEnhancer::SolveForLambda(float power_target,
- float power_bot,
- float power_top) {
- const float kConvergeThresh = 0.001f; // TODO(ekmeyerson): Find best values
- const int kMaxIters = 100; // for these, based on experiments.
-
- const float reciprocal_power_target = 1.f / power_target;
- float lambda_bot = kLambdaBot;
- float lambda_top = kLambdaTop;
- float power_ratio = 2.0f; // Ratio of achieved power to target power.
- int iters = 0;
- while (std::fabs(power_ratio - 1.0f) > kConvergeThresh &&
- iters <= kMaxIters) {
- const float lambda = lambda_bot + (lambda_top - lambda_bot) / 2.0f;
- SolveForGainsGivenLambda(lambda, start_freq_, gains_eq_.get());
- const float power =
- DotProduct(gains_eq_.get(), filtered_clear_var_.get(), bank_size_);
- if (power < power_target) {
- lambda_bot = lambda;
- } else {
- lambda_top = lambda;
- }
- power_ratio = std::fabs(power * reciprocal_power_target);
- ++iters;
- }
-}
-
-void IntelligibilityEnhancer::UpdateErbGains() {
- // (ERB gain) = filterbank' * (freq gain)
- float* gains = gain_applier_.target();
- for (size_t i = 0; i < freqs_; ++i) {
- gains[i] = 0.0f;
- for (size_t j = 0; j < bank_size_; ++j) {
- gains[i] = fmaf(filter_bank_[j][i], gains_eq_[j], gains[i]);
- }
- }
-}
-
-void IntelligibilityEnhancer::ProcessNoiseBlock(const complex<float>* in_block,
- complex<float>* /*out_block*/) {
- noise_variance_.Step(in_block);
-}
-
-size_t IntelligibilityEnhancer::GetBankSize(int sample_rate,
- size_t erb_resolution) {
- float freq_limit = sample_rate / 2000.0f;
- size_t erb_scale = static_cast<size_t>(ceilf(
- 11.17f * logf((freq_limit + 0.312f) / (freq_limit + 14.6575f)) + 43.0f));
- return erb_scale * erb_resolution;
-}
-
-void IntelligibilityEnhancer::CreateErbBank() {
- size_t lf = 1, rf = 4;
-
- for (size_t i = 0; i < bank_size_; ++i) {
- float abs_temp = fabsf((i + 1.0f) / static_cast<float>(erb_resolution_));
- center_freqs_[i] = 676170.4f / (47.06538f - expf(0.08950404f * abs_temp));
- center_freqs_[i] -= 14678.49f;
- }
- float last_center_freq = center_freqs_[bank_size_ - 1];
- for (size_t i = 0; i < bank_size_; ++i) {
- center_freqs_[i] *= 0.5f * sample_rate_hz_ / last_center_freq;
- }
-
- for (size_t i = 0; i < bank_size_; ++i) {
- filter_bank_[i].resize(freqs_);
- }
-
- for (size_t i = 1; i <= bank_size_; ++i) {
- size_t lll, ll, rr, rrr;
- static const size_t kOne = 1; // Avoids repeated static_cast<>s below.
- lll = static_cast<size_t>(round(
- center_freqs_[max(kOne, i - lf) - 1] * freqs_ /
- (0.5f * sample_rate_hz_)));
- ll = static_cast<size_t>(round(
- center_freqs_[max(kOne, i) - 1] * freqs_ / (0.5f * sample_rate_hz_)));
- lll = min(freqs_, max(lll, kOne)) - 1;
- ll = min(freqs_, max(ll, kOne)) - 1;
-
- rrr = static_cast<size_t>(round(
- center_freqs_[min(bank_size_, i + rf) - 1] * freqs_ /
- (0.5f * sample_rate_hz_)));
- rr = static_cast<size_t>(round(
- center_freqs_[min(bank_size_, i + 1) - 1] * freqs_ /
- (0.5f * sample_rate_hz_)));
- rrr = min(freqs_, max(rrr, kOne)) - 1;
- rr = min(freqs_, max(rr, kOne)) - 1;
-
- float step, element;
-
- step = 1.0f / (ll - lll);
- element = 0.0f;
- for (size_t j = lll; j <= ll; ++j) {
- filter_bank_[i - 1][j] = element;
- element += step;
- }
- step = 1.0f / (rrr - rr);
- element = 1.0f;
- for (size_t j = rr; j <= rrr; ++j) {
- filter_bank_[i - 1][j] = element;
- element -= step;
- }
- for (size_t j = ll; j <= rr; ++j) {
- filter_bank_[i - 1][j] = 1.0f;
- }
- }
-
- float sum;
- for (size_t i = 0; i < freqs_; ++i) {
- sum = 0.0f;
- for (size_t j = 0; j < bank_size_; ++j) {
- sum += filter_bank_[j][i];
- }
- for (size_t j = 0; j < bank_size_; ++j) {
- filter_bank_[j][i] /= sum;
- }
- }
-}
-
-void IntelligibilityEnhancer::SolveForGainsGivenLambda(float lambda,
- size_t start_freq,
- float* sols) {
- bool quadratic = (kConfigRho < 1.0f);
- const float* var_x0 = filtered_clear_var_.get();
- const float* var_n0 = filtered_noise_var_.get();
-
- for (size_t n = 0; n < start_freq; ++n) {
- sols[n] = 1.0f;
- }
-
- // Analytic solution for optimal gains. See paper for derivation.
- for (size_t n = start_freq - 1; n < bank_size_; ++n) {
- float alpha0, beta0, gamma0;
- gamma0 = 0.5f * rho_[n] * var_x0[n] * var_n0[n] +
- lambda * var_x0[n] * var_n0[n] * var_n0[n];
- beta0 = lambda * var_x0[n] * (2 - rho_[n]) * var_x0[n] * var_n0[n];
- if (quadratic) {
- alpha0 = lambda * var_x0[n] * (1 - rho_[n]) * var_x0[n] * var_x0[n];
- sols[n] =
- (-beta0 - sqrtf(beta0 * beta0 - 4 * alpha0 * gamma0)) / (2 * alpha0);
- } else {
- sols[n] = -gamma0 / beta0;
- }
- sols[n] = fmax(0, sols[n]);
- }
-}
-
-void IntelligibilityEnhancer::FilterVariance(const float* var, float* result) {
- RTC_DCHECK_GT(freqs_, 0u);
- for (size_t i = 0; i < bank_size_; ++i) {
- result[i] = DotProduct(&filter_bank_[i][0], var, freqs_);
- }
-}
-
-float IntelligibilityEnhancer::DotProduct(const float* a,
- const float* b,
- size_t length) {
- float ret = 0.0f;
-
- for (size_t i = 0; i < length; ++i) {
- ret = fmaf(a[i], b[i], ret);
- }
- return ret;
-}
-
-bool IntelligibilityEnhancer::active() const {
- return active_;
-}
-
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h b/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h
deleted file mode 100644
index 0215426..0000000
--- a/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-//
-// Specifies core class for intelligbility enhancement.
-//
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_ENHANCER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_ENHANCER_H_
-
-#include <complex>
-#include <vector>
-
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/lapped_transform.h"
-#include "webrtc/common_audio/channel_buffer.h"
-#include "webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h"
-
-namespace webrtc {
-
-// Speech intelligibility enhancement module. Reads render and capture
-// audio streams and modifies the render stream with a set of gains per
-// frequency bin to enhance speech against the noise background.
-// Note: assumes speech and noise streams are already separated.
-class IntelligibilityEnhancer {
- public:
- struct Config {
- // |var_*| are parameters for the VarianceArray constructor for the
- // clear speech stream.
- // TODO(bercic): the |var_*|, |*_rate| and |gain_limit| parameters should
- // probably go away once fine tuning is done.
- Config()
- : sample_rate_hz(16000),
- num_capture_channels(1),
- num_render_channels(1),
- var_type(intelligibility::VarianceArray::kStepDecaying),
- var_decay_rate(0.9f),
- var_window_size(10),
- analysis_rate(800),
- gain_change_limit(0.1f),
- rho(0.02f) {}
- int sample_rate_hz;
- int num_capture_channels;
- int num_render_channels;
- intelligibility::VarianceArray::StepType var_type;
- float var_decay_rate;
- size_t var_window_size;
- int analysis_rate;
- float gain_change_limit;
- float rho;
- };
-
- explicit IntelligibilityEnhancer(const Config& config);
- IntelligibilityEnhancer(); // Initialize with default config.
-
- // Reads and processes chunk of noise stream in time domain.
- void AnalyzeCaptureAudio(float* const* audio,
- int sample_rate_hz,
- int num_channels);
-
- // Reads chunk of speech in time domain and updates with modified signal.
- void ProcessRenderAudio(float* const* audio,
- int sample_rate_hz,
- int num_channels);
- bool active() const;
-
- private:
- enum AudioSource {
- kRenderStream = 0, // Clear speech stream.
- kCaptureStream, // Noise stream.
- };
-
- // Provides access point to the frequency domain.
- class TransformCallback : public LappedTransform::Callback {
- public:
- TransformCallback(IntelligibilityEnhancer* parent, AudioSource source);
-
- // All in frequency domain, receives input |in_block|, applies
- // intelligibility enhancement, and writes result to |out_block|.
- void ProcessAudioBlock(const std::complex<float>* const* in_block,
- int in_channels,
- size_t frames,
- int out_channels,
- std::complex<float>* const* out_block) override;
-
- private:
- IntelligibilityEnhancer* parent_;
- AudioSource source_;
- };
- friend class TransformCallback;
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
- FRIEND_TEST_ALL_PREFIXES(IntelligibilityEnhancerTest, TestErbCreation);
- FRIEND_TEST_ALL_PREFIXES(IntelligibilityEnhancerTest, TestSolveForGains);
-#endif
-
- // Sends streams to ProcessClearBlock or ProcessNoiseBlock based on source.
- void DispatchAudio(AudioSource source,
- const std::complex<float>* in_block,
- std::complex<float>* out_block);
-
- // Updates variance computation and analysis with |in_block_|,
- // and writes modified speech to |out_block|.
- void ProcessClearBlock(const std::complex<float>* in_block,
- std::complex<float>* out_block);
-
- // Computes and sets modified gains.
- void AnalyzeClearBlock(float power_target);
-
- // Bisection search for optimal |lambda|.
- void SolveForLambda(float power_target, float power_bot, float power_top);
-
- // Transforms freq gains to ERB gains.
- void UpdateErbGains();
-
- // Updates variance calculation for noise input with |in_block|.
- void ProcessNoiseBlock(const std::complex<float>* in_block,
- std::complex<float>* out_block);
-
- // Returns number of ERB filters.
- static size_t GetBankSize(int sample_rate, size_t erb_resolution);
-
- // Initializes ERB filterbank.
- void CreateErbBank();
-
- // Analytically solves quadratic for optimal gains given |lambda|.
- // Negative gains are set to 0. Stores the results in |sols|.
- void SolveForGainsGivenLambda(float lambda, size_t start_freq, float* sols);
-
- // Computes variance across ERB filters from freq variance |var|.
- // Stores in |result|.
- void FilterVariance(const float* var, float* result);
-
- // Returns dot product of vectors specified by size |length| arrays |a|,|b|.
- static float DotProduct(const float* a, const float* b, size_t length);
-
- const size_t freqs_; // Num frequencies in frequency domain.
- const size_t window_size_; // Window size in samples; also the block size.
- const size_t chunk_length_; // Chunk size in samples.
- const size_t bank_size_; // Num ERB filters.
- const int sample_rate_hz_;
- const int erb_resolution_;
- const int num_capture_channels_;
- const int num_render_channels_;
- const int analysis_rate_; // Num blocks before gains recalculated.
-
- const bool active_; // Whether render gains are being updated.
- // TODO(ekm): Add logic for updating |active_|.
-
- intelligibility::VarianceArray clear_variance_;
- intelligibility::VarianceArray noise_variance_;
- rtc::scoped_ptr<float[]> filtered_clear_var_;
- rtc::scoped_ptr<float[]> filtered_noise_var_;
- std::vector<std::vector<float>> filter_bank_;
- rtc::scoped_ptr<float[]> center_freqs_;
- size_t start_freq_;
- rtc::scoped_ptr<float[]> rho_; // Production and interpretation SNR.
- // for each ERB band.
- rtc::scoped_ptr<float[]> gains_eq_; // Pre-filter modified gains.
- intelligibility::GainApplier gain_applier_;
-
- // Destination buffers used to reassemble blocked chunks before overwriting
- // the original input array with modifications.
- ChannelBuffer<float> temp_render_out_buffer_;
- ChannelBuffer<float> temp_capture_out_buffer_;
-
- rtc::scoped_ptr<float[]> kbd_window_;
- TransformCallback render_callback_;
- TransformCallback capture_callback_;
- rtc::scoped_ptr<LappedTransform> render_mangler_;
- rtc::scoped_ptr<LappedTransform> capture_mangler_;
- int block_count_;
- int analysis_step_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_ENHANCER_H_
diff --git a/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc b/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc
deleted file mode 100644
index 7da9b95..0000000
--- a/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-//
-// Implements helper functions and classes for intelligibility enhancement.
-//
-
-#include "webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h"
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <algorithm>
-
-using std::complex;
-using std::min;
-
-namespace webrtc {
-
-namespace intelligibility {
-
-float UpdateFactor(float target, float current, float limit) {
- float delta = fabsf(target - current);
- float sign = copysign(1.0f, target - current);
- return current + sign * fminf(delta, limit);
-}
-
-float AddDitherIfZero(float value) {
- return value == 0.f ? std::rand() * 0.01f / RAND_MAX : value;
-}
-
-complex<float> zerofudge(complex<float> c) {
- return complex<float>(AddDitherIfZero(c.real()), AddDitherIfZero(c.imag()));
-}
-
-complex<float> NewMean(complex<float> mean, complex<float> data, size_t count) {
- return mean + (data - mean) / static_cast<float>(count);
-}
-
-void AddToMean(complex<float> data, size_t count, complex<float>* mean) {
- (*mean) = NewMean(*mean, data, count);
-}
-
-
-static const size_t kWindowBlockSize = 10;
-
-VarianceArray::VarianceArray(size_t num_freqs,
- StepType type,
- size_t window_size,
- float decay)
- : running_mean_(new complex<float>[num_freqs]()),
- running_mean_sq_(new complex<float>[num_freqs]()),
- sub_running_mean_(new complex<float>[num_freqs]()),
- sub_running_mean_sq_(new complex<float>[num_freqs]()),
- variance_(new float[num_freqs]()),
- conj_sum_(new float[num_freqs]()),
- num_freqs_(num_freqs),
- window_size_(window_size),
- decay_(decay),
- history_cursor_(0),
- count_(0),
- array_mean_(0.0f),
- buffer_full_(false) {
- history_.reset(new rtc::scoped_ptr<complex<float>[]>[num_freqs_]());
- for (size_t i = 0; i < num_freqs_; ++i) {
- history_[i].reset(new complex<float>[window_size_]());
- }
- subhistory_.reset(new rtc::scoped_ptr<complex<float>[]>[num_freqs_]());
- for (size_t i = 0; i < num_freqs_; ++i) {
- subhistory_[i].reset(new complex<float>[window_size_]());
- }
- subhistory_sq_.reset(new rtc::scoped_ptr<complex<float>[]>[num_freqs_]());
- for (size_t i = 0; i < num_freqs_; ++i) {
- subhistory_sq_[i].reset(new complex<float>[window_size_]());
- }
- switch (type) {
- case kStepInfinite:
- step_func_ = &VarianceArray::InfiniteStep;
- break;
- case kStepDecaying:
- step_func_ = &VarianceArray::DecayStep;
- break;
- case kStepWindowed:
- step_func_ = &VarianceArray::WindowedStep;
- break;
- case kStepBlocked:
- step_func_ = &VarianceArray::BlockedStep;
- break;
- case kStepBlockBasedMovingAverage:
- step_func_ = &VarianceArray::BlockBasedMovingAverage;
- break;
- }
-}
-
-// Compute the variance with Welford's algorithm, adding some fudge to
-// the input in case of all-zeroes.
-void VarianceArray::InfiniteStep(const complex<float>* data, bool skip_fudge) {
- array_mean_ = 0.0f;
- ++count_;
- for (size_t i = 0; i < num_freqs_; ++i) {
- complex<float> sample = data[i];
- if (!skip_fudge) {
- sample = zerofudge(sample);
- }
- if (count_ == 1) {
- running_mean_[i] = sample;
- variance_[i] = 0.0f;
- } else {
- float old_sum = conj_sum_[i];
- complex<float> old_mean = running_mean_[i];
- running_mean_[i] =
- old_mean + (sample - old_mean) / static_cast<float>(count_);
- conj_sum_[i] =
- (old_sum + std::conj(sample - old_mean) * (sample - running_mean_[i]))
- .real();
- variance_[i] =
- conj_sum_[i] / (count_ - 1);
- }
- array_mean_ += (variance_[i] - array_mean_) / (i + 1);
- }
-}
-
-// Compute the variance from the beginning, with exponential decaying of the
-// series data.
-void VarianceArray::DecayStep(const complex<float>* data, bool /*dummy*/) {
- array_mean_ = 0.0f;
- ++count_;
- for (size_t i = 0; i < num_freqs_; ++i) {
- complex<float> sample = data[i];
- sample = zerofudge(sample);
-
- if (count_ == 1) {
- running_mean_[i] = sample;
- running_mean_sq_[i] = sample * std::conj(sample);
- variance_[i] = 0.0f;
- } else {
- complex<float> prev = running_mean_[i];
- complex<float> prev2 = running_mean_sq_[i];
- running_mean_[i] = decay_ * prev + (1.0f - decay_) * sample;
- running_mean_sq_[i] =
- decay_ * prev2 + (1.0f - decay_) * sample * std::conj(sample);
- variance_[i] = (running_mean_sq_[i] -
- running_mean_[i] * std::conj(running_mean_[i])).real();
- }
-
- array_mean_ += (variance_[i] - array_mean_) / (i + 1);
- }
-}
-
-// Windowed variance computation. On each step, the variances for the
-// window are recomputed from scratch, using Welford's algorithm.
-void VarianceArray::WindowedStep(const complex<float>* data, bool /*dummy*/) {
- size_t num = min(count_ + 1, window_size_);
- array_mean_ = 0.0f;
- for (size_t i = 0; i < num_freqs_; ++i) {
- complex<float> mean;
- float conj_sum = 0.0f;
-
- history_[i][history_cursor_] = data[i];
-
- mean = history_[i][history_cursor_];
- variance_[i] = 0.0f;
- for (size_t j = 1; j < num; ++j) {
- complex<float> sample =
- zerofudge(history_[i][(history_cursor_ + j) % window_size_]);
- sample = history_[i][(history_cursor_ + j) % window_size_];
- float old_sum = conj_sum;
- complex<float> old_mean = mean;
-
- mean = old_mean + (sample - old_mean) / static_cast<float>(j + 1);
- conj_sum =
- (old_sum + std::conj(sample - old_mean) * (sample - mean)).real();
- variance_[i] = conj_sum / (j);
- }
- array_mean_ += (variance_[i] - array_mean_) / (i + 1);
- }
- history_cursor_ = (history_cursor_ + 1) % window_size_;
- ++count_;
-}
-
-// Variance with a window of blocks. Within each block, the variances are
-// recomputed from scratch at every stp, using |Var(X) = E(X^2) - E^2(X)|.
-// Once a block is filled with kWindowBlockSize samples, it is added to the
-// history window and a new block is started. The variances for the window
-// are recomputed from scratch at each of these transitions.
-void VarianceArray::BlockedStep(const complex<float>* data, bool /*dummy*/) {
- size_t blocks = min(window_size_, history_cursor_ + 1);
- for (size_t i = 0; i < num_freqs_; ++i) {
- AddToMean(data[i], count_ + 1, &sub_running_mean_[i]);
- AddToMean(data[i] * std::conj(data[i]), count_ + 1,
- &sub_running_mean_sq_[i]);
- subhistory_[i][history_cursor_ % window_size_] = sub_running_mean_[i];
- subhistory_sq_[i][history_cursor_ % window_size_] = sub_running_mean_sq_[i];
-
- variance_[i] =
- (NewMean(running_mean_sq_[i], sub_running_mean_sq_[i], blocks) -
- NewMean(running_mean_[i], sub_running_mean_[i], blocks) *
- std::conj(NewMean(running_mean_[i], sub_running_mean_[i], blocks)))
- .real();
- if (count_ == kWindowBlockSize - 1) {
- sub_running_mean_[i] = complex<float>(0.0f, 0.0f);
- sub_running_mean_sq_[i] = complex<float>(0.0f, 0.0f);
- running_mean_[i] = complex<float>(0.0f, 0.0f);
- running_mean_sq_[i] = complex<float>(0.0f, 0.0f);
- for (size_t j = 0; j < min(window_size_, history_cursor_); ++j) {
- AddToMean(subhistory_[i][j], j + 1, &running_mean_[i]);
- AddToMean(subhistory_sq_[i][j], j + 1, &running_mean_sq_[i]);
- }
- ++history_cursor_;
- }
- }
- ++count_;
- if (count_ == kWindowBlockSize) {
- count_ = 0;
- }
-}
-
-// Recomputes variances for each window from scratch based on previous window.
-void VarianceArray::BlockBasedMovingAverage(const std::complex<float>* data,
- bool /*dummy*/) {
- // TODO(ekmeyerson) To mitigate potential divergence, add counter so that
- // after every so often sums are computed scratch by summing over all
- // elements instead of subtracting oldest and adding newest.
- for (size_t i = 0; i < num_freqs_; ++i) {
- sub_running_mean_[i] += data[i];
- sub_running_mean_sq_[i] += data[i] * std::conj(data[i]);
- }
- ++count_;
-
- // TODO(ekmeyerson) Make kWindowBlockSize nonconstant to allow
- // experimentation with different block size,window size pairs.
- if (count_ >= kWindowBlockSize) {
- count_ = 0;
-
- for (size_t i = 0; i < num_freqs_; ++i) {
- running_mean_[i] -= subhistory_[i][history_cursor_];
- running_mean_sq_[i] -= subhistory_sq_[i][history_cursor_];
-
- float scale = 1.f / kWindowBlockSize;
- subhistory_[i][history_cursor_] = sub_running_mean_[i] * scale;
- subhistory_sq_[i][history_cursor_] = sub_running_mean_sq_[i] * scale;
-
- sub_running_mean_[i] = std::complex<float>(0.0f, 0.0f);
- sub_running_mean_sq_[i] = std::complex<float>(0.0f, 0.0f);
-
- running_mean_[i] += subhistory_[i][history_cursor_];
- running_mean_sq_[i] += subhistory_sq_[i][history_cursor_];
-
- scale = 1.f / (buffer_full_ ? window_size_ : history_cursor_ + 1);
- variance_[i] = std::real(running_mean_sq_[i] * scale -
- running_mean_[i] * scale *
- std::conj(running_mean_[i]) * scale);
- }
-
- ++history_cursor_;
- if (history_cursor_ >= window_size_) {
- buffer_full_ = true;
- history_cursor_ = 0;
- }
- }
-}
-
-void VarianceArray::Clear() {
- memset(running_mean_.get(), 0, sizeof(*running_mean_.get()) * num_freqs_);
- memset(running_mean_sq_.get(), 0,
- sizeof(*running_mean_sq_.get()) * num_freqs_);
- memset(variance_.get(), 0, sizeof(*variance_.get()) * num_freqs_);
- memset(conj_sum_.get(), 0, sizeof(*conj_sum_.get()) * num_freqs_);
- history_cursor_ = 0;
- count_ = 0;
- array_mean_ = 0.0f;
-}
-
-void VarianceArray::ApplyScale(float scale) {
- array_mean_ = 0.0f;
- for (size_t i = 0; i < num_freqs_; ++i) {
- variance_[i] *= scale * scale;
- array_mean_ += (variance_[i] - array_mean_) / (i + 1);
- }
-}
-
-GainApplier::GainApplier(size_t freqs, float change_limit)
- : num_freqs_(freqs),
- change_limit_(change_limit),
- target_(new float[freqs]()),
- current_(new float[freqs]()) {
- for (size_t i = 0; i < freqs; ++i) {
- target_[i] = 1.0f;
- current_[i] = 1.0f;
- }
-}
-
-void GainApplier::Apply(const complex<float>* in_block,
- complex<float>* out_block) {
- for (size_t i = 0; i < num_freqs_; ++i) {
- float factor = sqrtf(fabsf(current_[i]));
- if (!std::isnormal(factor)) {
- factor = 1.0f;
- }
- out_block[i] = factor * in_block[i];
- current_[i] = UpdateFactor(target_[i], current_[i], change_limit_);
- }
-}
-
-} // namespace intelligibility
-
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h b/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h
deleted file mode 100644
index 4ac1167..0000000
--- a/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-//
-// Specifies helper classes for intelligibility enhancement.
-//
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_UTILS_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_UTILS_H_
-
-#include <complex>
-
-#include "webrtc/base/scoped_ptr.h"
-
-namespace webrtc {
-
-namespace intelligibility {
-
-// Return |current| changed towards |target|, with the change being at most
-// |limit|.
-float UpdateFactor(float target, float current, float limit);
-
-// Apply a small fudge to degenerate complex values. The numbers in the array
-// were chosen randomly, so that even a series of all zeroes has some small
-// variability.
-std::complex<float> zerofudge(std::complex<float> c);
-
-// Incremental mean computation. Return the mean of the series with the
-// mean |mean| with added |data|.
-std::complex<float> NewMean(std::complex<float> mean,
- std::complex<float> data,
- size_t count);
-
-// Updates |mean| with added |data|;
-void AddToMean(std::complex<float> data,
- size_t count,
- std::complex<float>* mean);
-
-// Internal helper for computing the variances of a stream of arrays.
-// The result is an array of variances per position: the i-th variance
-// is the variance of the stream of data on the i-th positions in the
-// input arrays.
-// There are four methods of computation:
-// * kStepInfinite computes variances from the beginning onwards
-// * kStepDecaying uses a recursive exponential decay formula with a
-// settable forgetting factor
-// * kStepWindowed computes variances within a moving window
-// * kStepBlocked is similar to kStepWindowed, but history is kept
-// as a rolling window of blocks: multiple input elements are used for
-// one block and the history then consists of the variances of these blocks
-// with the same effect as kStepWindowed, but less storage, so the window
-// can be longer
-class VarianceArray {
- public:
- enum StepType {
- kStepInfinite = 0,
- kStepDecaying,
- kStepWindowed,
- kStepBlocked,
- kStepBlockBasedMovingAverage
- };
-
- // Construct an instance for the given input array length (|freqs|) and
- // computation algorithm (|type|), with the appropriate parameters.
- // |window_size| is the number of samples for kStepWindowed and
- // the number of blocks for kStepBlocked. |decay| is the forgetting factor
- // for kStepDecaying.
- VarianceArray(size_t freqs, StepType type, size_t window_size, float decay);
-
- // Add a new data point to the series and compute the new variances.
- // TODO(bercic) |skip_fudge| is a flag for kStepWindowed and kStepDecaying,
- // whether they should skip adding some small dummy values to the input
- // to prevent problems with all-zero inputs. Can probably be removed.
- void Step(const std::complex<float>* data, bool skip_fudge = false) {
- (this->*step_func_)(data, skip_fudge);
- }
- // Reset variances to zero and forget all history.
- void Clear();
- // Scale the input data by |scale|. Effectively multiply variances
- // by |scale^2|.
- void ApplyScale(float scale);
-
- // The current set of variances.
- const float* variance() const { return variance_.get(); }
-
- // The mean value of the current set of variances.
- float array_mean() const { return array_mean_; }
-
- private:
- void InfiniteStep(const std::complex<float>* data, bool dummy);
- void DecayStep(const std::complex<float>* data, bool dummy);
- void WindowedStep(const std::complex<float>* data, bool dummy);
- void BlockedStep(const std::complex<float>* data, bool dummy);
- void BlockBasedMovingAverage(const std::complex<float>* data, bool dummy);
-
- // TODO(ekmeyerson): Switch the following running means
- // and histories from rtc::scoped_ptr to std::vector.
-
- // The current average X and X^2.
- rtc::scoped_ptr<std::complex<float>[]> running_mean_;
- rtc::scoped_ptr<std::complex<float>[]> running_mean_sq_;
-
- // Average X and X^2 for the current block in kStepBlocked.
- rtc::scoped_ptr<std::complex<float>[]> sub_running_mean_;
- rtc::scoped_ptr<std::complex<float>[]> sub_running_mean_sq_;
-
- // Sample history for the rolling window in kStepWindowed and block-wise
- // histories for kStepBlocked.
- rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> history_;
- rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> subhistory_;
- rtc::scoped_ptr<rtc::scoped_ptr<std::complex<float>[]>[]> subhistory_sq_;
-
- // The current set of variances and sums for Welford's algorithm.
- rtc::scoped_ptr<float[]> variance_;
- rtc::scoped_ptr<float[]> conj_sum_;
-
- const size_t num_freqs_;
- const size_t window_size_;
- const float decay_;
- size_t history_cursor_;
- size_t count_;
- float array_mean_;
- bool buffer_full_;
- void (VarianceArray::*step_func_)(const std::complex<float>*, bool);
-};
-
-// Helper class for smoothing gain changes. On each applicatiion step, the
-// currently used gains are changed towards a set of settable target gains,
-// constrained by a limit on the magnitude of the changes.
-class GainApplier {
- public:
- GainApplier(size_t freqs, float change_limit);
-
- // Copy |in_block| to |out_block|, multiplied by the current set of gains,
- // and step the current set of gains towards the target set.
- void Apply(const std::complex<float>* in_block,
- std::complex<float>* out_block);
-
- // Return the current target gain set. Modify this array to set the targets.
- float* target() const { return target_.get(); }
-
- private:
- const size_t num_freqs_;
- const float change_limit_;
- rtc::scoped_ptr<float[]> target_;
- rtc::scoped_ptr<float[]> current_;
-};
-
-} // namespace intelligibility
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_INTELLIGIBILITY_INTELLIGIBILITY_UTILS_H_
diff --git a/webrtc/modules/audio_processing/level_estimator.cc b/webrtc/modules/audio_processing/level_estimator.cc
new file mode 100644
index 0000000..e707288
--- /dev/null
+++ b/webrtc/modules/audio_processing/level_estimator.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/level_estimator.h"
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+LevelEstimator::LevelEstimator() {
+ rms_.Reset();
+}
+
+LevelEstimator::~LevelEstimator() = default;
+
+void LevelEstimator::ProcessStream(const AudioBuffer& audio) {
+ for (size_t i = 0; i < audio.num_channels(); i++) {
+ rms_.Analyze(rtc::ArrayView<const float>(audio.channels_const()[i],
+ audio.num_frames()));
+ }
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/level_estimator.h b/webrtc/modules/audio_processing/level_estimator.h
new file mode 100644
index 0000000..1d8a071
--- /dev/null
+++ b/webrtc/modules/audio_processing/level_estimator.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_H_
+
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/rms_level.h"
+
+namespace webrtc {
+
+// An estimation component used to retrieve level metrics.
+class LevelEstimator {
+ public:
+ LevelEstimator();
+ ~LevelEstimator();
+
+ LevelEstimator(LevelEstimator&) = delete;
+ LevelEstimator& operator=(LevelEstimator&) = delete;
+
+ void ProcessStream(const AudioBuffer& audio);
+
+ // Returns the root mean square (RMS) level in dBFs (decibels from digital
+ // full-scale), or alternately dBov. It is computed over all primary stream
+ // frames since the last call to RMS(). The returned value is positive but
+ // should be interpreted as negative. It is constrained to [0, 127].
+ //
+ // The computation follows: https://tools.ietf.org/html/rfc6465
+ // with the intent that it can provide the RTP audio level indication.
+ //
+ // Frames passed to ProcessStream() with an |_energy| of zero are considered
+ // to have been muted. The RMS of the frame will be interpreted as -127.
+ int RMS() { return rms_.Average(); }
+
+ private:
+ RmsLevel rms_;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/level_estimator_impl.cc b/webrtc/modules/audio_processing/level_estimator_impl.cc
deleted file mode 100644
index 35fe697..0000000
--- a/webrtc/modules/audio_processing/level_estimator_impl.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/level_estimator_impl.h"
-
-#include "webrtc/modules/audio_processing/audio_buffer.h"
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/rms_level.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-
-namespace webrtc {
-
-LevelEstimatorImpl::LevelEstimatorImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit)
- : ProcessingComponent(),
- crit_(crit) {}
-
-LevelEstimatorImpl::~LevelEstimatorImpl() {}
-
-int LevelEstimatorImpl::ProcessStream(AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return AudioProcessing::kNoError;
- }
-
- RMSLevel* rms_level = static_cast<RMSLevel*>(handle(0));
- for (int i = 0; i < audio->num_channels(); ++i) {
- rms_level->Process(audio->channels_const()[i],
- audio->num_frames());
- }
-
- return AudioProcessing::kNoError;
-}
-
-int LevelEstimatorImpl::Enable(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- return EnableComponent(enable);
-}
-
-bool LevelEstimatorImpl::is_enabled() const {
- return is_component_enabled();
-}
-
-int LevelEstimatorImpl::RMS() {
- if (!is_component_enabled()) {
- return AudioProcessing::kNotEnabledError;
- }
-
- RMSLevel* rms_level = static_cast<RMSLevel*>(handle(0));
- return rms_level->RMS();
-}
-
-// The ProcessingComponent implementation is pretty weird in this class since
-// we have only a single instance of the trivial underlying component.
-void* LevelEstimatorImpl::CreateHandle() const {
- return new RMSLevel;
-}
-
-void LevelEstimatorImpl::DestroyHandle(void* handle) const {
- delete static_cast<RMSLevel*>(handle);
-}
-
-int LevelEstimatorImpl::InitializeHandle(void* handle) const {
- static_cast<RMSLevel*>(handle)->Reset();
- return AudioProcessing::kNoError;
-}
-
-int LevelEstimatorImpl::ConfigureHandle(void* /*handle*/) const {
- return AudioProcessing::kNoError;
-}
-
-int LevelEstimatorImpl::num_handles_required() const {
- return 1;
-}
-
-int LevelEstimatorImpl::GetHandleError(void* /*handle*/) const {
- return AudioProcessing::kUnspecifiedError;
-}
-
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/level_estimator_impl.h b/webrtc/modules/audio_processing/level_estimator_impl.h
deleted file mode 100644
index 0d0050c..0000000
--- a/webrtc/modules/audio_processing/level_estimator_impl.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_IMPL_H_
-
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/processing_component.h"
-#include "webrtc/modules/audio_processing/rms_level.h"
-
-namespace webrtc {
-
-class AudioBuffer;
-class CriticalSectionWrapper;
-
-class LevelEstimatorImpl : public LevelEstimator,
- public ProcessingComponent {
- public:
- LevelEstimatorImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit);
- virtual ~LevelEstimatorImpl();
-
- int ProcessStream(AudioBuffer* audio);
-
- // LevelEstimator implementation.
- bool is_enabled() const override;
-
- private:
- // LevelEstimator implementation.
- int Enable(bool enable) override;
- int RMS() override;
-
- // ProcessingComponent implementation.
- void* CreateHandle() const override;
- int InitializeHandle(void* handle) const override;
- int ConfigureHandle(void* handle) const override;
- void DestroyHandle(void* handle) const override;
- int num_handles_required() const override;
- int GetHandleError(void* handle) const override;
-
- CriticalSectionWrapper* crit_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_IMPL_H_
diff --git a/webrtc/modules/audio_processing/logging/aec_logging.h b/webrtc/modules/audio_processing/logging/aec_logging.h
deleted file mode 100644
index 3cf9ff8..0000000
--- a/webrtc/modules/audio_processing/logging/aec_logging.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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 WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_LOGGING_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_LOGGING_
-
-#include <stdio.h>
-
-#include "webrtc/modules/audio_processing/logging/aec_logging_file_handling.h"
-
-// To enable AEC logging, invoke GYP with -Daec_debug_dump=1.
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-// Dumps a wav data to file.
-#define RTC_AEC_DEBUG_WAV_WRITE(file, data, num_samples) \
- do { \
- rtc_WavWriteSamples(file, data, num_samples); \
- } while (0)
-
-// (Re)opens a wav file for writing using the specified sample rate.
-#define RTC_AEC_DEBUG_WAV_REOPEN(name, instance_index, process_rate, \
- sample_rate, wav_file) \
- do { \
- WebRtcAec_ReopenWav(name, instance_index, process_rate, sample_rate, \
- wav_file); \
- } while (0)
-
-// Closes a wav file.
-#define RTC_AEC_DEBUG_WAV_CLOSE(wav_file) \
- do { \
- rtc_WavClose(wav_file); \
- } while (0)
-
-// Dumps a raw data to file.
-#define RTC_AEC_DEBUG_RAW_WRITE(file, data, data_size) \
- do { \
- (void) fwrite(data, data_size, 1, file); \
- } while (0)
-
-// Opens a raw data file for writing using the specified sample rate.
-#define RTC_AEC_DEBUG_RAW_OPEN(name, instance_counter, file) \
- do { \
- WebRtcAec_RawFileOpen(name, instance_counter, file); \
- } while (0)
-
-// Closes a raw data file.
-#define RTC_AEC_DEBUG_RAW_CLOSE(file) \
- do { \
- fclose(file); \
- } while (0)
-
-#else // RTC_AEC_DEBUG_DUMP
-#define RTC_AEC_DEBUG_WAV_WRITE(file, data, num_samples) \
- do { \
- } while (0)
-
-#define RTC_AEC_DEBUG_WAV_REOPEN(wav_file, name, instance_index, process_rate, \
- sample_rate) \
- do { \
- } while (0)
-
-#define RTC_AEC_DEBUG_WAV_CLOSE(wav_file) \
- do { \
- } while (0)
-
-#define RTC_AEC_DEBUG_RAW_WRITE(file, data, data_size) \
- do { \
- } while (0)
-
-#define RTC_AEC_DEBUG_RAW_OPEN(file, name, instance_counter) \
- do { \
- } while (0)
-
-#define RTC_AEC_DEBUG_RAW_CLOSE(file) \
- do { \
- } while (0)
-
-#endif // WEBRTC_AEC_DEBUG_DUMP
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_LOGGING_
diff --git a/webrtc/modules/audio_processing/logging/aec_logging_file_handling.cc b/webrtc/modules/audio_processing/logging/aec_logging_file_handling.cc
deleted file mode 100644
index 3a43471..0000000
--- a/webrtc/modules/audio_processing/logging/aec_logging_file_handling.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 "webrtc/modules/audio_processing/logging/aec_logging_file_handling.h"
-
-#include <stdint.h>
-#include <stdio.h>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/stringutils.h"
-#include "webrtc/common_audio/wav_file.h"
-#include "webrtc/typedefs.h"
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-void WebRtcAec_ReopenWav(const char* name,
- int instance_index,
- int process_rate,
- int sample_rate,
- rtc_WavWriter** wav_file) {
- if (*wav_file) {
- if (rtc_WavSampleRate(*wav_file) == sample_rate)
- return;
- rtc_WavClose(*wav_file);
- }
- char filename[64];
- int written = rtc::sprintfn(filename, sizeof(filename), "%s%d-%d.wav", name,
- instance_index, process_rate);
-
- // Ensure there was no buffer output error.
- RTC_DCHECK_GE(written, 0);
- // Ensure that the buffer size was sufficient.
- RTC_DCHECK_LT(static_cast<size_t>(written), sizeof(filename));
-
- *wav_file = rtc_WavOpen(filename, sample_rate, 1);
-}
-
-void WebRtcAec_RawFileOpen(const char* name, int instance_index, FILE** file) {
- char filename[64];
- int written = rtc::sprintfn(filename, sizeof(filename), "%s_%d.dat", name,
- instance_index);
-
- // Ensure there was no buffer output error.
- RTC_DCHECK_GE(written, 0);
- // Ensure that the buffer size was sufficient.
- RTC_DCHECK_LT(static_cast<size_t>(written), sizeof(filename));
-
- *file = fopen(filename, "wb");
-}
-
-#endif // WEBRTC_AEC_DEBUG_DUMP
diff --git a/webrtc/modules/audio_processing/logging/aec_logging_file_handling.h b/webrtc/modules/audio_processing/logging/aec_logging_file_handling.h
deleted file mode 100644
index 5ec8394..0000000
--- a/webrtc/modules/audio_processing/logging/aec_logging_file_handling.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_LOGGING_FILE_HANDLING_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_LOGGING_FILE_HANDLING_
-
-#include <stdio.h>
-
-#include "webrtc/common_audio/wav_file.h"
-#include "webrtc/typedefs.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-// Opens a new Wav file for writing. If it was already open with a different
-// sample frequency, it closes it first.
-void WebRtcAec_ReopenWav(const char* name,
- int instance_index,
- int process_rate,
- int sample_rate,
- rtc_WavWriter** wav_file);
-
-// Opens dumpfile with instance-specific filename.
-void WebRtcAec_RawFileOpen(const char* name, int instance_index, FILE** file);
-
-#endif // WEBRTC_AEC_DEBUG_DUMP
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_LOGGING_FILE_HANDLING_
diff --git a/webrtc/modules/audio_processing/logging/apm_data_dumper.cc b/webrtc/modules/audio_processing/logging/apm_data_dumper.cc
new file mode 100644
index 0000000..917df60
--- /dev/null
+++ b/webrtc/modules/audio_processing/logging/apm_data_dumper.cc
@@ -0,0 +1,92 @@
+/*
+ * 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/audio_processing/logging/apm_data_dumper.h"
+
+#include "rtc_base/strings/string_builder.h"
+
+// Check to verify that the define is properly set.
+#if !defined(WEBRTC_APM_DEBUG_DUMP) || \
+ (WEBRTC_APM_DEBUG_DUMP != 0 && WEBRTC_APM_DEBUG_DUMP != 1)
+#error "Set WEBRTC_APM_DEBUG_DUMP to either 0 or 1"
+#endif
+
+namespace webrtc {
+namespace {
+
+#if WEBRTC_APM_DEBUG_DUMP == 1
+
+#if defined(WEBRTC_WIN)
+constexpr char kPathDelimiter = '\\';
+#else
+constexpr char kPathDelimiter = '/';
+#endif
+
+std::string FormFileName(const char* output_dir,
+ const char* name,
+ int instance_index,
+ int reinit_index,
+ const std::string& suffix) {
+ char buf[1024];
+ rtc::SimpleStringBuilder ss(buf);
+ const size_t output_dir_size = strlen(output_dir);
+ if (output_dir_size > 0) {
+ ss << output_dir;
+ if (output_dir[output_dir_size - 1] != kPathDelimiter) {
+ ss << kPathDelimiter;
+ }
+ }
+ ss << name << "_" << instance_index << "-" << reinit_index << suffix;
+ return ss.str();
+}
+#endif
+
+} // namespace
+
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ApmDataDumper::ApmDataDumper(int instance_index)
+ : instance_index_(instance_index) {}
+#else
+ApmDataDumper::ApmDataDumper(int instance_index) {}
+#endif
+
+ApmDataDumper::~ApmDataDumper() = default;
+
+#if WEBRTC_APM_DEBUG_DUMP == 1
+bool ApmDataDumper::recording_activated_ = false;
+char ApmDataDumper::output_dir_[] = "";
+
+FILE* ApmDataDumper::GetRawFile(const char* name) {
+ std::string filename = FormFileName(output_dir_, name, instance_index_,
+ recording_set_index_, ".dat");
+ auto& f = raw_files_[filename];
+ if (!f) {
+ f.reset(fopen(filename.c_str(), "wb"));
+ RTC_CHECK(f.get()) << "Cannot write to " << filename << ".";
+ }
+ return f.get();
+}
+
+WavWriter* ApmDataDumper::GetWavFile(const char* name,
+ int sample_rate_hz,
+ int num_channels,
+ WavFile::SampleFormat format) {
+ std::string filename = FormFileName(output_dir_, name, instance_index_,
+ recording_set_index_, ".wav");
+ auto& f = wav_files_[filename];
+ if (!f) {
+ f.reset(
+ new WavWriter(filename.c_str(), sample_rate_hz, num_channels, format));
+ }
+ return f.get();
+}
+#endif
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/logging/apm_data_dumper.h b/webrtc/modules/audio_processing/logging/apm_data_dumper.h
new file mode 100644
index 0000000..1824fdd
--- /dev/null
+++ b/webrtc/modules/audio_processing/logging/apm_data_dumper.h
@@ -0,0 +1,287 @@
+/*
+ * 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_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
+#define MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+#if WEBRTC_APM_DEBUG_DUMP == 1
+#include <memory>
+#include <unordered_map>
+#endif
+
+#include "api/array_view.h"
+#if WEBRTC_APM_DEBUG_DUMP == 1
+#include "common_audio/wav_file.h"
+#include "rtc_base/checks.h"
+#endif
+
+// Check to verify that the define is properly set.
+#if !defined(WEBRTC_APM_DEBUG_DUMP) || \
+ (WEBRTC_APM_DEBUG_DUMP != 0 && WEBRTC_APM_DEBUG_DUMP != 1)
+#error "Set WEBRTC_APM_DEBUG_DUMP to either 0 or 1"
+#endif
+
+namespace webrtc {
+
+#if WEBRTC_APM_DEBUG_DUMP == 1
+// Functor used to use as a custom deleter in the map of file pointers to raw
+// files.
+struct RawFileCloseFunctor {
+ void operator()(FILE* f) const { fclose(f); }
+};
+#endif
+
+// Class that handles dumping of variables into files.
+class ApmDataDumper {
+ public:
+ // Constructor that takes an instance index that may
+ // be used to distinguish data dumped from different
+ // instances of the code.
+ explicit ApmDataDumper(int instance_index);
+
+ ApmDataDumper() = delete;
+ ApmDataDumper(const ApmDataDumper&) = delete;
+ ApmDataDumper& operator=(const ApmDataDumper&) = delete;
+
+ ~ApmDataDumper();
+
+ // Activates or deactivate the dumping functionality.
+ static void SetActivated(bool activated) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ recording_activated_ = activated;
+#endif
+ }
+
+ // Set an optional output directory.
+ static void SetOutputDirectory(const std::string& output_dir) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ RTC_CHECK_LT(output_dir.size(), kOutputDirMaxLength);
+ strncpy(output_dir_, output_dir.c_str(), output_dir.size());
+#endif
+ }
+
+ // Reinitializes the data dumping such that new versions
+ // of all files being dumped to are created.
+ void InitiateNewSetOfRecordings() {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ ++recording_set_index_;
+#endif
+ }
+
+ // Methods for performing dumping of data of various types into
+ // various formats.
+ void DumpRaw(const char* name, double v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(&v, sizeof(v), 1, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, size_t v_length, const double* v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(v, sizeof(v[0]), v_length, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, rtc::ArrayView<const double> v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ DumpRaw(name, v.size(), v.data());
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, float v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(&v, sizeof(v), 1, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, size_t v_length, const float* v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(v, sizeof(v[0]), v_length, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, rtc::ArrayView<const float> v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ DumpRaw(name, v.size(), v.data());
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, bool v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ DumpRaw(name, static_cast<int16_t>(v));
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, size_t v_length, const bool* v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ for (size_t k = 0; k < v_length; ++k) {
+ int16_t value = static_cast<int16_t>(v[k]);
+ fwrite(&value, sizeof(value), 1, file);
+ }
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, rtc::ArrayView<const bool> v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ DumpRaw(name, v.size(), v.data());
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, int16_t v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(&v, sizeof(v), 1, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, size_t v_length, const int16_t* v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(v, sizeof(v[0]), v_length, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, rtc::ArrayView<const int16_t> v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ DumpRaw(name, v.size(), v.data());
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, int32_t v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(&v, sizeof(v), 1, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, size_t v_length, const int32_t* v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(v, sizeof(v[0]), v_length, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, size_t v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(&v, sizeof(v), 1, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, size_t v_length, const size_t* v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ FILE* file = GetRawFile(name);
+ fwrite(v, sizeof(v[0]), v_length, file);
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, rtc::ArrayView<const int32_t> v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ DumpRaw(name, v.size(), v.data());
+ }
+#endif
+ }
+
+ void DumpRaw(const char* name, rtc::ArrayView<const size_t> v) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ DumpRaw(name, v.size(), v.data());
+#endif
+ }
+
+ void DumpWav(const char* name,
+ size_t v_length,
+ const float* v,
+ int sample_rate_hz,
+ int num_channels) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ WavWriter* file = GetWavFile(name, sample_rate_hz, num_channels,
+ WavFile::SampleFormat::kFloat);
+ file->WriteSamples(v, v_length);
+ }
+#endif
+ }
+
+ void DumpWav(const char* name,
+ rtc::ArrayView<const float> v,
+ int sample_rate_hz,
+ int num_channels) {
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ if (recording_activated_) {
+ DumpWav(name, v.size(), v.data(), sample_rate_hz, num_channels);
+ }
+#endif
+ }
+
+ private:
+#if WEBRTC_APM_DEBUG_DUMP == 1
+ static bool recording_activated_;
+ static constexpr size_t kOutputDirMaxLength = 1024;
+ static char output_dir_[kOutputDirMaxLength];
+ const int instance_index_;
+ int recording_set_index_ = 0;
+ std::unordered_map<std::string, std::unique_ptr<FILE, RawFileCloseFunctor>>
+ raw_files_;
+ std::unordered_map<std::string, std::unique_ptr<WavWriter>> wav_files_;
+
+ FILE* GetRawFile(const char* name);
+ WavWriter* GetWavFile(const char* name,
+ int sample_rate_hz,
+ int num_channels,
+ WavFile::SampleFormat format);
+#endif
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
diff --git a/webrtc/modules/audio_processing/meson.build b/webrtc/modules/audio_processing/meson.build
index 34e23e0..8229eb3 100644
--- a/webrtc/modules/audio_processing/meson.build
+++ b/webrtc/modules/audio_processing/meson.build
@@ -1,32 +1,147 @@
+apm_flags = ['-DWEBRTC_APM_DEBUG_DUMP=0']
+
webrtc_audio_processing_sources = [
- 'aec/aec_core.c',
- 'aec/aec_rdft.c',
- 'aec/aec_resampler.c',
- 'aec/echo_cancellation.c',
- 'aecm/echo_control_mobile.c',
- 'aecm/aecm_core.c',
- 'aecm/aecm_core_c.c',
- 'agc/legacy/analog_agc.c',
- 'agc/legacy/digital_agc.c',
+ 'aec_dump/null_aec_dump_factory.cc',
+ 'aec3/adaptive_fir_filter.cc',
+ 'aec3/adaptive_fir_filter_erl.cc',
+ 'aec3/aec3_common.cc',
+ 'aec3/aec3_fft.cc',
+ 'aec3/aec_state.cc',
+ 'aec3/alignment_mixer.cc',
+ 'aec3/api_call_jitter_metrics.cc',
+ 'aec3/block_buffer.cc',
+ 'aec3/block_delay_buffer.cc',
+ 'aec3/block_framer.cc',
+ 'aec3/block_processor.cc',
+ 'aec3/block_processor_metrics.cc',
+ 'aec3/clockdrift_detector.cc',
+ 'aec3/coarse_filter_update_gain.cc',
+ 'aec3/comfort_noise_generator.cc',
+ 'aec3/decimator.cc',
+ 'aec3/dominant_nearend_detector.cc',
+ 'aec3/downsampled_render_buffer.cc',
+ 'aec3/echo_audibility.cc',
+ 'aec3/echo_canceller3.cc',
+ 'aec3/echo_path_delay_estimator.cc',
+ 'aec3/echo_path_variability.cc',
+ 'aec3/echo_remover.cc',
+ 'aec3/echo_remover_metrics.cc',
+ 'aec3/erle_estimator.cc',
+ 'aec3/erl_estimator.cc',
+ 'aec3/fft_buffer.cc',
+ 'aec3/filter_analyzer.cc',
+ 'aec3/frame_blocker.cc',
+ 'aec3/fullband_erle_estimator.cc',
+ 'aec3/matched_filter.cc',
+ 'aec3/matched_filter_lag_aggregator.cc',
+ 'aec3/moving_average.cc',
+ 'aec3/refined_filter_update_gain.cc',
+ 'aec3/render_buffer.cc',
+ 'aec3/render_delay_buffer.cc',
+ 'aec3/render_delay_controller.cc',
+ 'aec3/render_delay_controller_metrics.cc',
+ 'aec3/render_signal_analyzer.cc',
+ 'aec3/residual_echo_estimator.cc',
+ 'aec3/reverb_decay_estimator.cc',
+ 'aec3/reverb_frequency_response.cc',
+ 'aec3/reverb_model.cc',
+ 'aec3/reverb_model_estimator.cc',
+ 'aec3/signal_dependent_erle_estimator.cc',
+ 'aec3/spectrum_buffer.cc',
+ 'aec3/stationarity_estimator.cc',
+ 'aec3/subband_erle_estimator.cc',
+ 'aec3/subband_nearend_detector.cc',
+ 'aec3/subtractor.cc',
+ 'aec3/subtractor_output_analyzer.cc',
+ 'aec3/subtractor_output.cc',
+ 'aec3/suppression_filter.cc',
+ 'aec3/suppression_gain.cc',
+ 'aec3/transparent_mode.cc',
+ 'aecm/aecm_core.cc',
+ 'aecm/aecm_core_c.cc',
+ 'aecm/echo_control_mobile.cc',
'agc/agc.cc',
'agc/agc_manager_direct.cc',
- 'agc/histogram.cc',
+ 'agc/legacy/analog_agc.cc',
+ 'agc/legacy/digital_agc.cc',
+ 'agc/loudness_histogram.cc',
'agc/utility.cc',
- 'beamformer/array_util.cc',
- 'beamformer/covariance_matrix_generator.cc',
- 'beamformer/nonlinear_beamformer.cc',
- 'intelligibility/intelligibility_enhancer.cc',
- 'intelligibility/intelligibility_utils.cc',
- 'logging/aec_logging_file_handling.cc',
- 'transient/click_annotate.cc',
+ 'agc2/adaptive_agc.cc',
+ 'agc2/adaptive_digital_gain_applier.cc',
+ 'agc2/adaptive_mode_level_estimator_agc.cc',
+ 'agc2/adaptive_mode_level_estimator.cc',
+ 'agc2/agc2_testing_common.cc',
+ 'agc2/biquad_filter.cc',
+ 'agc2/compute_interpolated_gain_curve.cc',
+ 'agc2/down_sampler.cc',
+ 'agc2/fixed_digital_level_estimator.cc',
+ 'agc2/gain_applier.cc',
+ 'agc2/interpolated_gain_curve.cc',
+ 'agc2/limiter.cc',
+ 'agc2/limiter_db_gain_curve.cc',
+ 'agc2/noise_level_estimator.cc',
+ 'agc2/noise_spectrum_estimator.cc',
+ 'agc2/rnn_vad/auto_correlation.cc',
+ 'agc2/rnn_vad/common.cc',
+ 'agc2/rnn_vad/features_extraction.cc',
+ 'agc2/rnn_vad/lp_residual.cc',
+ 'agc2/rnn_vad/pitch_search.cc',
+ 'agc2/rnn_vad/pitch_search_internal.cc',
+ 'agc2/rnn_vad/rnn.cc',
+ 'agc2/rnn_vad/rnn_vad_tool.cc',
+ 'agc2/rnn_vad/spectral_features.cc',
+ 'agc2/rnn_vad/spectral_features_internal.cc',
+ 'agc2/saturation_protector.cc',
+ 'agc2/signal_classifier.cc',
+ 'agc2/vad_with_level.cc',
+ 'agc2/vector_float_frame.cc',
+ 'audio_buffer.cc',
+ 'audio_processing_builder_impl.cc',
+ 'audio_processing_impl.cc',
+ 'echo_control_mobile_impl.cc',
+ 'echo_detector/circular_buffer.cc',
+ 'echo_detector/mean_variance_estimator.cc',
+ 'echo_detector/moving_max.cc',
+ 'echo_detector/normalized_covariance_estimator.cc',
+ 'gain_control_impl.cc',
+ 'gain_controller2.cc',
+ 'high_pass_filter.cc',
+ 'include/aec_dump.cc',
+ 'include/audio_frame_proxies.cc',
+ 'include/audio_processing.cc',
+ 'include/audio_processing_statistics.cc',
+ 'include/config.cc',
+ 'level_estimator.cc',
+ 'logging/apm_data_dumper.cc',
+ 'ns/fast_math.cc',
+ 'ns/histograms.cc',
+ 'ns/noise_estimator.cc',
+ 'ns/noise_suppressor.cc',
+ 'ns/ns_fft.cc',
+ 'ns/prior_signal_model.cc',
+ 'ns/prior_signal_model_estimator.cc',
+ 'ns/quantile_noise_estimator.cc',
+ 'ns/signal_model.cc',
+ 'ns/signal_model_estimator.cc',
+ 'ns/speech_probability_estimator.cc',
+ 'ns/suppression_params.cc',
+ 'ns/wiener_filter.cc',
+ 'optionally_built_submodule_creators.cc',
+ 'residual_echo_detector.cc',
+ 'rms_level.cc',
+ 'splitting_filter.cc',
+ 'three_band_filter_bank.cc',
'transient/file_utils.cc',
'transient/moving_moments.cc',
'transient/transient_detector.cc',
- 'transient/transient_suppressor.cc',
+ 'transient/transient_suppressor_impl.cc',
'transient/wpd_node.cc',
'transient/wpd_tree.cc',
- 'utility/delay_estimator.c',
- 'utility/delay_estimator_wrapper.c',
+ 'typing_detection.cc',
+ 'utility/cascaded_biquad_filter.cc',
+ 'utility/delay_estimator.cc',
+ 'utility/delay_estimator_wrapper.cc',
+ 'utility/pffft_wrapper.cc',
'vad/gmm.cc',
'vad/pitch_based_vad.cc',
'vad/pitch_internal.cc',
@@ -35,85 +150,65 @@ webrtc_audio_processing_sources = [
'vad/vad_audio_proc.cc',
'vad/vad_circular_buffer.cc',
'vad/voice_activity_detector.cc',
- 'audio_buffer.cc',
- 'audio_processing_impl.cc',
- 'audio_processing_impl.h',
- 'echo_cancellation_impl.cc',
- 'echo_control_mobile_impl.cc',
- 'gain_control_impl.cc',
- 'high_pass_filter_impl.cc',
- 'level_estimator_impl.cc',
- 'noise_suppression_impl.cc',
- 'rms_level.cc',
- 'splitting_filter.cc',
- 'processing_component.cc',
- 'three_band_filter_bank.cc',
- 'typing_detection.cc',
- 'voice_detection_impl.cc',
-]
-
-webrtc_audio_processing_beamformer_headers = [
- 'beamformer/array_util.h',
+ 'voice_detection.cc',
]
webrtc_audio_processing_include_headers = [
'include/audio_processing.h',
+ 'include/audio_processing_statistics.h',
+ 'include/config.h',
]
-if get_option('ns_mode') == 'float'
- webrtc_audio_processing_sources += [
- 'ns/noise_suppression.c',
- 'ns/ns_core.c',
- ]
-else
- webrtc_audio_processing_sources += [
- 'ns/noise_suppression_x.c',
- 'ns/nsx_core.c',
- 'ns/nsx_core_c.c',
- ]
- if have_neon
- webrtc_audio_processing_sources += [
- 'ns/nsx_core_neon.c',
- ]
- endif
-endif
-
extra_libs = []
if have_x86
extra_libs += [
static_library('webrtc_audio_processing_privatearch',
- ['aec/aec_core_sse2.c', 'aec/aec_rdft_sse2.c'],
+ [
+ 'aec3/adaptive_fir_filter_avx2.cc',
+ 'aec3/adaptive_fir_filter_erl_avx2.cc',
+ 'aec3/fft_data_avx2.cc',
+ 'aec3/matched_filter_avx2.cc',
+ 'aec3/vector_math_avx2.cc',
+ ],
dependencies: common_deps,
include_directories: webrtc_inc,
- c_args: common_cflags + ['-msse2'],
- cpp_args: common_cxxflags + ['-msse2']
+ c_args: common_cflags + apm_flags + ['-mavx2', '-mfma'],
+ cpp_args: common_cxxflags + apm_flags + ['-mavx2', '-mfma']
)
]
endif
+if have_mips
+ webrtc_audio_processing_sources += [
+ 'aecm/aecm_core_mips.cc',
+ ]
+endif
+
if have_neon
webrtc_audio_processing_sources += [
- 'aec/aec_core_neon.c',
- 'aec/aec_rdft_neon.c',
'aecm/aecm_core_neon.c',
]
endif
-install_headers(webrtc_audio_processing_beamformer_headers,
- subdir: 'webrtc_audio_processing/webrtc/modules/audio_processing/beamformer'
-)
-
install_headers(webrtc_audio_processing_include_headers,
- subdir: 'webrtc_audio_processing/webrtc/modules/audio_processing/include'
+ subdir: 'webrtc_audio_processing/modules/audio_processing/include'
)
libwebrtc_audio_processing = library('webrtc_audio_processing',
webrtc_audio_processing_sources,
- dependencies: [base_dep, webrtc_audio_coding_dep, system_wrappers_dep, common_audio_dep, webrtc_dep] + common_deps,
+ dependencies: [
+ base_dep,
+ api_dep,
+ webrtc_audio_coding_dep,
+ system_wrappers_dep,
+ common_audio_dep,
+ pffft_dep,
+ rnnoise_dep,
+ ] + common_deps,
link_with: extra_libs,
include_directories: webrtc_inc,
- c_args: common_cflags,
- cpp_args: common_cxxflags,
+ c_args: common_cflags + apm_flags,
+ cpp_args: common_cxxflags + apm_flags,
soversion: soversion,
install: true
)
diff --git a/webrtc/modules/audio_processing/noise_suppression_impl.cc b/webrtc/modules/audio_processing/noise_suppression_impl.cc
deleted file mode 100644
index 65ec3c4..0000000
--- a/webrtc/modules/audio_processing/noise_suppression_impl.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/noise_suppression_impl.h"
-
-#include <assert.h>
-
-#include "webrtc/modules/audio_processing/audio_buffer.h"
-#if defined(WEBRTC_NS_FLOAT)
-#include "webrtc/modules/audio_processing/ns/include/noise_suppression.h"
-#elif defined(WEBRTC_NS_FIXED)
-#include "webrtc/modules/audio_processing/ns/include/noise_suppression_x.h"
-#endif
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-
-
-namespace webrtc {
-
-#if defined(WEBRTC_NS_FLOAT)
-typedef NsHandle Handle;
-#elif defined(WEBRTC_NS_FIXED)
-typedef NsxHandle Handle;
-#endif
-
-namespace {
-int MapSetting(NoiseSuppression::Level level) {
- switch (level) {
- case NoiseSuppression::kLow:
- return 0;
- case NoiseSuppression::kModerate:
- return 1;
- case NoiseSuppression::kHigh:
- return 2;
- case NoiseSuppression::kVeryHigh:
- return 3;
- }
- assert(false);
- return -1;
-}
-} // namespace
-
-NoiseSuppressionImpl::NoiseSuppressionImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit)
- : ProcessingComponent(),
- apm_(apm),
- crit_(crit),
- level_(kModerate) {}
-
-NoiseSuppressionImpl::~NoiseSuppressionImpl() {}
-
-int NoiseSuppressionImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
-#if defined(WEBRTC_NS_FLOAT)
- if (!is_component_enabled()) {
- return apm_->kNoError;
- }
- assert(audio->num_frames_per_band() <= 160);
- assert(audio->num_channels() == num_handles());
-
- for (int i = 0; i < num_handles(); ++i) {
- Handle* my_handle = static_cast<Handle*>(handle(i));
-
- WebRtcNs_Analyze(my_handle, audio->split_bands_const_f(i)[kBand0To8kHz]);
- }
-#endif
- return apm_->kNoError;
-}
-
-int NoiseSuppressionImpl::ProcessCaptureAudio(AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
- }
- assert(audio->num_frames_per_band() <= 160);
- assert(audio->num_channels() == num_handles());
-
- for (int i = 0; i < num_handles(); ++i) {
- Handle* my_handle = static_cast<Handle*>(handle(i));
-#if defined(WEBRTC_NS_FLOAT)
- WebRtcNs_Process(my_handle,
- audio->split_bands_const_f(i),
- audio->num_bands(),
- audio->split_bands_f(i));
-#elif defined(WEBRTC_NS_FIXED)
- WebRtcNsx_Process(my_handle,
- audio->split_bands_const(i),
- audio->num_bands(),
- audio->split_bands(i));
-#endif
- }
- return apm_->kNoError;
-}
-
-int NoiseSuppressionImpl::Enable(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- return EnableComponent(enable);
-}
-
-bool NoiseSuppressionImpl::is_enabled() const {
- return is_component_enabled();
-}
-
-int NoiseSuppressionImpl::set_level(Level level) {
- CriticalSectionScoped crit_scoped(crit_);
- if (MapSetting(level) == -1) {
- return apm_->kBadParameterError;
- }
-
- level_ = level;
- return Configure();
-}
-
-NoiseSuppression::Level NoiseSuppressionImpl::level() const {
- return level_;
-}
-
-float NoiseSuppressionImpl::speech_probability() const {
-#if defined(WEBRTC_NS_FLOAT)
- float probability_average = 0.0f;
- for (int i = 0; i < num_handles(); i++) {
- Handle* my_handle = static_cast<Handle*>(handle(i));
- probability_average += WebRtcNs_prior_speech_probability(my_handle);
- }
- return probability_average / num_handles();
-#elif defined(WEBRTC_NS_FIXED)
- // Currently not available for the fixed point implementation.
- return apm_->kUnsupportedFunctionError;
-#endif
-}
-
-void* NoiseSuppressionImpl::CreateHandle() const {
-#if defined(WEBRTC_NS_FLOAT)
- return WebRtcNs_Create();
-#elif defined(WEBRTC_NS_FIXED)
- return WebRtcNsx_Create();
-#endif
-}
-
-void NoiseSuppressionImpl::DestroyHandle(void* handle) const {
-#if defined(WEBRTC_NS_FLOAT)
- WebRtcNs_Free(static_cast<Handle*>(handle));
-#elif defined(WEBRTC_NS_FIXED)
- WebRtcNsx_Free(static_cast<Handle*>(handle));
-#endif
-}
-
-int NoiseSuppressionImpl::InitializeHandle(void* handle) const {
-#if defined(WEBRTC_NS_FLOAT)
- return WebRtcNs_Init(static_cast<Handle*>(handle),
- apm_->proc_sample_rate_hz());
-#elif defined(WEBRTC_NS_FIXED)
- return WebRtcNsx_Init(static_cast<Handle*>(handle),
- apm_->proc_sample_rate_hz());
-#endif
-}
-
-int NoiseSuppressionImpl::ConfigureHandle(void* handle) const {
-#if defined(WEBRTC_NS_FLOAT)
- return WebRtcNs_set_policy(static_cast<Handle*>(handle),
- MapSetting(level_));
-#elif defined(WEBRTC_NS_FIXED)
- return WebRtcNsx_set_policy(static_cast<Handle*>(handle),
- MapSetting(level_));
-#endif
-}
-
-int NoiseSuppressionImpl::num_handles_required() const {
- return apm_->num_output_channels();
-}
-
-int NoiseSuppressionImpl::GetHandleError(void* handle) const {
- // The NS has no get_error() function.
- assert(handle != NULL);
- return apm_->kUnspecifiedError;
-}
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/noise_suppression_impl.h b/webrtc/modules/audio_processing/noise_suppression_impl.h
deleted file mode 100644
index 76a39b8..0000000
--- a/webrtc/modules/audio_processing/noise_suppression_impl.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_IMPL_H_
-
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/processing_component.h"
-
-namespace webrtc {
-
-class AudioBuffer;
-class CriticalSectionWrapper;
-
-class NoiseSuppressionImpl : public NoiseSuppression,
- public ProcessingComponent {
- public:
- NoiseSuppressionImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit);
- virtual ~NoiseSuppressionImpl();
-
- int AnalyzeCaptureAudio(AudioBuffer* audio);
- int ProcessCaptureAudio(AudioBuffer* audio);
-
- // NoiseSuppression implementation.
- bool is_enabled() const override;
- float speech_probability() const override;
- Level level() const override;
-
- private:
- // NoiseSuppression implementation.
- int Enable(bool enable) override;
- int set_level(Level level) override;
-
- // ProcessingComponent implementation.
- void* CreateHandle() const override;
- int InitializeHandle(void* handle) const override;
- int ConfigureHandle(void* handle) const override;
- void DestroyHandle(void* handle) const override;
- int num_handles_required() const override;
- int GetHandleError(void* handle) const override;
-
- const AudioProcessing* apm_;
- CriticalSectionWrapper* crit_;
- Level level_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_IMPL_H_
diff --git a/webrtc/modules/audio_processing/ns/BUILD.gn b/webrtc/modules/audio_processing/ns/BUILD.gn
new file mode 100644
index 0000000..f0842c5
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/BUILD.gn
@@ -0,0 +1,102 @@
+# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../../webrtc.gni")
+
+rtc_static_library("ns") {
+ visibility = [ "*" ]
+ configs += [ "..:apm_debug_dump" ]
+ sources = [
+ "fast_math.cc",
+ "fast_math.h",
+ "histograms.cc",
+ "histograms.h",
+ "noise_estimator.cc",
+ "noise_estimator.h",
+ "noise_suppressor.cc",
+ "noise_suppressor.h",
+ "ns_common.h",
+ "ns_config.h",
+ "ns_fft.cc",
+ "ns_fft.h",
+ "prior_signal_model.cc",
+ "prior_signal_model.h",
+ "prior_signal_model_estimator.cc",
+ "prior_signal_model_estimator.h",
+ "quantile_noise_estimator.cc",
+ "quantile_noise_estimator.h",
+ "signal_model.cc",
+ "signal_model.h",
+ "signal_model_estimator.cc",
+ "signal_model_estimator.h",
+ "speech_probability_estimator.cc",
+ "speech_probability_estimator.h",
+ "suppression_params.cc",
+ "suppression_params.h",
+ "wiener_filter.cc",
+ "wiener_filter.h",
+ ]
+
+ defines = []
+ if (rtc_build_with_neon && current_cpu != "arm64") {
+ suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags = [ "-mfpu=neon" ]
+ }
+
+ deps = [
+ "..:apm_logging",
+ "..:audio_buffer",
+ "..:high_pass_filter",
+ "../../../api:array_view",
+ "../../../common_audio:common_audio_c",
+ "../../../common_audio/third_party/ooura:fft_size_128",
+ "../../../common_audio/third_party/ooura:fft_size_256",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:safe_minmax",
+ "../../../rtc_base/system:arch",
+ "../../../system_wrappers",
+ "../../../system_wrappers:field_trial",
+ "../../../system_wrappers:metrics",
+ "../utility:cascaded_biquad_filter",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+if (rtc_include_tests) {
+ rtc_source_set("ns_unittests") {
+ testonly = true
+
+ configs += [ "..:apm_debug_dump" ]
+ sources = [ "noise_suppressor_unittest.cc" ]
+
+ deps = [
+ ":ns",
+ "..:apm_logging",
+ "..:audio_buffer",
+ "..:audio_processing",
+ "..:audio_processing_unittests",
+ "..:high_pass_filter",
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base:safe_minmax",
+ "../../../rtc_base/system:arch",
+ "../../../system_wrappers",
+ "../../../test:test_support",
+ "../utility:cascaded_biquad_filter",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+
+ defines = []
+
+ if (rtc_enable_protobuf) {
+ sources += []
+ }
+ }
+}
diff --git a/webrtc/modules/audio_processing/ns/defines.h b/webrtc/modules/audio_processing/ns/defines.h
deleted file mode 100644
index 8271332..0000000
--- a/webrtc/modules/audio_processing/ns/defines.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
-
-#define BLOCKL_MAX 160 // max processing block length: 160
-#define ANAL_BLOCKL_MAX 256 // max analysis block length: 256
-#define HALF_ANAL_BLOCKL 129 // half max analysis block length + 1
-#define NUM_HIGH_BANDS_MAX 2 // max number of high bands: 2
-
-#define QUANTILE (float)0.25
-
-#define SIMULT 3
-#define END_STARTUP_LONG 200
-#define END_STARTUP_SHORT 50
-#define FACTOR (float)40.0
-#define WIDTH (float)0.01
-
-// Length of fft work arrays.
-#define IP_LENGTH (ANAL_BLOCKL_MAX >> 1) // must be at least ceil(2 + sqrt(ANAL_BLOCKL_MAX/2))
-#define W_LENGTH (ANAL_BLOCKL_MAX >> 1)
-
-//PARAMETERS FOR NEW METHOD
-#define DD_PR_SNR (float)0.98 // DD update of prior SNR
-#define LRT_TAVG (float)0.50 // tavg parameter for LRT (previously 0.90)
-#define SPECT_FL_TAVG (float)0.30 // tavg parameter for spectral flatness measure
-#define SPECT_DIFF_TAVG (float)0.30 // tavg parameter for spectral difference measure
-#define PRIOR_UPDATE (float)0.10 // update parameter of prior model
-#define NOISE_UPDATE (float)0.90 // update parameter for noise
-#define SPEECH_UPDATE (float)0.99 // update parameter when likely speech
-#define WIDTH_PR_MAP (float)4.0 // width parameter in sigmoid map for prior model
-#define LRT_FEATURE_THR (float)0.5 // default threshold for LRT feature
-#define SF_FEATURE_THR (float)0.5 // default threshold for Spectral Flatness feature
-#define SD_FEATURE_THR (float)0.5 // default threshold for Spectral Difference feature
-#define PROB_RANGE (float)0.20 // probability threshold for noise state in
- // speech/noise likelihood
-#define HIST_PAR_EST 1000 // histogram size for estimation of parameters
-#define GAMMA_PAUSE (float)0.05 // update for conservative noise estimate
-//
-#define B_LIM (float)0.5 // threshold in final energy gain factor calculation
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
diff --git a/webrtc/modules/audio_processing/ns/fast_math.cc b/webrtc/modules/audio_processing/ns/fast_math.cc
new file mode 100644
index 0000000..d13110c
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/fast_math.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/fast_math.h"
+
+#include <math.h>
+#include <stdint.h>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+float FastLog2f(float in) {
+ RTC_DCHECK_GT(in, .0f);
+ // Read and interpret float as uint32_t and then cast to float.
+ // This is done to extract the exponent (bits 30 - 23).
+ // "Right shift" of the exponent is then performed by multiplying
+ // with the constant (1/2^23). Finally, we subtract a constant to
+ // remove the bias (https://en.wikipedia.org/wiki/Exponent_bias).
+ union {
+ float dummy;
+ uint32_t a;
+ } x = {in};
+ float out = x.a;
+ out *= 1.1920929e-7f; // 1/2^23
+ out -= 126.942695f; // Remove bias.
+ return out;
+}
+
+} // namespace
+
+float SqrtFastApproximation(float f) {
+ // TODO(peah): Add fast approximate implementation.
+ return sqrtf(f);
+}
+
+float Pow2Approximation(float p) {
+ // TODO(peah): Add fast approximate implementation.
+ return powf(2.f, p);
+}
+
+float PowApproximation(float x, float p) {
+ return Pow2Approximation(p * FastLog2f(x));
+}
+
+float LogApproximation(float x) {
+ constexpr float kLogOf2 = 0.69314718056f;
+ return FastLog2f(x) * kLogOf2;
+}
+
+void LogApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y) {
+ for (size_t k = 0; k < x.size(); ++k) {
+ y[k] = LogApproximation(x[k]);
+ }
+}
+
+float ExpApproximation(float x) {
+ constexpr float kLog10Ofe = 0.4342944819f;
+ return PowApproximation(10.f, x * kLog10Ofe);
+}
+
+void ExpApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y) {
+ for (size_t k = 0; k < x.size(); ++k) {
+ y[k] = ExpApproximation(x[k]);
+ }
+}
+
+void ExpApproximationSignFlip(rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> y) {
+ for (size_t k = 0; k < x.size(); ++k) {
+ y[k] = ExpApproximation(-x[k]);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/fast_math.h b/webrtc/modules/audio_processing/ns/fast_math.h
new file mode 100644
index 0000000..0aefee9
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/fast_math.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_
+#define MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+// Sqrt approximation.
+float SqrtFastApproximation(float f);
+
+// Log base conversion log(x) = log2(x)/log2(e).
+float LogApproximation(float x);
+void LogApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
+
+// 2^x approximation.
+float Pow2Approximation(float p);
+
+// x^p approximation.
+float PowApproximation(float x, float p);
+
+// e^x approximation.
+float ExpApproximation(float x);
+void ExpApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
+void ExpApproximationSignFlip(rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> y);
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_
diff --git a/webrtc/modules/audio_processing/ns/histograms.cc b/webrtc/modules/audio_processing/ns/histograms.cc
new file mode 100644
index 0000000..1d4f459
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/histograms.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/histograms.h"
+
+namespace webrtc {
+
+Histograms::Histograms() {
+ Clear();
+}
+
+void Histograms::Clear() {
+ lrt_.fill(0);
+ spectral_flatness_.fill(0);
+ spectral_diff_.fill(0);
+}
+
+void Histograms::Update(const SignalModel& features_) {
+ // Update the histogram for the LRT.
+ constexpr float kOneByBinSizeLrt = 1.f / kBinSizeLrt;
+ if (features_.lrt < kHistogramSize * kBinSizeLrt && features_.lrt >= 0.f) {
+ ++lrt_[kOneByBinSizeLrt * features_.lrt];
+ }
+
+ // Update histogram for the spectral flatness.
+ constexpr float kOneByBinSizeSpecFlat = 1.f / kBinSizeSpecFlat;
+ if (features_.spectral_flatness < kHistogramSize * kBinSizeSpecFlat &&
+ features_.spectral_flatness >= 0.f) {
+ ++spectral_flatness_[features_.spectral_flatness * kOneByBinSizeSpecFlat];
+ }
+
+ // Update histogram for the spectral difference.
+ constexpr float kOneByBinSizeSpecDiff = 1.f / kBinSizeSpecDiff;
+ if (features_.spectral_diff < kHistogramSize * kBinSizeSpecDiff &&
+ features_.spectral_diff >= 0.f) {
+ ++spectral_diff_[features_.spectral_diff * kOneByBinSizeSpecDiff];
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/histograms.h b/webrtc/modules/audio_processing/ns/histograms.h
new file mode 100644
index 0000000..9640e74
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/histograms.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_
+#define MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/signal_model.h"
+
+namespace webrtc {
+
+constexpr int kHistogramSize = 1000;
+
+// Class for handling the updating of histograms.
+class Histograms {
+ public:
+ Histograms();
+ Histograms(const Histograms&) = delete;
+ Histograms& operator=(const Histograms&) = delete;
+
+ // Clears the histograms.
+ void Clear();
+
+ // Extracts thresholds for feature parameters and updates the corresponding
+ // histogram.
+ void Update(const SignalModel& features_);
+
+ // Methods for accessing the histograms.
+ rtc::ArrayView<const int, kHistogramSize> get_lrt() const { return lrt_; }
+ rtc::ArrayView<const int, kHistogramSize> get_spectral_flatness() const {
+ return spectral_flatness_;
+ }
+ rtc::ArrayView<const int, kHistogramSize> get_spectral_diff() const {
+ return spectral_diff_;
+ }
+
+ private:
+ std::array<int, kHistogramSize> lrt_;
+ std::array<int, kHistogramSize> spectral_flatness_;
+ std::array<int, kHistogramSize> spectral_diff_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_
diff --git a/webrtc/modules/audio_processing/ns/include/noise_suppression.h b/webrtc/modules/audio_processing/ns/include/noise_suppression.h
deleted file mode 100644
index 9dac56b..0000000
--- a/webrtc/modules/audio_processing/ns/include/noise_suppression.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_H_
-
-#include <stddef.h>
-
-#include "webrtc/typedefs.h"
-
-typedef struct NsHandleT NsHandle;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * This function creates an instance of the floating point Noise Suppression.
- */
-NsHandle* WebRtcNs_Create();
-
-/*
- * This function frees the dynamic memory of a specified noise suppression
- * instance.
- *
- * Input:
- * - NS_inst : Pointer to NS instance that should be freed
- */
-void WebRtcNs_Free(NsHandle* NS_inst);
-
-/*
- * This function initializes a NS instance and has to be called before any other
- * processing is made.
- *
- * Input:
- * - NS_inst : Instance that should be initialized
- * - fs : sampling frequency
- *
- * Output:
- * - NS_inst : Initialized instance
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int WebRtcNs_Init(NsHandle* NS_inst, uint32_t fs);
-
-/*
- * This changes the aggressiveness of the noise suppression method.
- *
- * Input:
- * - NS_inst : Noise suppression instance.
- * - mode : 0: Mild, 1: Medium , 2: Aggressive
- *
- * Output:
- * - NS_inst : Updated instance.
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int WebRtcNs_set_policy(NsHandle* NS_inst, int mode);
-
-/*
- * This functions estimates the background noise for the inserted speech frame.
- * The input and output signals should always be 10ms (80 or 160 samples).
- *
- * Input
- * - NS_inst : Noise suppression instance.
- * - spframe : Pointer to speech frame buffer for L band
- *
- * Output:
- * - NS_inst : Updated NS instance
- */
-void WebRtcNs_Analyze(NsHandle* NS_inst, const float* spframe);
-
-/*
- * This functions does Noise Suppression for the inserted speech frame. The
- * input and output signals should always be 10ms (80 or 160 samples).
- *
- * Input
- * - NS_inst : Noise suppression instance.
- * - spframe : Pointer to speech frame buffer for each band
- * - num_bands : Number of bands
- *
- * Output:
- * - NS_inst : Updated NS instance
- * - outframe : Pointer to output frame for each band
- */
-void WebRtcNs_Process(NsHandle* NS_inst,
- const float* const* spframe,
- size_t num_bands,
- float* const* outframe);
-
-/* Returns the internally used prior speech probability of the current frame.
- * There is a frequency bin based one as well, with which this should not be
- * confused.
- *
- * Input
- * - handle : Noise suppression instance.
- *
- * Return value : Prior speech probability in interval [0.0, 1.0].
- * -1 - NULL pointer or uninitialized instance.
- */
-float WebRtcNs_prior_speech_probability(NsHandle* handle);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_H_
diff --git a/webrtc/modules/audio_processing/ns/include/noise_suppression_x.h b/webrtc/modules/audio_processing/ns/include/noise_suppression_x.h
deleted file mode 100644
index 88fe4cd..0000000
--- a/webrtc/modules/audio_processing/ns/include/noise_suppression_x.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_X_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_X_H_
-
-#include "webrtc/typedefs.h"
-
-typedef struct NsxHandleT NsxHandle;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * This function creates an instance of the fixed point Noise Suppression.
- */
-NsxHandle* WebRtcNsx_Create();
-
-/*
- * This function frees the dynamic memory of a specified Noise Suppression
- * instance.
- *
- * Input:
- * - nsxInst : Pointer to NS instance that should be freed
- */
-void WebRtcNsx_Free(NsxHandle* nsxInst);
-
-/*
- * This function initializes a NS instance
- *
- * Input:
- * - nsxInst : Instance that should be initialized
- * - fs : sampling frequency
- *
- * Output:
- * - nsxInst : Initialized instance
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int WebRtcNsx_Init(NsxHandle* nsxInst, uint32_t fs);
-
-/*
- * This changes the aggressiveness of the noise suppression method.
- *
- * Input:
- * - nsxInst : Instance that should be initialized
- * - mode : 0: Mild, 1: Medium , 2: Aggressive
- *
- * Output:
- * - nsxInst : Initialized instance
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int WebRtcNsx_set_policy(NsxHandle* nsxInst, int mode);
-
-/*
- * This functions does noise suppression for the inserted speech frame. The
- * input and output signals should always be 10ms (80 or 160 samples).
- *
- * Input
- * - nsxInst : NSx instance. Needs to be initiated before call.
- * - speechFrame : Pointer to speech frame buffer for each band
- * - num_bands : Number of bands
- *
- * Output:
- * - nsxInst : Updated NSx instance
- * - outFrame : Pointer to output frame for each band
- */
-void WebRtcNsx_Process(NsxHandle* nsxInst,
- const short* const* speechFrame,
- int num_bands,
- short* const* outFrame);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_X_H_
diff --git a/webrtc/modules/audio_processing/ns/noise_estimator.cc b/webrtc/modules/audio_processing/ns/noise_estimator.cc
new file mode 100644
index 0000000..5367545
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/noise_estimator.cc
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/noise_estimator.h"
+
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Log(i).
+constexpr std::array<float, 129> log_table = {
+ 0.f, 0.f, 0.f, 0.f, 0.f, 1.609438f, 1.791759f,
+ 1.945910f, 2.079442f, 2.197225f, 2.302585f, 2.397895f, 2.484907f, 2.564949f,
+ 2.639057f, 2.708050f, 2.772589f, 2.833213f, 2.890372f, 2.944439f, 2.995732f,
+ 3.044522f, 3.091043f, 3.135494f, 3.178054f, 3.218876f, 3.258097f, 3.295837f,
+ 3.332205f, 3.367296f, 3.401197f, 3.433987f, 3.465736f, 3.496507f, 3.526361f,
+ 3.555348f, 3.583519f, 3.610918f, 3.637586f, 3.663562f, 3.688879f, 3.713572f,
+ 3.737669f, 3.761200f, 3.784190f, 3.806663f, 3.828641f, 3.850147f, 3.871201f,
+ 3.891820f, 3.912023f, 3.931826f, 3.951244f, 3.970292f, 3.988984f, 4.007333f,
+ 4.025352f, 4.043051f, 4.060443f, 4.077538f, 4.094345f, 4.110874f, 4.127134f,
+ 4.143135f, 4.158883f, 4.174387f, 4.189655f, 4.204693f, 4.219508f, 4.234107f,
+ 4.248495f, 4.262680f, 4.276666f, 4.290460f, 4.304065f, 4.317488f, 4.330733f,
+ 4.343805f, 4.356709f, 4.369448f, 4.382027f, 4.394449f, 4.406719f, 4.418841f,
+ 4.430817f, 4.442651f, 4.454347f, 4.465908f, 4.477337f, 4.488636f, 4.499810f,
+ 4.510859f, 4.521789f, 4.532599f, 4.543295f, 4.553877f, 4.564348f, 4.574711f,
+ 4.584968f, 4.595119f, 4.605170f, 4.615121f, 4.624973f, 4.634729f, 4.644391f,
+ 4.653960f, 4.663439f, 4.672829f, 4.682131f, 4.691348f, 4.700480f, 4.709530f,
+ 4.718499f, 4.727388f, 4.736198f, 4.744932f, 4.753591f, 4.762174f, 4.770685f,
+ 4.779124f, 4.787492f, 4.795791f, 4.804021f, 4.812184f, 4.820282f, 4.828314f,
+ 4.836282f, 4.844187f, 4.852030f};
+
+} // namespace
+
+NoiseEstimator::NoiseEstimator(const SuppressionParams& suppression_params)
+ : suppression_params_(suppression_params) {
+ noise_spectrum_.fill(0.f);
+ prev_noise_spectrum_.fill(0.f);
+ conservative_noise_spectrum_.fill(0.f);
+ parametric_noise_spectrum_.fill(0.f);
+}
+
+void NoiseEstimator::PrepareAnalysis() {
+ std::copy(noise_spectrum_.begin(), noise_spectrum_.end(),
+ prev_noise_spectrum_.begin());
+}
+
+void NoiseEstimator::PreUpdate(
+ int32_t num_analyzed_frames,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ float signal_spectral_sum) {
+ quantile_noise_estimator_.Estimate(signal_spectrum, noise_spectrum_);
+
+ if (num_analyzed_frames < kShortStartupPhaseBlocks) {
+ // Compute simplified noise model during startup.
+ const size_t kStartBand = 5;
+ float sum_log_i_log_magn = 0.f;
+ float sum_log_i = 0.f;
+ float sum_log_i_square = 0.f;
+ float sum_log_magn = 0.f;
+ for (size_t i = kStartBand; i < kFftSizeBy2Plus1; ++i) {
+ float log_i = log_table[i];
+ sum_log_i += log_i;
+ sum_log_i_square += log_i * log_i;
+ float log_signal = LogApproximation(signal_spectrum[i]);
+ sum_log_magn += log_signal;
+ sum_log_i_log_magn += log_i * log_signal;
+ }
+
+ // Estimate the parameter for the level of the white noise.
+ constexpr float kOneByFftSizeBy2Plus1 = 1.f / kFftSizeBy2Plus1;
+ white_noise_level_ += signal_spectral_sum * kOneByFftSizeBy2Plus1 *
+ suppression_params_.over_subtraction_factor;
+
+ // Estimate pink noise parameters.
+ float denom = sum_log_i_square * (kFftSizeBy2Plus1 - kStartBand) -
+ sum_log_i * sum_log_i;
+ float num =
+ sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn;
+ RTC_DCHECK_NE(denom, 0.f);
+ float pink_noise_adjustment = num / denom;
+
+ // Constrain the estimated spectrum to be positive.
+ pink_noise_adjustment = std::max(pink_noise_adjustment, 0.f);
+ pink_noise_numerator_ += pink_noise_adjustment;
+ num = sum_log_i * sum_log_magn -
+ (kFftSizeBy2Plus1 - kStartBand) * sum_log_i_log_magn;
+ RTC_DCHECK_NE(denom, 0.f);
+ pink_noise_adjustment = num / denom;
+
+ // Constrain the pink noise power to be in the interval [0, 1].
+ pink_noise_adjustment = std::max(std::min(pink_noise_adjustment, 1.f), 0.f);
+
+ pink_noise_exp_ += pink_noise_adjustment;
+
+ const float one_by_num_analyzed_frames_plus_1 =
+ 1.f / (num_analyzed_frames + 1.f);
+
+ // Calculate the frequency-independent parts of parametric noise estimate.
+ float parametric_exp = 0.f;
+ float parametric_num = 0.f;
+ if (pink_noise_exp_ > 0.f) {
+ // Use pink noise estimate.
+ parametric_num = ExpApproximation(pink_noise_numerator_ *
+ one_by_num_analyzed_frames_plus_1);
+ parametric_num *= num_analyzed_frames + 1.f;
+ parametric_exp = pink_noise_exp_ * one_by_num_analyzed_frames_plus_1;
+ }
+
+ constexpr float kOneByShortStartupPhaseBlocks =
+ 1.f / kShortStartupPhaseBlocks;
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ // Estimate the background noise using the white and pink noise
+ // parameters.
+ if (pink_noise_exp_ == 0.f) {
+ // Use white noise estimate.
+ parametric_noise_spectrum_[i] = white_noise_level_;
+ } else {
+ // Use pink noise estimate.
+ float use_band = i < kStartBand ? kStartBand : i;
+ float denom = PowApproximation(use_band, parametric_exp);
+ RTC_DCHECK_NE(denom, 0.f);
+ parametric_noise_spectrum_[i] = parametric_num / denom;
+ }
+ }
+
+ // Weight quantile noise with modeled noise.
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ noise_spectrum_[i] *= num_analyzed_frames;
+ float tmp = parametric_noise_spectrum_[i] *
+ (kShortStartupPhaseBlocks - num_analyzed_frames);
+ noise_spectrum_[i] += tmp * one_by_num_analyzed_frames_plus_1;
+ noise_spectrum_[i] *= kOneByShortStartupPhaseBlocks;
+ }
+ }
+}
+
+void NoiseEstimator::PostUpdate(
+ rtc::ArrayView<const float> speech_probability,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum) {
+ // Time-avg parameter for noise_spectrum update.
+ constexpr float kNoiseUpdate = 0.9f;
+
+ float gamma = kNoiseUpdate;
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ const float prob_speech = speech_probability[i];
+ const float prob_non_speech = 1.f - prob_speech;
+
+ // Temporary noise update used for speech frames if update value is less
+ // than previous.
+ float noise_update_tmp =
+ gamma * prev_noise_spectrum_[i] +
+ (1.f - gamma) * (prob_non_speech * signal_spectrum[i] +
+ prob_speech * prev_noise_spectrum_[i]);
+
+ // Time-constant based on speech/noise_spectrum state.
+ float gamma_old = gamma;
+
+ // Increase gamma for frame likely to be seech.
+ constexpr float kProbRange = .2f;
+ gamma = prob_speech > kProbRange ? .99f : kNoiseUpdate;
+
+ // Conservative noise_spectrum update.
+ if (prob_speech < kProbRange) {
+ conservative_noise_spectrum_[i] +=
+ 0.05f * (signal_spectrum[i] - conservative_noise_spectrum_[i]);
+ }
+
+ // Noise_spectrum update.
+ if (gamma == gamma_old) {
+ noise_spectrum_[i] = noise_update_tmp;
+ } else {
+ noise_spectrum_[i] =
+ gamma * prev_noise_spectrum_[i] +
+ (1.f - gamma) * (prob_non_speech * signal_spectrum[i] +
+ prob_speech * prev_noise_spectrum_[i]);
+ // Allow for noise_spectrum update downwards: If noise_spectrum update
+ // decreases the noise_spectrum, it is safe, so allow it to happen.
+ noise_spectrum_[i] = std::min(noise_spectrum_[i], noise_update_tmp);
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/noise_estimator.h b/webrtc/modules/audio_processing/ns/noise_estimator.h
new file mode 100644
index 0000000..0c0466a
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/noise_estimator.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/quantile_noise_estimator.h"
+#include "modules/audio_processing/ns/suppression_params.h"
+
+namespace webrtc {
+
+// Class for estimating the spectral characteristics of the noise in an incoming
+// signal.
+class NoiseEstimator {
+ public:
+ explicit NoiseEstimator(const SuppressionParams& suppression_params);
+
+ // Prepare the estimator for analysis of a new frame.
+ void PrepareAnalysis();
+
+ // Performs the first step of the estimator update.
+ void PreUpdate(int32_t num_analyzed_frames,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ float signal_spectral_sum);
+
+ // Performs the second step of the estimator update.
+ void PostUpdate(
+ rtc::ArrayView<const float> speech_probability,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum);
+
+ // Returns the noise spectral estimate.
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> get_noise_spectrum() const {
+ return noise_spectrum_;
+ }
+
+ // Returns the noise from the previous frame.
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> get_prev_noise_spectrum()
+ const {
+ return prev_noise_spectrum_;
+ }
+
+ // Returns a noise spectral estimate based on white and pink noise parameters.
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> get_parametric_noise_spectrum()
+ const {
+ return parametric_noise_spectrum_;
+ }
+ rtc::ArrayView<const float, kFftSizeBy2Plus1>
+ get_conservative_noise_spectrum() const {
+ return conservative_noise_spectrum_;
+ }
+
+ private:
+ const SuppressionParams& suppression_params_;
+ float white_noise_level_ = 0.f;
+ float pink_noise_numerator_ = 0.f;
+ float pink_noise_exp_ = 0.f;
+ std::array<float, kFftSizeBy2Plus1> prev_noise_spectrum_;
+ std::array<float, kFftSizeBy2Plus1> conservative_noise_spectrum_;
+ std::array<float, kFftSizeBy2Plus1> parametric_noise_spectrum_;
+ std::array<float, kFftSizeBy2Plus1> noise_spectrum_;
+ QuantileNoiseEstimator quantile_noise_estimator_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/ns/noise_suppression.c b/webrtc/modules/audio_processing/ns/noise_suppression.c
deleted file mode 100644
index 13f1b2d..0000000
--- a/webrtc/modules/audio_processing/ns/noise_suppression.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/ns/include/noise_suppression.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/ns/defines.h"
-#include "webrtc/modules/audio_processing/ns/ns_core.h"
-
-NsHandle* WebRtcNs_Create() {
- NoiseSuppressionC* self = malloc(sizeof(NoiseSuppressionC));
- self->initFlag = 0;
- return (NsHandle*)self;
-}
-
-void WebRtcNs_Free(NsHandle* NS_inst) {
- free(NS_inst);
-}
-
-int WebRtcNs_Init(NsHandle* NS_inst, uint32_t fs) {
- return WebRtcNs_InitCore((NoiseSuppressionC*)NS_inst, fs);
-}
-
-int WebRtcNs_set_policy(NsHandle* NS_inst, int mode) {
- return WebRtcNs_set_policy_core((NoiseSuppressionC*)NS_inst, mode);
-}
-
-void WebRtcNs_Analyze(NsHandle* NS_inst, const float* spframe) {
- WebRtcNs_AnalyzeCore((NoiseSuppressionC*)NS_inst, spframe);
-}
-
-void WebRtcNs_Process(NsHandle* NS_inst,
- const float* const* spframe,
- size_t num_bands,
- float* const* outframe) {
- WebRtcNs_ProcessCore((NoiseSuppressionC*)NS_inst, spframe, num_bands,
- outframe);
-}
-
-float WebRtcNs_prior_speech_probability(NsHandle* handle) {
- NoiseSuppressionC* self = (NoiseSuppressionC*)handle;
- if (handle == NULL) {
- return -1;
- }
- if (self->initFlag == 0) {
- return -1;
- }
- return self->priorSpeechProb;
-}
diff --git a/webrtc/modules/audio_processing/ns/noise_suppression_x.c b/webrtc/modules/audio_processing/ns/noise_suppression_x.c
deleted file mode 100644
index 150fe60..0000000
--- a/webrtc/modules/audio_processing/ns/noise_suppression_x.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/ns/include/noise_suppression_x.h"
-
-#include <stdlib.h>
-
-#include "webrtc/common_audio/signal_processing/include/real_fft.h"
-#include "webrtc/modules/audio_processing/ns/nsx_core.h"
-#include "webrtc/modules/audio_processing/ns/nsx_defines.h"
-
-NsxHandle* WebRtcNsx_Create() {
- NoiseSuppressionFixedC* self = malloc(sizeof(NoiseSuppressionFixedC));
- WebRtcSpl_Init();
- self->real_fft = NULL;
- self->initFlag = 0;
- return (NsxHandle*)self;
-}
-
-void WebRtcNsx_Free(NsxHandle* nsxInst) {
- WebRtcSpl_FreeRealFFT(((NoiseSuppressionFixedC*)nsxInst)->real_fft);
- free(nsxInst);
-}
-
-int WebRtcNsx_Init(NsxHandle* nsxInst, uint32_t fs) {
- return WebRtcNsx_InitCore((NoiseSuppressionFixedC*)nsxInst, fs);
-}
-
-int WebRtcNsx_set_policy(NsxHandle* nsxInst, int mode) {
- return WebRtcNsx_set_policy_core((NoiseSuppressionFixedC*)nsxInst, mode);
-}
-
-void WebRtcNsx_Process(NsxHandle* nsxInst,
- const short* const* speechFrame,
- int num_bands,
- short* const* outFrame) {
- WebRtcNsx_ProcessCore((NoiseSuppressionFixedC*)nsxInst, speechFrame,
- num_bands, outFrame);
-}
diff --git a/webrtc/modules/audio_processing/ns/noise_suppressor.cc b/webrtc/modules/audio_processing/ns/noise_suppressor.cc
new file mode 100644
index 0000000..89e1fe0
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/noise_suppressor.cc
@@ -0,0 +1,549 @@
+/*
+ * 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/audio_processing/ns/noise_suppressor.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Maps sample rate to number of bands.
+size_t NumBandsForRate(size_t sample_rate_hz) {
+ RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
+ sample_rate_hz == 48000);
+ return sample_rate_hz / 16000;
+}
+
+// Maximum number of channels for which the channel data is stored on
+// the stack. If the number of channels are larger than this, they are stored
+// using scratch memory that is pre-allocated on the heap. The reason for this
+// partitioning is not to waste heap space for handling the more common numbers
+// of channels, while at the same time not limiting the support for higher
+// numbers of channels by enforcing the channel data to be stored on the
+// stack using a fixed maximum value.
+constexpr size_t kMaxNumChannelsOnStack = 2;
+
+// Chooses the number of channels to store on the heap when that is required due
+// to the number of channels being larger than the pre-defined number
+// of channels to store on the stack.
+size_t NumChannelsOnHeap(size_t num_channels) {
+ return num_channels > kMaxNumChannelsOnStack ? num_channels : 0;
+}
+
+// Hybrib Hanning and flat window for the filterbank.
+constexpr std::array<float, 96> kBlocks160w256FirstHalf = {
+ 0.00000000f, 0.01636173f, 0.03271908f, 0.04906767f, 0.06540313f,
+ 0.08172107f, 0.09801714f, 0.11428696f, 0.13052619f, 0.14673047f,
+ 0.16289547f, 0.17901686f, 0.19509032f, 0.21111155f, 0.22707626f,
+ 0.24298018f, 0.25881905f, 0.27458862f, 0.29028468f, 0.30590302f,
+ 0.32143947f, 0.33688985f, 0.35225005f, 0.36751594f, 0.38268343f,
+ 0.39774847f, 0.41270703f, 0.42755509f, 0.44228869f, 0.45690388f,
+ 0.47139674f, 0.48576339f, 0.50000000f, 0.51410274f, 0.52806785f,
+ 0.54189158f, 0.55557023f, 0.56910015f, 0.58247770f, 0.59569930f,
+ 0.60876143f, 0.62166057f, 0.63439328f, 0.64695615f, 0.65934582f,
+ 0.67155895f, 0.68359230f, 0.69544264f, 0.70710678f, 0.71858162f,
+ 0.72986407f, 0.74095113f, 0.75183981f, 0.76252720f, 0.77301045f,
+ 0.78328675f, 0.79335334f, 0.80320753f, 0.81284668f, 0.82226822f,
+ 0.83146961f, 0.84044840f, 0.84920218f, 0.85772861f, 0.86602540f,
+ 0.87409034f, 0.88192126f, 0.88951608f, 0.89687274f, 0.90398929f,
+ 0.91086382f, 0.91749450f, 0.92387953f, 0.93001722f, 0.93590593f,
+ 0.94154407f, 0.94693013f, 0.95206268f, 0.95694034f, 0.96156180f,
+ 0.96592583f, 0.97003125f, 0.97387698f, 0.97746197f, 0.98078528f,
+ 0.98384601f, 0.98664333f, 0.98917651f, 0.99144486f, 0.99344778f,
+ 0.99518473f, 0.99665524f, 0.99785892f, 0.99879546f, 0.99946459f,
+ 0.99986614f};
+
+// Applies the filterbank window to a buffer.
+void ApplyFilterBankWindow(rtc::ArrayView<float, kFftSize> x) {
+ for (size_t i = 0; i < 96; ++i) {
+ x[i] = kBlocks160w256FirstHalf[i] * x[i];
+ }
+
+ for (size_t i = 161, k = 95; i < kFftSize; ++i, --k) {
+ RTC_DCHECK_NE(0, k);
+ x[i] = kBlocks160w256FirstHalf[k] * x[i];
+ }
+}
+
+// Extends a frame with previous data.
+void FormExtendedFrame(rtc::ArrayView<const float, kNsFrameSize> frame,
+ rtc::ArrayView<float, kFftSize - kNsFrameSize> old_data,
+ rtc::ArrayView<float, kFftSize> extended_frame) {
+ std::copy(old_data.begin(), old_data.end(), extended_frame.begin());
+ std::copy(frame.begin(), frame.end(),
+ extended_frame.begin() + old_data.size());
+ std::copy(extended_frame.end() - old_data.size(), extended_frame.end(),
+ old_data.begin());
+}
+
+// Uses overlap-and-add to produce an output frame.
+void OverlapAndAdd(rtc::ArrayView<const float, kFftSize> extended_frame,
+ rtc::ArrayView<float, kOverlapSize> overlap_memory,
+ rtc::ArrayView<float, kNsFrameSize> output_frame) {
+ for (size_t i = 0; i < kOverlapSize; ++i) {
+ output_frame[i] = overlap_memory[i] + extended_frame[i];
+ }
+ std::copy(extended_frame.begin() + kOverlapSize,
+ extended_frame.begin() + kNsFrameSize,
+ output_frame.begin() + kOverlapSize);
+ std::copy(extended_frame.begin() + kNsFrameSize, extended_frame.end(),
+ overlap_memory.begin());
+}
+
+// Produces a delayed frame.
+void DelaySignal(rtc::ArrayView<const float, kNsFrameSize> frame,
+ rtc::ArrayView<float, kFftSize - kNsFrameSize> delay_buffer,
+ rtc::ArrayView<float, kNsFrameSize> delayed_frame) {
+ constexpr size_t kSamplesFromFrame = kNsFrameSize - (kFftSize - kNsFrameSize);
+ std::copy(delay_buffer.begin(), delay_buffer.end(), delayed_frame.begin());
+ std::copy(frame.begin(), frame.begin() + kSamplesFromFrame,
+ delayed_frame.begin() + delay_buffer.size());
+
+ std::copy(frame.begin() + kSamplesFromFrame, frame.end(),
+ delay_buffer.begin());
+}
+
+// Computes the energy of an extended frame.
+float ComputeEnergyOfExtendedFrame(rtc::ArrayView<const float, kFftSize> x) {
+ float energy = 0.f;
+ for (float x_k : x) {
+ energy += x_k * x_k;
+ }
+
+ return energy;
+}
+
+// Computes the energy of an extended frame based on its subcomponents.
+float ComputeEnergyOfExtendedFrame(
+ rtc::ArrayView<const float, kNsFrameSize> frame,
+ rtc::ArrayView<float, kFftSize - kNsFrameSize> old_data) {
+ float energy = 0.f;
+ for (float v : old_data) {
+ energy += v * v;
+ }
+ for (float v : frame) {
+ energy += v * v;
+ }
+
+ return energy;
+}
+
+// Computes the magnitude spectrum based on an FFT output.
+void ComputeMagnitudeSpectrum(
+ rtc::ArrayView<const float, kFftSize> real,
+ rtc::ArrayView<const float, kFftSize> imag,
+ rtc::ArrayView<float, kFftSizeBy2Plus1> signal_spectrum) {
+ signal_spectrum[0] = fabsf(real[0]) + 1.f;
+ signal_spectrum[kFftSizeBy2Plus1 - 1] =
+ fabsf(real[kFftSizeBy2Plus1 - 1]) + 1.f;
+
+ for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) {
+ signal_spectrum[i] =
+ SqrtFastApproximation(real[i] * real[i] + imag[i] * imag[i]) + 1.f;
+ }
+}
+
+// Compute prior and post SNR.
+void ComputeSnr(rtc::ArrayView<const float, kFftSizeBy2Plus1> filter,
+ rtc::ArrayView<const float> prev_signal_spectrum,
+ rtc::ArrayView<const float> signal_spectrum,
+ rtc::ArrayView<const float> prev_noise_spectrum,
+ rtc::ArrayView<const float> noise_spectrum,
+ rtc::ArrayView<float> prior_snr,
+ rtc::ArrayView<float> post_snr) {
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ // Previous post SNR.
+ // Previous estimate: based on previous frame with gain filter.
+ float prev_estimate = prev_signal_spectrum[i] /
+ (prev_noise_spectrum[i] + 0.0001f) * filter[i];
+ // Post SNR.
+ if (signal_spectrum[i] > noise_spectrum[i]) {
+ post_snr[i] = signal_spectrum[i] / (noise_spectrum[i] + 0.0001f) - 1.f;
+ } else {
+ post_snr[i] = 0.f;
+ }
+ // The directed decision estimate of the prior SNR is a sum the current and
+ // previous estimates.
+ prior_snr[i] = 0.98f * prev_estimate + (1.f - 0.98f) * post_snr[i];
+ }
+}
+
+// Computes the attenuating gain for the noise suppression of the upper bands.
+float ComputeUpperBandsGain(
+ float minimum_attenuating_gain,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> filter,
+ rtc::ArrayView<const float> speech_probability,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> prev_analysis_signal_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum) {
+ // Average speech prob and filter gain for the end of the lowest band.
+ constexpr int kNumAvgBins = 32;
+ constexpr float kOneByNumAvgBins = 1.f / kNumAvgBins;
+
+ float avg_prob_speech = 0.f;
+ float avg_filter_gain = 0.f;
+ for (size_t i = kFftSizeBy2Plus1 - kNumAvgBins - 1; i < kFftSizeBy2Plus1 - 1;
+ i++) {
+ avg_prob_speech += speech_probability[i];
+ avg_filter_gain += filter[i];
+ }
+ avg_prob_speech = avg_prob_speech * kOneByNumAvgBins;
+ avg_filter_gain = avg_filter_gain * kOneByNumAvgBins;
+
+ // If the speech was suppressed by a component between Analyze and Process, an
+ // example being by an AEC, it should not be considered speech for the purpose
+ // of high band suppression. To that end, the speech probability is scaled
+ // accordingly.
+ float sum_analysis_spectrum = 0.f;
+ float sum_processing_spectrum = 0.f;
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ sum_analysis_spectrum += prev_analysis_signal_spectrum[i];
+ sum_processing_spectrum += signal_spectrum[i];
+ }
+
+ // The magnitude spectrum computation enforces the spectrum to be strictly
+ // positive.
+ RTC_DCHECK_GT(sum_analysis_spectrum, 0.f);
+ avg_prob_speech *= sum_processing_spectrum / sum_analysis_spectrum;
+
+ // Compute gain based on speech probability.
+ float gain =
+ 0.5f * (1.f + static_cast<float>(tanh(2.f * avg_prob_speech - 1.f)));
+
+ // Combine gain with low band gain.
+ if (avg_prob_speech >= 0.5f) {
+ gain = 0.25f * gain + 0.75f * avg_filter_gain;
+ } else {
+ gain = 0.5f * gain + 0.5f * avg_filter_gain;
+ }
+
+ // Make sure gain is within flooring range.
+ return std::min(std::max(gain, minimum_attenuating_gain), 1.f);
+}
+
+} // namespace
+
+NoiseSuppressor::ChannelState::ChannelState(
+ const SuppressionParams& suppression_params,
+ size_t num_bands)
+ : wiener_filter(suppression_params),
+ noise_estimator(suppression_params),
+ process_delay_memory(num_bands > 1 ? num_bands - 1 : 0) {
+ analyze_analysis_memory.fill(0.f);
+ prev_analysis_signal_spectrum.fill(1.f);
+ process_analysis_memory.fill(0.f);
+ process_synthesis_memory.fill(0.f);
+ for (auto& d : process_delay_memory) {
+ d.fill(0.f);
+ }
+}
+
+NoiseSuppressor::NoiseSuppressor(const NsConfig& config,
+ size_t sample_rate_hz,
+ size_t num_channels)
+ : num_bands_(NumBandsForRate(sample_rate_hz)),
+ num_channels_(num_channels),
+ suppression_params_(config.target_level),
+ filter_bank_states_heap_(NumChannelsOnHeap(num_channels_)),
+ upper_band_gains_heap_(NumChannelsOnHeap(num_channels_)),
+ energies_before_filtering_heap_(NumChannelsOnHeap(num_channels_)),
+ gain_adjustments_heap_(NumChannelsOnHeap(num_channels_)),
+ channels_(num_channels_) {
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ channels_[ch] =
+ std::make_unique<ChannelState>(suppression_params_, num_bands_);
+ }
+}
+
+void NoiseSuppressor::AggregateWienerFilters(
+ rtc::ArrayView<float, kFftSizeBy2Plus1> filter) const {
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> filter0 =
+ channels_[0]->wiener_filter.get_filter();
+ std::copy(filter0.begin(), filter0.end(), filter.begin());
+
+ for (size_t ch = 1; ch < num_channels_; ++ch) {
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> filter_ch =
+ channels_[ch]->wiener_filter.get_filter();
+
+ for (size_t k = 0; k < kFftSizeBy2Plus1; ++k) {
+ filter[k] = std::min(filter[k], filter_ch[k]);
+ }
+ }
+}
+
+void NoiseSuppressor::Analyze(const AudioBuffer& audio) {
+ // Prepare the noise estimator for the analysis stage.
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ channels_[ch]->noise_estimator.PrepareAnalysis();
+ }
+
+ // Check for zero frames.
+ bool zero_frame = true;
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ rtc::ArrayView<const float, kNsFrameSize> y_band0(
+ &audio.split_bands_const(ch)[0][0], kNsFrameSize);
+ float energy = ComputeEnergyOfExtendedFrame(
+ y_band0, channels_[ch]->analyze_analysis_memory);
+ if (energy > 0.f) {
+ zero_frame = false;
+ break;
+ }
+ }
+
+ if (zero_frame) {
+ // We want to avoid updating statistics in this case:
+ // Updating feature statistics when we have zeros only will cause
+ // thresholds to move towards zero signal situations. This in turn has the
+ // effect that once the signal is "turned on" (non-zero values) everything
+ // will be treated as speech and there is no noise suppression effect.
+ // Depending on the duration of the inactive signal it takes a
+ // considerable amount of time for the system to learn what is noise and
+ // what is speech.
+ return;
+ }
+
+ // Only update analysis counter for frames that are properly analyzed.
+ if (++num_analyzed_frames_ < 0) {
+ num_analyzed_frames_ = 0;
+ }
+
+ // Analyze all channels.
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ std::unique_ptr<ChannelState>& ch_p = channels_[ch];
+ rtc::ArrayView<const float, kNsFrameSize> y_band0(
+ &audio.split_bands_const(ch)[0][0], kNsFrameSize);
+
+ // Form an extended frame and apply analysis filter bank windowing.
+ std::array<float, kFftSize> extended_frame;
+ FormExtendedFrame(y_band0, ch_p->analyze_analysis_memory, extended_frame);
+ ApplyFilterBankWindow(extended_frame);
+
+ // Compute the magnitude spectrum.
+ std::array<float, kFftSize> real;
+ std::array<float, kFftSize> imag;
+ fft_.Fft(extended_frame, real, imag);
+
+ std::array<float, kFftSizeBy2Plus1> signal_spectrum;
+ ComputeMagnitudeSpectrum(real, imag, signal_spectrum);
+
+ // Compute energies.
+ float signal_energy = 0.f;
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ signal_energy += real[i] * real[i] + imag[i] * imag[i];
+ }
+ signal_energy /= kFftSizeBy2Plus1;
+
+ float signal_spectral_sum = 0.f;
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ signal_spectral_sum += signal_spectrum[i];
+ }
+
+ // Estimate the noise spectra and the probability estimates of speech
+ // presence.
+ ch_p->noise_estimator.PreUpdate(num_analyzed_frames_, signal_spectrum,
+ signal_spectral_sum);
+
+ std::array<float, kFftSizeBy2Plus1> post_snr;
+ std::array<float, kFftSizeBy2Plus1> prior_snr;
+ ComputeSnr(ch_p->wiener_filter.get_filter(),
+ ch_p->prev_analysis_signal_spectrum, signal_spectrum,
+ ch_p->noise_estimator.get_prev_noise_spectrum(),
+ ch_p->noise_estimator.get_noise_spectrum(), prior_snr, post_snr);
+
+ ch_p->speech_probability_estimator.Update(
+ num_analyzed_frames_, prior_snr, post_snr,
+ ch_p->noise_estimator.get_conservative_noise_spectrum(),
+ signal_spectrum, signal_spectral_sum, signal_energy);
+
+ ch_p->noise_estimator.PostUpdate(
+ ch_p->speech_probability_estimator.get_probability(), signal_spectrum);
+
+ // Store the magnitude spectrum to make it avalilable for the process
+ // method.
+ std::copy(signal_spectrum.begin(), signal_spectrum.end(),
+ ch_p->prev_analysis_signal_spectrum.begin());
+ }
+}
+
+void NoiseSuppressor::Process(AudioBuffer* audio) {
+ // Select the space for storing data during the processing.
+ std::array<FilterBankState, kMaxNumChannelsOnStack> filter_bank_states_stack;
+ rtc::ArrayView<FilterBankState> filter_bank_states(
+ filter_bank_states_stack.data(), num_channels_);
+ std::array<float, kMaxNumChannelsOnStack> upper_band_gains_stack;
+ rtc::ArrayView<float> upper_band_gains(upper_band_gains_stack.data(),
+ num_channels_);
+ std::array<float, kMaxNumChannelsOnStack> energies_before_filtering_stack;
+ rtc::ArrayView<float> energies_before_filtering(
+ energies_before_filtering_stack.data(), num_channels_);
+ std::array<float, kMaxNumChannelsOnStack> gain_adjustments_stack;
+ rtc::ArrayView<float> gain_adjustments(gain_adjustments_stack.data(),
+ num_channels_);
+ if (NumChannelsOnHeap(num_channels_) > 0) {
+ // If the stack-allocated space is too small, use the heap for storing the
+ // data.
+ filter_bank_states = rtc::ArrayView<FilterBankState>(
+ filter_bank_states_heap_.data(), num_channels_);
+ upper_band_gains =
+ rtc::ArrayView<float>(upper_band_gains_heap_.data(), num_channels_);
+ energies_before_filtering = rtc::ArrayView<float>(
+ energies_before_filtering_heap_.data(), num_channels_);
+ gain_adjustments =
+ rtc::ArrayView<float>(gain_adjustments_heap_.data(), num_channels_);
+ }
+
+ // Compute the suppression filters for all channels.
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ // Form an extended frame and apply analysis filter bank windowing.
+ rtc::ArrayView<float, kNsFrameSize> y_band0(&audio->split_bands(ch)[0][0],
+ kNsFrameSize);
+
+ FormExtendedFrame(y_band0, channels_[ch]->process_analysis_memory,
+ filter_bank_states[ch].extended_frame);
+
+ ApplyFilterBankWindow(filter_bank_states[ch].extended_frame);
+
+ energies_before_filtering[ch] =
+ ComputeEnergyOfExtendedFrame(filter_bank_states[ch].extended_frame);
+
+ // Perform filter bank analysis and compute the magnitude spectrum.
+ fft_.Fft(filter_bank_states[ch].extended_frame, filter_bank_states[ch].real,
+ filter_bank_states[ch].imag);
+
+ std::array<float, kFftSizeBy2Plus1> signal_spectrum;
+ ComputeMagnitudeSpectrum(filter_bank_states[ch].real,
+ filter_bank_states[ch].imag, signal_spectrum);
+
+ // Compute the frequency domain gain filter for noise attenuation.
+ channels_[ch]->wiener_filter.Update(
+ num_analyzed_frames_,
+ channels_[ch]->noise_estimator.get_noise_spectrum(),
+ channels_[ch]->noise_estimator.get_prev_noise_spectrum(),
+ channels_[ch]->noise_estimator.get_parametric_noise_spectrum(),
+ signal_spectrum);
+
+ if (num_bands_ > 1) {
+ // Compute the time-domain gain for attenuating the noise in the upper
+ // bands.
+
+ upper_band_gains[ch] = ComputeUpperBandsGain(
+ suppression_params_.minimum_attenuating_gain,
+ channels_[ch]->wiener_filter.get_filter(),
+ channels_[ch]->speech_probability_estimator.get_probability(),
+ channels_[ch]->prev_analysis_signal_spectrum, signal_spectrum);
+ }
+ }
+
+ // Aggregate the Wiener filters for all channels.
+ std::array<float, kFftSizeBy2Plus1> filter_data;
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> filter = filter_data;
+ if (num_channels_ == 1) {
+ filter = channels_[0]->wiener_filter.get_filter();
+ } else {
+ AggregateWienerFilters(filter_data);
+ }
+
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ // Apply the filter to the lower band.
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ filter_bank_states[ch].real[i] *= filter[i];
+ filter_bank_states[ch].imag[i] *= filter[i];
+ }
+ }
+
+ // Perform filter bank synthesis
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ fft_.Ifft(filter_bank_states[ch].real, filter_bank_states[ch].imag,
+ filter_bank_states[ch].extended_frame);
+ }
+
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ const float energy_after_filtering =
+ ComputeEnergyOfExtendedFrame(filter_bank_states[ch].extended_frame);
+
+ // Apply synthesis window.
+ ApplyFilterBankWindow(filter_bank_states[ch].extended_frame);
+
+ // Compute the adjustment of the noise attenuation filter based on the
+ // effect of the attenuation.
+ gain_adjustments[ch] =
+ channels_[ch]->wiener_filter.ComputeOverallScalingFactor(
+ num_analyzed_frames_,
+ channels_[ch]->speech_probability_estimator.get_prior_probability(),
+ energies_before_filtering[ch], energy_after_filtering);
+ }
+
+ // Select and apply adjustment of the noise attenuation filter based on the
+ // effect of the attenuation.
+ float gain_adjustment = gain_adjustments[0];
+ for (size_t ch = 1; ch < num_channels_; ++ch) {
+ gain_adjustment = std::min(gain_adjustment, gain_adjustments[ch]);
+ }
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ for (size_t i = 0; i < kFftSize; ++i) {
+ filter_bank_states[ch].extended_frame[i] =
+ gain_adjustment * filter_bank_states[ch].extended_frame[i];
+ }
+ }
+
+ // Use overlap-and-add to form the output frame of the lowest band.
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ rtc::ArrayView<float, kNsFrameSize> y_band0(&audio->split_bands(ch)[0][0],
+ kNsFrameSize);
+ OverlapAndAdd(filter_bank_states[ch].extended_frame,
+ channels_[ch]->process_synthesis_memory, y_band0);
+ }
+
+ if (num_bands_ > 1) {
+ // Select the noise attenuating gain to apply to the upper band.
+ float upper_band_gain = upper_band_gains[0];
+ for (size_t ch = 1; ch < num_channels_; ++ch) {
+ upper_band_gain = std::min(upper_band_gain, upper_band_gains[ch]);
+ }
+
+ // Process the upper bands.
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ for (size_t b = 1; b < num_bands_; ++b) {
+ // Delay the upper bands to match the delay of the filterbank applied to
+ // the lowest band.
+ rtc::ArrayView<float, kNsFrameSize> y_band(
+ &audio->split_bands(ch)[b][0], kNsFrameSize);
+ std::array<float, kNsFrameSize> delayed_frame;
+ DelaySignal(y_band, channels_[ch]->process_delay_memory[b - 1],
+ delayed_frame);
+
+ // Apply the time-domain noise-attenuating gain.
+ for (size_t j = 0; j < kNsFrameSize; j++) {
+ y_band[j] = upper_band_gain * delayed_frame[j];
+ }
+ }
+ }
+ }
+
+ // Limit the output the allowed range.
+ for (size_t ch = 0; ch < num_channels_; ++ch) {
+ for (size_t b = 0; b < num_bands_; ++b) {
+ rtc::ArrayView<float, kNsFrameSize> y_band(&audio->split_bands(ch)[b][0],
+ kNsFrameSize);
+ for (size_t j = 0; j < kNsFrameSize; j++) {
+ y_band[j] = std::min(std::max(y_band[j], -32768.f), 32767.f);
+ }
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/noise_suppressor.h b/webrtc/modules/audio_processing/ns/noise_suppressor.h
new file mode 100644
index 0000000..d962886
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/noise_suppressor.h
@@ -0,0 +1,83 @@
+/*
+ * 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_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/ns/noise_estimator.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/ns_config.h"
+#include "modules/audio_processing/ns/ns_fft.h"
+#include "modules/audio_processing/ns/speech_probability_estimator.h"
+#include "modules/audio_processing/ns/wiener_filter.h"
+
+namespace webrtc {
+
+// Class for suppressing noise in a signal.
+class NoiseSuppressor {
+ public:
+ NoiseSuppressor(const NsConfig& config,
+ size_t sample_rate_hz,
+ size_t num_channels);
+ NoiseSuppressor(const NoiseSuppressor&) = delete;
+ NoiseSuppressor& operator=(const NoiseSuppressor&) = delete;
+
+ // Analyses the signal (typically applied before the AEC to avoid analyzing
+ // any comfort noise signal).
+ void Analyze(const AudioBuffer& audio);
+
+ // Applies noise suppression.
+ void Process(AudioBuffer* audio);
+
+ private:
+ const size_t num_bands_;
+ const size_t num_channels_;
+ const SuppressionParams suppression_params_;
+ int32_t num_analyzed_frames_ = -1;
+ NrFft fft_;
+
+ struct ChannelState {
+ ChannelState(const SuppressionParams& suppression_params, size_t num_bands);
+
+ SpeechProbabilityEstimator speech_probability_estimator;
+ WienerFilter wiener_filter;
+ NoiseEstimator noise_estimator;
+ std::array<float, kFftSizeBy2Plus1> prev_analysis_signal_spectrum;
+ std::array<float, kFftSize - kNsFrameSize> analyze_analysis_memory;
+ std::array<float, kOverlapSize> process_analysis_memory;
+ std::array<float, kOverlapSize> process_synthesis_memory;
+ std::vector<std::array<float, kOverlapSize>> process_delay_memory;
+ };
+
+ struct FilterBankState {
+ std::array<float, kFftSize> real;
+ std::array<float, kFftSize> imag;
+ std::array<float, kFftSize> extended_frame;
+ };
+
+ std::vector<FilterBankState> filter_bank_states_heap_;
+ std::vector<float> upper_band_gains_heap_;
+ std::vector<float> energies_before_filtering_heap_;
+ std::vector<float> gain_adjustments_heap_;
+ std::vector<std::unique_ptr<ChannelState>> channels_;
+
+ // Aggregates the Wiener filters into a single filter to use.
+ void AggregateWienerFilters(
+ rtc::ArrayView<float, kFftSizeBy2Plus1> filter) const;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_
diff --git a/webrtc/modules/audio_processing/ns/ns_common.h b/webrtc/modules/audio_processing/ns/ns_common.h
new file mode 100644
index 0000000..d6149f7
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/ns_common.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_
+
+#include <cstddef>
+
+namespace webrtc {
+
+constexpr size_t kFftSize = 256;
+constexpr size_t kFftSizeBy2Plus1 = kFftSize / 2 + 1;
+constexpr size_t kNsFrameSize = 160;
+constexpr size_t kOverlapSize = kFftSize - kNsFrameSize;
+
+constexpr int kShortStartupPhaseBlocks = 50;
+constexpr int kLongStartupPhaseBlocks = 200;
+constexpr int kFeatureUpdateWindowSize = 500;
+
+constexpr float kLtrFeatureThr = 0.5f;
+constexpr float kBinSizeLrt = 0.1f;
+constexpr float kBinSizeSpecFlat = 0.05f;
+constexpr float kBinSizeSpecDiff = 0.1f;
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_
diff --git a/webrtc/modules/audio_processing/ns/ns_config.h b/webrtc/modules/audio_processing/ns/ns_config.h
new file mode 100644
index 0000000..0a285e9
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/ns_config.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_
+#define MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_
+
+namespace webrtc {
+
+// Config struct for the noise suppressor
+struct NsConfig {
+ enum class SuppressionLevel { k6dB, k12dB, k18dB, k21dB };
+ SuppressionLevel target_level = SuppressionLevel::k12dB;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_
diff --git a/webrtc/modules/audio_processing/ns/ns_core.c b/webrtc/modules/audio_processing/ns/ns_core.c
deleted file mode 100644
index 1d60914..0000000
--- a/webrtc/modules/audio_processing/ns/ns_core.c
+++ /dev/null
@@ -1,1416 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <assert.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "webrtc/common_audio/fft4g.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/ns/include/noise_suppression.h"
-#include "webrtc/modules/audio_processing/ns/ns_core.h"
-#include "webrtc/modules/audio_processing/ns/windows_private.h"
-
-// Set Feature Extraction Parameters.
-static void set_feature_extraction_parameters(NoiseSuppressionC* self) {
- // Bin size of histogram.
- self->featureExtractionParams.binSizeLrt = 0.1f;
- self->featureExtractionParams.binSizeSpecFlat = 0.05f;
- self->featureExtractionParams.binSizeSpecDiff = 0.1f;
-
- // Range of histogram over which LRT threshold is computed.
- self->featureExtractionParams.rangeAvgHistLrt = 1.f;
-
- // Scale parameters: multiply dominant peaks of the histograms by scale factor
- // to obtain thresholds for prior model.
- // For LRT and spectral difference.
- self->featureExtractionParams.factor1ModelPars = 1.2f;
- // For spectral_flatness: used when noise is flatter than speech.
- self->featureExtractionParams.factor2ModelPars = 0.9f;
-
- // Peak limit for spectral flatness (varies between 0 and 1).
- self->featureExtractionParams.thresPosSpecFlat = 0.6f;
-
- // Limit on spacing of two highest peaks in histogram: spacing determined by
- // bin size.
- self->featureExtractionParams.limitPeakSpacingSpecFlat =
- 2 * self->featureExtractionParams.binSizeSpecFlat;
- self->featureExtractionParams.limitPeakSpacingSpecDiff =
- 2 * self->featureExtractionParams.binSizeSpecDiff;
-
- // Limit on relevance of second peak.
- self->featureExtractionParams.limitPeakWeightsSpecFlat = 0.5f;
- self->featureExtractionParams.limitPeakWeightsSpecDiff = 0.5f;
-
- // Fluctuation limit of LRT feature.
- self->featureExtractionParams.thresFluctLrt = 0.05f;
-
- // Limit on the max and min values for the feature thresholds.
- self->featureExtractionParams.maxLrt = 1.f;
- self->featureExtractionParams.minLrt = 0.2f;
-
- self->featureExtractionParams.maxSpecFlat = 0.95f;
- self->featureExtractionParams.minSpecFlat = 0.1f;
-
- self->featureExtractionParams.maxSpecDiff = 1.f;
- self->featureExtractionParams.minSpecDiff = 0.16f;
-
- // Criteria of weight of histogram peak to accept/reject feature.
- self->featureExtractionParams.thresWeightSpecFlat =
- (int)(0.3 * (self->modelUpdatePars[1])); // For spectral flatness.
- self->featureExtractionParams.thresWeightSpecDiff =
- (int)(0.3 * (self->modelUpdatePars[1])); // For spectral difference.
-}
-
-// Initialize state.
-int WebRtcNs_InitCore(NoiseSuppressionC* self, uint32_t fs) {
- int i;
- // Check for valid pointer.
- if (self == NULL) {
- return -1;
- }
-
- // Initialization of struct.
- if (fs == 8000 || fs == 16000 || fs == 32000 || fs == 48000) {
- self->fs = fs;
- } else {
- return -1;
- }
- self->windShift = 0;
- // We only support 10ms frames.
- if (fs == 8000) {
- self->blockLen = 80;
- self->anaLen = 128;
- self->window = kBlocks80w128;
- } else {
- self->blockLen = 160;
- self->anaLen = 256;
- self->window = kBlocks160w256;
- }
- self->magnLen = self->anaLen / 2 + 1; // Number of frequency bins.
-
- // Initialize FFT work arrays.
- self->ip[0] = 0; // Setting this triggers initialization.
- memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
- WebRtc_rdft(self->anaLen, 1, self->dataBuf, self->ip, self->wfft);
-
- memset(self->analyzeBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
- memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
- memset(self->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
-
- // For HB processing.
- memset(self->dataBufHB,
- 0,
- sizeof(float) * NUM_HIGH_BANDS_MAX * ANAL_BLOCKL_MAX);
-
- // For quantile noise estimation.
- memset(self->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL);
- for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) {
- self->lquantile[i] = 8.f;
- self->density[i] = 0.3f;
- }
-
- for (i = 0; i < SIMULT; i++) {
- self->counter[i] =
- (int)floor((float)(END_STARTUP_LONG * (i + 1)) / (float)SIMULT);
- }
-
- self->updates = 0;
-
- // Wiener filter initialization.
- for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
- self->smooth[i] = 1.f;
- }
-
- // Set the aggressiveness: default.
- self->aggrMode = 0;
-
- // Initialize variables for new method.
- self->priorSpeechProb = 0.5f; // Prior prob for speech/noise.
- // Previous analyze mag spectrum.
- memset(self->magnPrevAnalyze, 0, sizeof(float) * HALF_ANAL_BLOCKL);
- // Previous process mag spectrum.
- memset(self->magnPrevProcess, 0, sizeof(float) * HALF_ANAL_BLOCKL);
- // Current noise-spectrum.
- memset(self->noise, 0, sizeof(float) * HALF_ANAL_BLOCKL);
- // Previous noise-spectrum.
- memset(self->noisePrev, 0, sizeof(float) * HALF_ANAL_BLOCKL);
- // Conservative noise spectrum estimate.
- memset(self->magnAvgPause, 0, sizeof(float) * HALF_ANAL_BLOCKL);
- // For estimation of HB in second pass.
- memset(self->speechProb, 0, sizeof(float) * HALF_ANAL_BLOCKL);
- // Initial average magnitude spectrum.
- memset(self->initMagnEst, 0, sizeof(float) * HALF_ANAL_BLOCKL);
- for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
- // Smooth LR (same as threshold).
- self->logLrtTimeAvg[i] = LRT_FEATURE_THR;
- }
-
- // Feature quantities.
- // Spectral flatness (start on threshold).
- self->featureData[0] = SF_FEATURE_THR;
- self->featureData[1] = 0.f; // Spectral entropy: not used in this version.
- self->featureData[2] = 0.f; // Spectral variance: not used in this version.
- // Average LRT factor (start on threshold).
- self->featureData[3] = LRT_FEATURE_THR;
- // Spectral template diff (start on threshold).
- self->featureData[4] = SF_FEATURE_THR;
- self->featureData[5] = 0.f; // Normalization for spectral difference.
- // Window time-average of input magnitude spectrum.
- self->featureData[6] = 0.f;
-
- // Histogram quantities: used to estimate/update thresholds for features.
- memset(self->histLrt, 0, sizeof(int) * HIST_PAR_EST);
- memset(self->histSpecFlat, 0, sizeof(int) * HIST_PAR_EST);
- memset(self->histSpecDiff, 0, sizeof(int) * HIST_PAR_EST);
-
-
- self->blockInd = -1; // Frame counter.
- // Default threshold for LRT feature.
- self->priorModelPars[0] = LRT_FEATURE_THR;
- // Threshold for spectral flatness: determined on-line.
- self->priorModelPars[1] = 0.5f;
- // sgn_map par for spectral measure: 1 for flatness measure.
- self->priorModelPars[2] = 1.f;
- // Threshold for template-difference feature: determined on-line.
- self->priorModelPars[3] = 0.5f;
- // Default weighting parameter for LRT feature.
- self->priorModelPars[4] = 1.f;
- // Default weighting parameter for spectral flatness feature.
- self->priorModelPars[5] = 0.f;
- // Default weighting parameter for spectral difference feature.
- self->priorModelPars[6] = 0.f;
-
- // Update flag for parameters:
- // 0 no update, 1 = update once, 2 = update every window.
- self->modelUpdatePars[0] = 2;
- self->modelUpdatePars[1] = 500; // Window for update.
- // Counter for update of conservative noise spectrum.
- self->modelUpdatePars[2] = 0;
- // Counter if the feature thresholds are updated during the sequence.
- self->modelUpdatePars[3] = self->modelUpdatePars[1];
-
- self->signalEnergy = 0.0;
- self->sumMagn = 0.0;
- self->whiteNoiseLevel = 0.0;
- self->pinkNoiseNumerator = 0.0;
- self->pinkNoiseExp = 0.0;
-
- set_feature_extraction_parameters(self);
-
- // Default mode.
- WebRtcNs_set_policy_core(self, 0);
-
- self->initFlag = 1;
- return 0;
-}
-
-// Estimate noise.
-static void NoiseEstimation(NoiseSuppressionC* self,
- float* magn,
- float* noise) {
- size_t i, s, offset;
- float lmagn[HALF_ANAL_BLOCKL], delta;
-
- if (self->updates < END_STARTUP_LONG) {
- self->updates++;
- }
-
- for (i = 0; i < self->magnLen; i++) {
- lmagn[i] = (float)log(magn[i]);
- }
-
- // Loop over simultaneous estimates.
- for (s = 0; s < SIMULT; s++) {
- offset = s * self->magnLen;
-
- // newquantest(...)
- for (i = 0; i < self->magnLen; i++) {
- // Compute delta.
- if (self->density[offset + i] > 1.0) {
- delta = FACTOR * 1.f / self->density[offset + i];
- } else {
- delta = FACTOR;
- }
-
- // Update log quantile estimate.
- if (lmagn[i] > self->lquantile[offset + i]) {
- self->lquantile[offset + i] +=
- QUANTILE * delta / (float)(self->counter[s] + 1);
- } else {
- self->lquantile[offset + i] -=
- (1.f - QUANTILE) * delta / (float)(self->counter[s] + 1);
- }
-
- // Update density estimate.
- if (fabs(lmagn[i] - self->lquantile[offset + i]) < WIDTH) {
- self->density[offset + i] =
- ((float)self->counter[s] * self->density[offset + i] +
- 1.f / (2.f * WIDTH)) /
- (float)(self->counter[s] + 1);
- }
- } // End loop over magnitude spectrum.
-
- if (self->counter[s] >= END_STARTUP_LONG) {
- self->counter[s] = 0;
- if (self->updates >= END_STARTUP_LONG) {
- for (i = 0; i < self->magnLen; i++) {
- self->quantile[i] = (float)exp(self->lquantile[offset + i]);
- }
- }
- }
-
- self->counter[s]++;
- } // End loop over simultaneous estimates.
-
- // Sequentially update the noise during startup.
- if (self->updates < END_STARTUP_LONG) {
- // Use the last "s" to get noise during startup that differ from zero.
- for (i = 0; i < self->magnLen; i++) {
- self->quantile[i] = (float)exp(self->lquantile[offset + i]);
- }
- }
-
- for (i = 0; i < self->magnLen; i++) {
- noise[i] = self->quantile[i];
- }
-}
-
-// Extract thresholds for feature parameters.
-// Histograms are computed over some window size (given by
-// self->modelUpdatePars[1]).
-// Thresholds and weights are extracted every window.
-// |flag| = 0 updates histogram only, |flag| = 1 computes the threshold/weights.
-// Threshold and weights are returned in: self->priorModelPars.
-static void FeatureParameterExtraction(NoiseSuppressionC* self, int flag) {
- int i, useFeatureSpecFlat, useFeatureSpecDiff, numHistLrt;
- int maxPeak1, maxPeak2;
- int weightPeak1SpecFlat, weightPeak2SpecFlat, weightPeak1SpecDiff,
- weightPeak2SpecDiff;
-
- float binMid, featureSum;
- float posPeak1SpecFlat, posPeak2SpecFlat, posPeak1SpecDiff, posPeak2SpecDiff;
- float fluctLrt, avgHistLrt, avgSquareHistLrt, avgHistLrtCompl;
-
- // 3 features: LRT, flatness, difference.
- // lrt_feature = self->featureData[3];
- // flat_feature = self->featureData[0];
- // diff_feature = self->featureData[4];
-
- // Update histograms.
- if (flag == 0) {
- // LRT
- if ((self->featureData[3] <
- HIST_PAR_EST * self->featureExtractionParams.binSizeLrt) &&
- (self->featureData[3] >= 0.0)) {
- i = (int)(self->featureData[3] /
- self->featureExtractionParams.binSizeLrt);
- self->histLrt[i]++;
- }
- // Spectral flatness.
- if ((self->featureData[0] <
- HIST_PAR_EST * self->featureExtractionParams.binSizeSpecFlat) &&
- (self->featureData[0] >= 0.0)) {
- i = (int)(self->featureData[0] /
- self->featureExtractionParams.binSizeSpecFlat);
- self->histSpecFlat[i]++;
- }
- // Spectral difference.
- if ((self->featureData[4] <
- HIST_PAR_EST * self->featureExtractionParams.binSizeSpecDiff) &&
- (self->featureData[4] >= 0.0)) {
- i = (int)(self->featureData[4] /
- self->featureExtractionParams.binSizeSpecDiff);
- self->histSpecDiff[i]++;
- }
- }
-
- // Extract parameters for speech/noise probability.
- if (flag == 1) {
- // LRT feature: compute the average over
- // self->featureExtractionParams.rangeAvgHistLrt.
- avgHistLrt = 0.0;
- avgHistLrtCompl = 0.0;
- avgSquareHistLrt = 0.0;
- numHistLrt = 0;
- for (i = 0; i < HIST_PAR_EST; i++) {
- binMid = ((float)i + 0.5f) * self->featureExtractionParams.binSizeLrt;
- if (binMid <= self->featureExtractionParams.rangeAvgHistLrt) {
- avgHistLrt += self->histLrt[i] * binMid;
- numHistLrt += self->histLrt[i];
- }
- avgSquareHistLrt += self->histLrt[i] * binMid * binMid;
- avgHistLrtCompl += self->histLrt[i] * binMid;
- }
- if (numHistLrt > 0) {
- avgHistLrt = avgHistLrt / ((float)numHistLrt);
- }
- avgHistLrtCompl = avgHistLrtCompl / ((float)self->modelUpdatePars[1]);
- avgSquareHistLrt = avgSquareHistLrt / ((float)self->modelUpdatePars[1]);
- fluctLrt = avgSquareHistLrt - avgHistLrt * avgHistLrtCompl;
- // Get threshold for LRT feature.
- if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
- // Very low fluctuation, so likely noise.
- self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
- } else {
- self->priorModelPars[0] =
- self->featureExtractionParams.factor1ModelPars * avgHistLrt;
- // Check if value is within min/max range.
- if (self->priorModelPars[0] < self->featureExtractionParams.minLrt) {
- self->priorModelPars[0] = self->featureExtractionParams.minLrt;
- }
- if (self->priorModelPars[0] > self->featureExtractionParams.maxLrt) {
- self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
- }
- }
- // Done with LRT feature.
-
- // For spectral flatness and spectral difference: compute the main peaks of
- // histogram.
- maxPeak1 = 0;
- maxPeak2 = 0;
- posPeak1SpecFlat = 0.0;
- posPeak2SpecFlat = 0.0;
- weightPeak1SpecFlat = 0;
- weightPeak2SpecFlat = 0;
-
- // Peaks for flatness.
- for (i = 0; i < HIST_PAR_EST; i++) {
- binMid =
- (i + 0.5f) * self->featureExtractionParams.binSizeSpecFlat;
- if (self->histSpecFlat[i] > maxPeak1) {
- // Found new "first" peak.
- maxPeak2 = maxPeak1;
- weightPeak2SpecFlat = weightPeak1SpecFlat;
- posPeak2SpecFlat = posPeak1SpecFlat;
-
- maxPeak1 = self->histSpecFlat[i];
- weightPeak1SpecFlat = self->histSpecFlat[i];
- posPeak1SpecFlat = binMid;
- } else if (self->histSpecFlat[i] > maxPeak2) {
- // Found new "second" peak.
- maxPeak2 = self->histSpecFlat[i];
- weightPeak2SpecFlat = self->histSpecFlat[i];
- posPeak2SpecFlat = binMid;
- }
- }
-
- // Compute two peaks for spectral difference.
- maxPeak1 = 0;
- maxPeak2 = 0;
- posPeak1SpecDiff = 0.0;
- posPeak2SpecDiff = 0.0;
- weightPeak1SpecDiff = 0;
- weightPeak2SpecDiff = 0;
- // Peaks for spectral difference.
- for (i = 0; i < HIST_PAR_EST; i++) {
- binMid =
- ((float)i + 0.5f) * self->featureExtractionParams.binSizeSpecDiff;
- if (self->histSpecDiff[i] > maxPeak1) {
- // Found new "first" peak.
- maxPeak2 = maxPeak1;
- weightPeak2SpecDiff = weightPeak1SpecDiff;
- posPeak2SpecDiff = posPeak1SpecDiff;
-
- maxPeak1 = self->histSpecDiff[i];
- weightPeak1SpecDiff = self->histSpecDiff[i];
- posPeak1SpecDiff = binMid;
- } else if (self->histSpecDiff[i] > maxPeak2) {
- // Found new "second" peak.
- maxPeak2 = self->histSpecDiff[i];
- weightPeak2SpecDiff = self->histSpecDiff[i];
- posPeak2SpecDiff = binMid;
- }
- }
-
- // For spectrum flatness feature.
- useFeatureSpecFlat = 1;
- // Merge the two peaks if they are close.
- if ((fabs(posPeak2SpecFlat - posPeak1SpecFlat) <
- self->featureExtractionParams.limitPeakSpacingSpecFlat) &&
- (weightPeak2SpecFlat >
- self->featureExtractionParams.limitPeakWeightsSpecFlat *
- weightPeak1SpecFlat)) {
- weightPeak1SpecFlat += weightPeak2SpecFlat;
- posPeak1SpecFlat = 0.5f * (posPeak1SpecFlat + posPeak2SpecFlat);
- }
- // Reject if weight of peaks is not large enough, or peak value too small.
- if (weightPeak1SpecFlat <
- self->featureExtractionParams.thresWeightSpecFlat ||
- posPeak1SpecFlat < self->featureExtractionParams.thresPosSpecFlat) {
- useFeatureSpecFlat = 0;
- }
- // If selected, get the threshold.
- if (useFeatureSpecFlat == 1) {
- // Compute the threshold.
- self->priorModelPars[1] =
- self->featureExtractionParams.factor2ModelPars * posPeak1SpecFlat;
- // Check if value is within min/max range.
- if (self->priorModelPars[1] < self->featureExtractionParams.minSpecFlat) {
- self->priorModelPars[1] = self->featureExtractionParams.minSpecFlat;
- }
- if (self->priorModelPars[1] > self->featureExtractionParams.maxSpecFlat) {
- self->priorModelPars[1] = self->featureExtractionParams.maxSpecFlat;
- }
- }
- // Done with flatness feature.
-
- // For template feature.
- useFeatureSpecDiff = 1;
- // Merge the two peaks if they are close.
- if ((fabs(posPeak2SpecDiff - posPeak1SpecDiff) <
- self->featureExtractionParams.limitPeakSpacingSpecDiff) &&
- (weightPeak2SpecDiff >
- self->featureExtractionParams.limitPeakWeightsSpecDiff *
- weightPeak1SpecDiff)) {
- weightPeak1SpecDiff += weightPeak2SpecDiff;
- posPeak1SpecDiff = 0.5f * (posPeak1SpecDiff + posPeak2SpecDiff);
- }
- // Get the threshold value.
- self->priorModelPars[3] =
- self->featureExtractionParams.factor1ModelPars * posPeak1SpecDiff;
- // Reject if weight of peaks is not large enough.
- if (weightPeak1SpecDiff <
- self->featureExtractionParams.thresWeightSpecDiff) {
- useFeatureSpecDiff = 0;
- }
- // Check if value is within min/max range.
- if (self->priorModelPars[3] < self->featureExtractionParams.minSpecDiff) {
- self->priorModelPars[3] = self->featureExtractionParams.minSpecDiff;
- }
- if (self->priorModelPars[3] > self->featureExtractionParams.maxSpecDiff) {
- self->priorModelPars[3] = self->featureExtractionParams.maxSpecDiff;
- }
- // Done with spectral difference feature.
-
- // Don't use template feature if fluctuation of LRT feature is very low:
- // most likely just noise state.
- if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
- useFeatureSpecDiff = 0;
- }
-
- // Select the weights between the features.
- // self->priorModelPars[4] is weight for LRT: always selected.
- // self->priorModelPars[5] is weight for spectral flatness.
- // self->priorModelPars[6] is weight for spectral difference.
- featureSum = (float)(1 + useFeatureSpecFlat + useFeatureSpecDiff);
- self->priorModelPars[4] = 1.f / featureSum;
- self->priorModelPars[5] = ((float)useFeatureSpecFlat) / featureSum;
- self->priorModelPars[6] = ((float)useFeatureSpecDiff) / featureSum;
-
- // Set hists to zero for next update.
- if (self->modelUpdatePars[0] >= 1) {
- for (i = 0; i < HIST_PAR_EST; i++) {
- self->histLrt[i] = 0;
- self->histSpecFlat[i] = 0;
- self->histSpecDiff[i] = 0;
- }
- }
- } // End of flag == 1.
-}
-
-// Compute spectral flatness on input spectrum.
-// |magnIn| is the magnitude spectrum.
-// Spectral flatness is returned in self->featureData[0].
-static void ComputeSpectralFlatness(NoiseSuppressionC* self,
- const float* magnIn) {
- size_t i;
- size_t shiftLP = 1; // Option to remove first bin(s) from spectral measures.
- float avgSpectralFlatnessNum, avgSpectralFlatnessDen, spectralTmp;
-
- // Compute spectral measures.
- // For flatness.
- avgSpectralFlatnessNum = 0.0;
- avgSpectralFlatnessDen = self->sumMagn;
- for (i = 0; i < shiftLP; i++) {
- avgSpectralFlatnessDen -= magnIn[i];
- }
- // Compute log of ratio of the geometric to arithmetic mean: check for log(0)
- // case.
- for (i = shiftLP; i < self->magnLen; i++) {
- if (magnIn[i] > 0.0) {
- avgSpectralFlatnessNum += (float)log(magnIn[i]);
- } else {
- self->featureData[0] -= SPECT_FL_TAVG * self->featureData[0];
- return;
- }
- }
- // Normalize.
- avgSpectralFlatnessDen = avgSpectralFlatnessDen / self->magnLen;
- avgSpectralFlatnessNum = avgSpectralFlatnessNum / self->magnLen;
-
- // Ratio and inverse log: check for case of log(0).
- spectralTmp = (float)exp(avgSpectralFlatnessNum) / avgSpectralFlatnessDen;
-
- // Time-avg update of spectral flatness feature.
- self->featureData[0] += SPECT_FL_TAVG * (spectralTmp - self->featureData[0]);
- // Done with flatness feature.
-}
-
-// Compute prior and post SNR based on quantile noise estimation.
-// Compute DD estimate of prior SNR.
-// Inputs:
-// * |magn| is the signal magnitude spectrum estimate.
-// * |noise| is the magnitude noise spectrum estimate.
-// Outputs:
-// * |snrLocPrior| is the computed prior SNR.
-// * |snrLocPost| is the computed post SNR.
-static void ComputeSnr(const NoiseSuppressionC* self,
- const float* magn,
- const float* noise,
- float* snrLocPrior,
- float* snrLocPost) {
- size_t i;
-
- for (i = 0; i < self->magnLen; i++) {
- // Previous post SNR.
- // Previous estimate: based on previous frame with gain filter.
- float previousEstimateStsa = self->magnPrevAnalyze[i] /
- (self->noisePrev[i] + 0.0001f) * self->smooth[i];
- // Post SNR.
- snrLocPost[i] = 0.f;
- if (magn[i] > noise[i]) {
- snrLocPost[i] = magn[i] / (noise[i] + 0.0001f) - 1.f;
- }
- // DD estimate is sum of two terms: current estimate and previous estimate.
- // Directed decision update of snrPrior.
- snrLocPrior[i] =
- DD_PR_SNR * previousEstimateStsa + (1.f - DD_PR_SNR) * snrLocPost[i];
- } // End of loop over frequencies.
-}
-
-// Compute the difference measure between input spectrum and a template/learned
-// noise spectrum.
-// |magnIn| is the input spectrum.
-// The reference/template spectrum is self->magnAvgPause[i].
-// Returns (normalized) spectral difference in self->featureData[4].
-static void ComputeSpectralDifference(NoiseSuppressionC* self,
- const float* magnIn) {
- // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 /
- // var(magnAvgPause)
- size_t i;
- float avgPause, avgMagn, covMagnPause, varPause, varMagn, avgDiffNormMagn;
-
- avgPause = 0.0;
- avgMagn = self->sumMagn;
- // Compute average quantities.
- for (i = 0; i < self->magnLen; i++) {
- // Conservative smooth noise spectrum from pause frames.
- avgPause += self->magnAvgPause[i];
- }
- avgPause /= self->magnLen;
- avgMagn /= self->magnLen;
-
- covMagnPause = 0.0;
- varPause = 0.0;
- varMagn = 0.0;
- // Compute variance and covariance quantities.
- for (i = 0; i < self->magnLen; i++) {
- covMagnPause += (magnIn[i] - avgMagn) * (self->magnAvgPause[i] - avgPause);
- varPause +=
- (self->magnAvgPause[i] - avgPause) * (self->magnAvgPause[i] - avgPause);
- varMagn += (magnIn[i] - avgMagn) * (magnIn[i] - avgMagn);
- }
- covMagnPause /= self->magnLen;
- varPause /= self->magnLen;
- varMagn /= self->magnLen;
- // Update of average magnitude spectrum.
- self->featureData[6] += self->signalEnergy;
-
- avgDiffNormMagn =
- varMagn - (covMagnPause * covMagnPause) / (varPause + 0.0001f);
- // Normalize and compute time-avg update of difference feature.
- avgDiffNormMagn = (float)(avgDiffNormMagn / (self->featureData[5] + 0.0001f));
- self->featureData[4] +=
- SPECT_DIFF_TAVG * (avgDiffNormMagn - self->featureData[4]);
-}
-
-// Compute speech/noise probability.
-// Speech/noise probability is returned in |probSpeechFinal|.
-// |magn| is the input magnitude spectrum.
-// |noise| is the noise spectrum.
-// |snrLocPrior| is the prior SNR for each frequency.
-// |snrLocPost| is the post SNR for each frequency.
-static void SpeechNoiseProb(NoiseSuppressionC* self,
- float* probSpeechFinal,
- const float* snrLocPrior,
- const float* snrLocPost) {
- size_t i;
- int sgnMap;
- float invLrt, gainPrior, indPrior;
- float logLrtTimeAvgKsum, besselTmp;
- float indicator0, indicator1, indicator2;
- float tmpFloat1, tmpFloat2;
- float weightIndPrior0, weightIndPrior1, weightIndPrior2;
- float threshPrior0, threshPrior1, threshPrior2;
- float widthPrior, widthPrior0, widthPrior1, widthPrior2;
-
- widthPrior0 = WIDTH_PR_MAP;
- // Width for pause region: lower range, so increase width in tanh map.
- widthPrior1 = 2.f * WIDTH_PR_MAP;
- widthPrior2 = 2.f * WIDTH_PR_MAP; // For spectral-difference measure.
-
- // Threshold parameters for features.
- threshPrior0 = self->priorModelPars[0];
- threshPrior1 = self->priorModelPars[1];
- threshPrior2 = self->priorModelPars[3];
-
- // Sign for flatness feature.
- sgnMap = (int)(self->priorModelPars[2]);
-
- // Weight parameters for features.
- weightIndPrior0 = self->priorModelPars[4];
- weightIndPrior1 = self->priorModelPars[5];
- weightIndPrior2 = self->priorModelPars[6];
-
- // Compute feature based on average LR factor.
- // This is the average over all frequencies of the smooth log LRT.
- logLrtTimeAvgKsum = 0.0;
- for (i = 0; i < self->magnLen; i++) {
- tmpFloat1 = 1.f + 2.f * snrLocPrior[i];
- tmpFloat2 = 2.f * snrLocPrior[i] / (tmpFloat1 + 0.0001f);
- besselTmp = (snrLocPost[i] + 1.f) * tmpFloat2;
- self->logLrtTimeAvg[i] +=
- LRT_TAVG * (besselTmp - (float)log(tmpFloat1) - self->logLrtTimeAvg[i]);
- logLrtTimeAvgKsum += self->logLrtTimeAvg[i];
- }
- logLrtTimeAvgKsum = (float)logLrtTimeAvgKsum / (self->magnLen);
- self->featureData[3] = logLrtTimeAvgKsum;
- // Done with computation of LR factor.
-
- // Compute the indicator functions.
- // Average LRT feature.
- widthPrior = widthPrior0;
- // Use larger width in tanh map for pause regions.
- if (logLrtTimeAvgKsum < threshPrior0) {
- widthPrior = widthPrior1;
- }
- // Compute indicator function: sigmoid map.
- indicator0 =
- 0.5f *
- ((float)tanh(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) + 1.f);
-
- // Spectral flatness feature.
- tmpFloat1 = self->featureData[0];
- widthPrior = widthPrior0;
- // Use larger width in tanh map for pause regions.
- if (sgnMap == 1 && (tmpFloat1 > threshPrior1)) {
- widthPrior = widthPrior1;
- }
- if (sgnMap == -1 && (tmpFloat1 < threshPrior1)) {
- widthPrior = widthPrior1;
- }
- // Compute indicator function: sigmoid map.
- indicator1 =
- 0.5f *
- ((float)tanh((float)sgnMap * widthPrior * (threshPrior1 - tmpFloat1)) +
- 1.f);
-
- // For template spectrum-difference.
- tmpFloat1 = self->featureData[4];
- widthPrior = widthPrior0;
- // Use larger width in tanh map for pause regions.
- if (tmpFloat1 < threshPrior2) {
- widthPrior = widthPrior2;
- }
- // Compute indicator function: sigmoid map.
- indicator2 =
- 0.5f * ((float)tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.f);
-
- // Combine the indicator function with the feature weights.
- indPrior = weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 +
- weightIndPrior2 * indicator2;
- // Done with computing indicator function.
-
- // Compute the prior probability.
- self->priorSpeechProb += PRIOR_UPDATE * (indPrior - self->priorSpeechProb);
- // Make sure probabilities are within range: keep floor to 0.01.
- if (self->priorSpeechProb > 1.f) {
- self->priorSpeechProb = 1.f;
- }
- if (self->priorSpeechProb < 0.01f) {
- self->priorSpeechProb = 0.01f;
- }
-
- // Final speech probability: combine prior model with LR factor:.
- gainPrior = (1.f - self->priorSpeechProb) / (self->priorSpeechProb + 0.0001f);
- for (i = 0; i < self->magnLen; i++) {
- invLrt = (float)exp(-self->logLrtTimeAvg[i]);
- invLrt = (float)gainPrior * invLrt;
- probSpeechFinal[i] = 1.f / (1.f + invLrt);
- }
-}
-
-// Update the noise features.
-// Inputs:
-// * |magn| is the signal magnitude spectrum estimate.
-// * |updateParsFlag| is an update flag for parameters.
-static void FeatureUpdate(NoiseSuppressionC* self,
- const float* magn,
- int updateParsFlag) {
- // Compute spectral flatness on input spectrum.
- ComputeSpectralFlatness(self, magn);
- // Compute difference of input spectrum with learned/estimated noise spectrum.
- ComputeSpectralDifference(self, magn);
- // Compute histograms for parameter decisions (thresholds and weights for
- // features).
- // Parameters are extracted once every window time.
- // (=self->modelUpdatePars[1])
- if (updateParsFlag >= 1) {
- // Counter update.
- self->modelUpdatePars[3]--;
- // Update histogram.
- if (self->modelUpdatePars[3] > 0) {
- FeatureParameterExtraction(self, 0);
- }
- // Compute model parameters.
- if (self->modelUpdatePars[3] == 0) {
- FeatureParameterExtraction(self, 1);
- self->modelUpdatePars[3] = self->modelUpdatePars[1];
- // If wish to update only once, set flag to zero.
- if (updateParsFlag == 1) {
- self->modelUpdatePars[0] = 0;
- } else {
- // Update every window:
- // Get normalization for spectral difference for next window estimate.
- self->featureData[6] =
- self->featureData[6] / ((float)self->modelUpdatePars[1]);
- self->featureData[5] =
- 0.5f * (self->featureData[6] + self->featureData[5]);
- self->featureData[6] = 0.f;
- }
- }
- }
-}
-
-// Update the noise estimate.
-// Inputs:
-// * |magn| is the signal magnitude spectrum estimate.
-// * |snrLocPrior| is the prior SNR.
-// * |snrLocPost| is the post SNR.
-// Output:
-// * |noise| is the updated noise magnitude spectrum estimate.
-static void UpdateNoiseEstimate(NoiseSuppressionC* self,
- const float* magn,
- const float* snrLocPrior,
- const float* snrLocPost,
- float* noise) {
- size_t i;
- float probSpeech, probNonSpeech;
- // Time-avg parameter for noise update.
- float gammaNoiseTmp = NOISE_UPDATE;
- float gammaNoiseOld;
- float noiseUpdateTmp;
-
- for (i = 0; i < self->magnLen; i++) {
- probSpeech = self->speechProb[i];
- probNonSpeech = 1.f - probSpeech;
- // Temporary noise update:
- // Use it for speech frames if update value is less than previous.
- noiseUpdateTmp = gammaNoiseTmp * self->noisePrev[i] +
- (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
- probSpeech * self->noisePrev[i]);
- // Time-constant based on speech/noise state.
- gammaNoiseOld = gammaNoiseTmp;
- gammaNoiseTmp = NOISE_UPDATE;
- // Increase gamma (i.e., less noise update) for frame likely to be speech.
- if (probSpeech > PROB_RANGE) {
- gammaNoiseTmp = SPEECH_UPDATE;
- }
- // Conservative noise update.
- if (probSpeech < PROB_RANGE) {
- self->magnAvgPause[i] += GAMMA_PAUSE * (magn[i] - self->magnAvgPause[i]);
- }
- // Noise update.
- if (gammaNoiseTmp == gammaNoiseOld) {
- noise[i] = noiseUpdateTmp;
- } else {
- noise[i] = gammaNoiseTmp * self->noisePrev[i] +
- (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
- probSpeech * self->noisePrev[i]);
- // Allow for noise update downwards:
- // If noise update decreases the noise, it is safe, so allow it to
- // happen.
- if (noiseUpdateTmp < noise[i]) {
- noise[i] = noiseUpdateTmp;
- }
- }
- } // End of freq loop.
-}
-
-// Updates |buffer| with a new |frame|.
-// Inputs:
-// * |frame| is a new speech frame or NULL for setting to zero.
-// * |frame_length| is the length of the new frame.
-// * |buffer_length| is the length of the buffer.
-// Output:
-// * |buffer| is the updated buffer.
-static void UpdateBuffer(const float* frame,
- size_t frame_length,
- size_t buffer_length,
- float* buffer) {
- assert(buffer_length < 2 * frame_length);
-
- memcpy(buffer,
- buffer + frame_length,
- sizeof(*buffer) * (buffer_length - frame_length));
- if (frame) {
- memcpy(buffer + buffer_length - frame_length,
- frame,
- sizeof(*buffer) * frame_length);
- } else {
- memset(buffer + buffer_length - frame_length,
- 0,
- sizeof(*buffer) * frame_length);
- }
-}
-
-// Transforms the signal from time to frequency domain.
-// Inputs:
-// * |time_data| is the signal in the time domain.
-// * |time_data_length| is the length of the analysis buffer.
-// * |magnitude_length| is the length of the spectrum magnitude, which equals
-// the length of both |real| and |imag| (time_data_length / 2 + 1).
-// Outputs:
-// * |time_data| is the signal in the frequency domain.
-// * |real| is the real part of the frequency domain.
-// * |imag| is the imaginary part of the frequency domain.
-// * |magn| is the calculated signal magnitude in the frequency domain.
-static void FFT(NoiseSuppressionC* self,
- float* time_data,
- size_t time_data_length,
- size_t magnitude_length,
- float* real,
- float* imag,
- float* magn) {
- size_t i;
-
- assert(magnitude_length == time_data_length / 2 + 1);
-
- WebRtc_rdft(time_data_length, 1, time_data, self->ip, self->wfft);
-
- imag[0] = 0;
- real[0] = time_data[0];
- magn[0] = fabsf(real[0]) + 1.f;
- imag[magnitude_length - 1] = 0;
- real[magnitude_length - 1] = time_data[1];
- magn[magnitude_length - 1] = fabsf(real[magnitude_length - 1]) + 1.f;
- for (i = 1; i < magnitude_length - 1; ++i) {
- real[i] = time_data[2 * i];
- imag[i] = time_data[2 * i + 1];
- // Magnitude spectrum.
- magn[i] = sqrtf(real[i] * real[i] + imag[i] * imag[i]) + 1.f;
- }
-}
-
-// Transforms the signal from frequency to time domain.
-// Inputs:
-// * |real| is the real part of the frequency domain.
-// * |imag| is the imaginary part of the frequency domain.
-// * |magnitude_length| is the length of the spectrum magnitude, which equals
-// the length of both |real| and |imag|.
-// * |time_data_length| is the length of the analysis buffer
-// (2 * (magnitude_length - 1)).
-// Output:
-// * |time_data| is the signal in the time domain.
-static void IFFT(NoiseSuppressionC* self,
- const float* real,
- const float* imag,
- size_t magnitude_length,
- size_t time_data_length,
- float* time_data) {
- size_t i;
-
- assert(time_data_length == 2 * (magnitude_length - 1));
-
- time_data[0] = real[0];
- time_data[1] = real[magnitude_length - 1];
- for (i = 1; i < magnitude_length - 1; ++i) {
- time_data[2 * i] = real[i];
- time_data[2 * i + 1] = imag[i];
- }
- WebRtc_rdft(time_data_length, -1, time_data, self->ip, self->wfft);
-
- for (i = 0; i < time_data_length; ++i) {
- time_data[i] *= 2.f / time_data_length; // FFT scaling.
- }
-}
-
-// Calculates the energy of a buffer.
-// Inputs:
-// * |buffer| is the buffer over which the energy is calculated.
-// * |length| is the length of the buffer.
-// Returns the calculated energy.
-static float Energy(const float* buffer, size_t length) {
- size_t i;
- float energy = 0.f;
-
- for (i = 0; i < length; ++i) {
- energy += buffer[i] * buffer[i];
- }
-
- return energy;
-}
-
-// Windows a buffer.
-// Inputs:
-// * |window| is the window by which to multiply.
-// * |data| is the data without windowing.
-// * |length| is the length of the window and data.
-// Output:
-// * |data_windowed| is the windowed data.
-static void Windowing(const float* window,
- const float* data,
- size_t length,
- float* data_windowed) {
- size_t i;
-
- for (i = 0; i < length; ++i) {
- data_windowed[i] = window[i] * data[i];
- }
-}
-
-// Estimate prior SNR decision-directed and compute DD based Wiener Filter.
-// Input:
-// * |magn| is the signal magnitude spectrum estimate.
-// Output:
-// * |theFilter| is the frequency response of the computed Wiener filter.
-static void ComputeDdBasedWienerFilter(const NoiseSuppressionC* self,
- const float* magn,
- float* theFilter) {
- size_t i;
- float snrPrior, previousEstimateStsa, currentEstimateStsa;
-
- for (i = 0; i < self->magnLen; i++) {
- // Previous estimate: based on previous frame with gain filter.
- previousEstimateStsa = self->magnPrevProcess[i] /
- (self->noisePrev[i] + 0.0001f) * self->smooth[i];
- // Post and prior SNR.
- currentEstimateStsa = 0.f;
- if (magn[i] > self->noise[i]) {
- currentEstimateStsa = magn[i] / (self->noise[i] + 0.0001f) - 1.f;
- }
- // DD estimate is sum of two terms: current estimate and previous estimate.
- // Directed decision update of |snrPrior|.
- snrPrior = DD_PR_SNR * previousEstimateStsa +
- (1.f - DD_PR_SNR) * currentEstimateStsa;
- // Gain filter.
- theFilter[i] = snrPrior / (self->overdrive + snrPrior);
- } // End of loop over frequencies.
-}
-
-// Changes the aggressiveness of the noise suppression method.
-// |mode| = 0 is mild (6dB), |mode| = 1 is medium (10dB) and |mode| = 2 is
-// aggressive (15dB).
-// Returns 0 on success and -1 otherwise.
-int WebRtcNs_set_policy_core(NoiseSuppressionC* self, int mode) {
- // Allow for modes: 0, 1, 2, 3.
- if (mode < 0 || mode > 3) {
- return (-1);
- }
-
- self->aggrMode = mode;
- if (mode == 0) {
- self->overdrive = 1.f;
- self->denoiseBound = 0.5f;
- self->gainmap = 0;
- } else if (mode == 1) {
- // self->overdrive = 1.25f;
- self->overdrive = 1.f;
- self->denoiseBound = 0.25f;
- self->gainmap = 1;
- } else if (mode == 2) {
- // self->overdrive = 1.25f;
- self->overdrive = 1.1f;
- self->denoiseBound = 0.125f;
- self->gainmap = 1;
- } else if (mode == 3) {
- // self->overdrive = 1.3f;
- self->overdrive = 1.25f;
- self->denoiseBound = 0.09f;
- self->gainmap = 1;
- }
- return 0;
-}
-
-void WebRtcNs_AnalyzeCore(NoiseSuppressionC* self, const float* speechFrame) {
- size_t i;
- const size_t kStartBand = 5; // Skip first frequency bins during estimation.
- int updateParsFlag;
- float energy;
- float signalEnergy = 0.f;
- float sumMagn = 0.f;
- float tmpFloat1, tmpFloat2, tmpFloat3;
- float winData[ANAL_BLOCKL_MAX];
- float magn[HALF_ANAL_BLOCKL], noise[HALF_ANAL_BLOCKL];
- float snrLocPost[HALF_ANAL_BLOCKL], snrLocPrior[HALF_ANAL_BLOCKL];
- float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL];
- // Variables during startup.
- float sum_log_i = 0.0;
- float sum_log_i_square = 0.0;
- float sum_log_magn = 0.0;
- float sum_log_i_log_magn = 0.0;
- float parametric_exp = 0.0;
- float parametric_num = 0.0;
-
- // Check that initiation has been done.
- assert(self->initFlag == 1);
- updateParsFlag = self->modelUpdatePars[0];
-
- // Update analysis buffer for L band.
- UpdateBuffer(speechFrame, self->blockLen, self->anaLen, self->analyzeBuf);
-
- Windowing(self->window, self->analyzeBuf, self->anaLen, winData);
- energy = Energy(winData, self->anaLen);
- if (energy == 0.0) {
- // We want to avoid updating statistics in this case:
- // Updating feature statistics when we have zeros only will cause
- // thresholds to move towards zero signal situations. This in turn has the
- // effect that once the signal is "turned on" (non-zero values) everything
- // will be treated as speech and there is no noise suppression effect.
- // Depending on the duration of the inactive signal it takes a
- // considerable amount of time for the system to learn what is noise and
- // what is speech.
- return;
- }
-
- self->blockInd++; // Update the block index only when we process a block.
-
- FFT(self, winData, self->anaLen, self->magnLen, real, imag, magn);
-
- for (i = 0; i < self->magnLen; i++) {
- signalEnergy += real[i] * real[i] + imag[i] * imag[i];
- sumMagn += magn[i];
- if (self->blockInd < END_STARTUP_SHORT) {
- if (i >= kStartBand) {
- tmpFloat2 = logf((float)i);
- sum_log_i += tmpFloat2;
- sum_log_i_square += tmpFloat2 * tmpFloat2;
- tmpFloat1 = logf(magn[i]);
- sum_log_magn += tmpFloat1;
- sum_log_i_log_magn += tmpFloat2 * tmpFloat1;
- }
- }
- }
- signalEnergy /= self->magnLen;
- self->signalEnergy = signalEnergy;
- self->sumMagn = sumMagn;
-
- // Quantile noise estimate.
- NoiseEstimation(self, magn, noise);
- // Compute simplified noise model during startup.
- if (self->blockInd < END_STARTUP_SHORT) {
- // Estimate White noise.
- self->whiteNoiseLevel += sumMagn / self->magnLen * self->overdrive;
- // Estimate Pink noise parameters.
- tmpFloat1 = sum_log_i_square * (self->magnLen - kStartBand);
- tmpFloat1 -= (sum_log_i * sum_log_i);
- tmpFloat2 =
- (sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn);
- tmpFloat3 = tmpFloat2 / tmpFloat1;
- // Constrain the estimated spectrum to be positive.
- if (tmpFloat3 < 0.f) {
- tmpFloat3 = 0.f;
- }
- self->pinkNoiseNumerator += tmpFloat3;
- tmpFloat2 = (sum_log_i * sum_log_magn);
- tmpFloat2 -= (self->magnLen - kStartBand) * sum_log_i_log_magn;
- tmpFloat3 = tmpFloat2 / tmpFloat1;
- // Constrain the pink noise power to be in the interval [0, 1].
- if (tmpFloat3 < 0.f) {
- tmpFloat3 = 0.f;
- }
- if (tmpFloat3 > 1.f) {
- tmpFloat3 = 1.f;
- }
- self->pinkNoiseExp += tmpFloat3;
-
- // Calculate frequency independent parts of parametric noise estimate.
- if (self->pinkNoiseExp > 0.f) {
- // Use pink noise estimate.
- parametric_num =
- expf(self->pinkNoiseNumerator / (float)(self->blockInd + 1));
- parametric_num *= (float)(self->blockInd + 1);
- parametric_exp = self->pinkNoiseExp / (float)(self->blockInd + 1);
- }
- for (i = 0; i < self->magnLen; i++) {
- // Estimate the background noise using the white and pink noise
- // parameters.
- if (self->pinkNoiseExp == 0.f) {
- // Use white noise estimate.
- self->parametricNoise[i] = self->whiteNoiseLevel;
- } else {
- // Use pink noise estimate.
- float use_band = (float)(i < kStartBand ? kStartBand : i);
- self->parametricNoise[i] =
- parametric_num / powf(use_band, parametric_exp);
- }
- // Weight quantile noise with modeled noise.
- noise[i] *= (self->blockInd);
- tmpFloat2 =
- self->parametricNoise[i] * (END_STARTUP_SHORT - self->blockInd);
- noise[i] += (tmpFloat2 / (float)(self->blockInd + 1));
- noise[i] /= END_STARTUP_SHORT;
- }
- }
- // Compute average signal during END_STARTUP_LONG time:
- // used to normalize spectral difference measure.
- if (self->blockInd < END_STARTUP_LONG) {
- self->featureData[5] *= self->blockInd;
- self->featureData[5] += signalEnergy;
- self->featureData[5] /= (self->blockInd + 1);
- }
-
- // Post and prior SNR needed for SpeechNoiseProb.
- ComputeSnr(self, magn, noise, snrLocPrior, snrLocPost);
-
- FeatureUpdate(self, magn, updateParsFlag);
- SpeechNoiseProb(self, self->speechProb, snrLocPrior, snrLocPost);
- UpdateNoiseEstimate(self, magn, snrLocPrior, snrLocPost, noise);
-
- // Keep track of noise spectrum for next frame.
- memcpy(self->noise, noise, sizeof(*noise) * self->magnLen);
- memcpy(self->magnPrevAnalyze, magn, sizeof(*magn) * self->magnLen);
-}
-
-void WebRtcNs_ProcessCore(NoiseSuppressionC* self,
- const float* const* speechFrame,
- size_t num_bands,
- float* const* outFrame) {
- // Main routine for noise reduction.
- int flagHB = 0;
- size_t i, j;
-
- float energy1, energy2, gain, factor, factor1, factor2;
- float fout[BLOCKL_MAX];
- float winData[ANAL_BLOCKL_MAX];
- float magn[HALF_ANAL_BLOCKL];
- float theFilter[HALF_ANAL_BLOCKL], theFilterTmp[HALF_ANAL_BLOCKL];
- float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL];
-
- // SWB variables.
- int deltaBweHB = 1;
- int deltaGainHB = 1;
- float decayBweHB = 1.0;
- float gainMapParHB = 1.0;
- float gainTimeDomainHB = 1.0;
- float avgProbSpeechHB, avgProbSpeechHBTmp, avgFilterGainHB, gainModHB;
- float sumMagnAnalyze, sumMagnProcess;
-
- // Check that initiation has been done.
- assert(self->initFlag == 1);
- assert((num_bands - 1) <= NUM_HIGH_BANDS_MAX);
-
- const float* const* speechFrameHB = NULL;
- float* const* outFrameHB = NULL;
- size_t num_high_bands = 0;
- if (num_bands > 1) {
- speechFrameHB = &speechFrame[1];
- outFrameHB = &outFrame[1];
- num_high_bands = num_bands - 1;
- flagHB = 1;
- // Range for averaging low band quantities for H band gain.
- deltaBweHB = (int)self->magnLen / 4;
- deltaGainHB = deltaBweHB;
- }
-
- // Update analysis buffer for L band.
- UpdateBuffer(speechFrame[0], self->blockLen, self->anaLen, self->dataBuf);
-
- if (flagHB == 1) {
- // Update analysis buffer for H bands.
- for (i = 0; i < num_high_bands; ++i) {
- UpdateBuffer(speechFrameHB[i],
- self->blockLen,
- self->anaLen,
- self->dataBufHB[i]);
- }
- }
-
- Windowing(self->window, self->dataBuf, self->anaLen, winData);
- energy1 = Energy(winData, self->anaLen);
- if (energy1 == 0.0) {
- // Synthesize the special case of zero input.
- // Read out fully processed segment.
- for (i = self->windShift; i < self->blockLen + self->windShift; i++) {
- fout[i - self->windShift] = self->syntBuf[i];
- }
- // Update synthesis buffer.
- UpdateBuffer(NULL, self->blockLen, self->anaLen, self->syntBuf);
-
- for (i = 0; i < self->blockLen; ++i)
- outFrame[0][i] =
- WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, fout[i], WEBRTC_SPL_WORD16_MIN);
-
- // For time-domain gain of HB.
- if (flagHB == 1) {
- for (i = 0; i < num_high_bands; ++i) {
- for (j = 0; j < self->blockLen; ++j) {
- outFrameHB[i][j] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
- self->dataBufHB[i][j],
- WEBRTC_SPL_WORD16_MIN);
- }
- }
- }
-
- return;
- }
-
- FFT(self, winData, self->anaLen, self->magnLen, real, imag, magn);
-
- if (self->blockInd < END_STARTUP_SHORT) {
- for (i = 0; i < self->magnLen; i++) {
- self->initMagnEst[i] += magn[i];
- }
- }
-
- ComputeDdBasedWienerFilter(self, magn, theFilter);
-
- for (i = 0; i < self->magnLen; i++) {
- // Flooring bottom.
- if (theFilter[i] < self->denoiseBound) {
- theFilter[i] = self->denoiseBound;
- }
- // Flooring top.
- if (theFilter[i] > 1.f) {
- theFilter[i] = 1.f;
- }
- if (self->blockInd < END_STARTUP_SHORT) {
- theFilterTmp[i] =
- (self->initMagnEst[i] - self->overdrive * self->parametricNoise[i]);
- theFilterTmp[i] /= (self->initMagnEst[i] + 0.0001f);
- // Flooring bottom.
- if (theFilterTmp[i] < self->denoiseBound) {
- theFilterTmp[i] = self->denoiseBound;
- }
- // Flooring top.
- if (theFilterTmp[i] > 1.f) {
- theFilterTmp[i] = 1.f;
- }
- // Weight the two suppression filters.
- theFilter[i] *= (self->blockInd);
- theFilterTmp[i] *= (END_STARTUP_SHORT - self->blockInd);
- theFilter[i] += theFilterTmp[i];
- theFilter[i] /= (END_STARTUP_SHORT);
- }
-
- self->smooth[i] = theFilter[i];
- real[i] *= self->smooth[i];
- imag[i] *= self->smooth[i];
- }
- // Keep track of |magn| spectrum for next frame.
- memcpy(self->magnPrevProcess, magn, sizeof(*magn) * self->magnLen);
- memcpy(self->noisePrev, self->noise, sizeof(self->noise[0]) * self->magnLen);
- // Back to time domain.
- IFFT(self, real, imag, self->magnLen, self->anaLen, winData);
-
- // Scale factor: only do it after END_STARTUP_LONG time.
- factor = 1.f;
- if (self->gainmap == 1 && self->blockInd > END_STARTUP_LONG) {
- factor1 = 1.f;
- factor2 = 1.f;
-
- energy2 = Energy(winData, self->anaLen);
- gain = (float)sqrt(energy2 / (energy1 + 1.f));
-
- // Scaling for new version.
- if (gain > B_LIM) {
- factor1 = 1.f + 1.3f * (gain - B_LIM);
- if (gain * factor1 > 1.f) {
- factor1 = 1.f / gain;
- }
- }
- if (gain < B_LIM) {
- // Don't reduce scale too much for pause regions:
- // attenuation here should be controlled by flooring.
- if (gain <= self->denoiseBound) {
- gain = self->denoiseBound;
- }
- factor2 = 1.f - 0.3f * (B_LIM - gain);
- }
- // Combine both scales with speech/noise prob:
- // note prior (priorSpeechProb) is not frequency dependent.
- factor = self->priorSpeechProb * factor1 +
- (1.f - self->priorSpeechProb) * factor2;
- } // Out of self->gainmap == 1.
-
- Windowing(self->window, winData, self->anaLen, winData);
-
- // Synthesis.
- for (i = 0; i < self->anaLen; i++) {
- self->syntBuf[i] += factor * winData[i];
- }
- // Read out fully processed segment.
- for (i = self->windShift; i < self->blockLen + self->windShift; i++) {
- fout[i - self->windShift] = self->syntBuf[i];
- }
- // Update synthesis buffer.
- UpdateBuffer(NULL, self->blockLen, self->anaLen, self->syntBuf);
-
- for (i = 0; i < self->blockLen; ++i)
- outFrame[0][i] =
- WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, fout[i], WEBRTC_SPL_WORD16_MIN);
-
- // For time-domain gain of HB.
- if (flagHB == 1) {
- // Average speech prob from low band.
- // Average over second half (i.e., 4->8kHz) of frequencies spectrum.
- avgProbSpeechHB = 0.0;
- for (i = self->magnLen - deltaBweHB - 1; i < self->magnLen - 1; i++) {
- avgProbSpeechHB += self->speechProb[i];
- }
- avgProbSpeechHB = avgProbSpeechHB / ((float)deltaBweHB);
- // If the speech was suppressed by a component between Analyze and
- // Process, for example the AEC, then it should not be considered speech
- // for high band suppression purposes.
- sumMagnAnalyze = 0;
- sumMagnProcess = 0;
- for (i = 0; i < self->magnLen; ++i) {
- sumMagnAnalyze += self->magnPrevAnalyze[i];
- sumMagnProcess += self->magnPrevProcess[i];
- }
- avgProbSpeechHB *= sumMagnProcess / sumMagnAnalyze;
- // Average filter gain from low band.
- // Average over second half (i.e., 4->8kHz) of frequencies spectrum.
- avgFilterGainHB = 0.0;
- for (i = self->magnLen - deltaGainHB - 1; i < self->magnLen - 1; i++) {
- avgFilterGainHB += self->smooth[i];
- }
- avgFilterGainHB = avgFilterGainHB / ((float)(deltaGainHB));
- avgProbSpeechHBTmp = 2.f * avgProbSpeechHB - 1.f;
- // Gain based on speech probability.
- gainModHB = 0.5f * (1.f + (float)tanh(gainMapParHB * avgProbSpeechHBTmp));
- // Combine gain with low band gain.
- gainTimeDomainHB = 0.5f * gainModHB + 0.5f * avgFilterGainHB;
- if (avgProbSpeechHB >= 0.5f) {
- gainTimeDomainHB = 0.25f * gainModHB + 0.75f * avgFilterGainHB;
- }
- gainTimeDomainHB = gainTimeDomainHB * decayBweHB;
- // Make sure gain is within flooring range.
- // Flooring bottom.
- if (gainTimeDomainHB < self->denoiseBound) {
- gainTimeDomainHB = self->denoiseBound;
- }
- // Flooring top.
- if (gainTimeDomainHB > 1.f) {
- gainTimeDomainHB = 1.f;
- }
- // Apply gain.
- for (i = 0; i < num_high_bands; ++i) {
- for (j = 0; j < self->blockLen; j++) {
- outFrameHB[i][j] =
- WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
- gainTimeDomainHB * self->dataBufHB[i][j],
- WEBRTC_SPL_WORD16_MIN);
- }
- }
- } // End of H band gain computation.
-}
diff --git a/webrtc/modules/audio_processing/ns/ns_core.h b/webrtc/modules/audio_processing/ns/ns_core.h
deleted file mode 100644
index aba1c46..0000000
--- a/webrtc/modules/audio_processing/ns/ns_core.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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 WEBRTC_MODULES_AUDIO_PROCESSING_NS_NS_CORE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_NS_CORE_H_
-
-#include "webrtc/modules/audio_processing/ns/defines.h"
-
-typedef struct NSParaExtract_ {
- // Bin size of histogram.
- float binSizeLrt;
- float binSizeSpecFlat;
- float binSizeSpecDiff;
- // Range of histogram over which LRT threshold is computed.
- float rangeAvgHistLrt;
- // Scale parameters: multiply dominant peaks of the histograms by scale factor
- // to obtain thresholds for prior model.
- float factor1ModelPars; // For LRT and spectral difference.
- float factor2ModelPars; // For spectral_flatness: used when noise is flatter
- // than speech.
- // Peak limit for spectral flatness (varies between 0 and 1).
- float thresPosSpecFlat;
- // Limit on spacing of two highest peaks in histogram: spacing determined by
- // bin size.
- float limitPeakSpacingSpecFlat;
- float limitPeakSpacingSpecDiff;
- // Limit on relevance of second peak.
- float limitPeakWeightsSpecFlat;
- float limitPeakWeightsSpecDiff;
- // Limit on fluctuation of LRT feature.
- float thresFluctLrt;
- // Limit on the max and min values for the feature thresholds.
- float maxLrt;
- float minLrt;
- float maxSpecFlat;
- float minSpecFlat;
- float maxSpecDiff;
- float minSpecDiff;
- // Criteria of weight of histogram peak to accept/reject feature.
- int thresWeightSpecFlat;
- int thresWeightSpecDiff;
-
-} NSParaExtract;
-
-typedef struct NoiseSuppressionC_ {
- uint32_t fs;
- size_t blockLen;
- size_t windShift;
- size_t anaLen;
- size_t magnLen;
- int aggrMode;
- const float* window;
- float analyzeBuf[ANAL_BLOCKL_MAX];
- float dataBuf[ANAL_BLOCKL_MAX];
- float syntBuf[ANAL_BLOCKL_MAX];
-
- int initFlag;
- // Parameters for quantile noise estimation.
- float density[SIMULT * HALF_ANAL_BLOCKL];
- float lquantile[SIMULT * HALF_ANAL_BLOCKL];
- float quantile[HALF_ANAL_BLOCKL];
- int counter[SIMULT];
- int updates;
- // Parameters for Wiener filter.
- float smooth[HALF_ANAL_BLOCKL];
- float overdrive;
- float denoiseBound;
- int gainmap;
- // FFT work arrays.
- size_t ip[IP_LENGTH];
- float wfft[W_LENGTH];
-
- // Parameters for new method: some not needed, will reduce/cleanup later.
- int32_t blockInd; // Frame index counter.
- int modelUpdatePars[4]; // Parameters for updating or estimating.
- // Thresholds/weights for prior model.
- float priorModelPars[7]; // Parameters for prior model.
- float noise[HALF_ANAL_BLOCKL]; // Noise spectrum from current frame.
- float noisePrev[HALF_ANAL_BLOCKL]; // Noise spectrum from previous frame.
- // Magnitude spectrum of previous analyze frame.
- float magnPrevAnalyze[HALF_ANAL_BLOCKL];
- // Magnitude spectrum of previous process frame.
- float magnPrevProcess[HALF_ANAL_BLOCKL];
- float logLrtTimeAvg[HALF_ANAL_BLOCKL]; // Log LRT factor with time-smoothing.
- float priorSpeechProb; // Prior speech/noise probability.
- float featureData[7];
- // Conservative noise spectrum estimate.
- float magnAvgPause[HALF_ANAL_BLOCKL];
- float signalEnergy; // Energy of |magn|.
- float sumMagn;
- float whiteNoiseLevel; // Initial noise estimate.
- float initMagnEst[HALF_ANAL_BLOCKL]; // Initial magnitude spectrum estimate.
- float pinkNoiseNumerator; // Pink noise parameter: numerator.
- float pinkNoiseExp; // Pink noise parameter: power of frequencies.
- float parametricNoise[HALF_ANAL_BLOCKL];
- // Parameters for feature extraction.
- NSParaExtract featureExtractionParams;
- // Histograms for parameter estimation.
- int histLrt[HIST_PAR_EST];
- int histSpecFlat[HIST_PAR_EST];
- int histSpecDiff[HIST_PAR_EST];
- // Quantities for high band estimate.
- float speechProb[HALF_ANAL_BLOCKL]; // Final speech/noise prob: prior + LRT.
- // Buffering data for HB.
- float dataBufHB[NUM_HIGH_BANDS_MAX][ANAL_BLOCKL_MAX];
-
-} NoiseSuppressionC;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/****************************************************************************
- * WebRtcNs_InitCore(...)
- *
- * This function initializes a noise suppression instance
- *
- * Input:
- * - self : Instance that should be initialized
- * - fs : Sampling frequency
- *
- * Output:
- * - self : Initialized instance
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int WebRtcNs_InitCore(NoiseSuppressionC* self, uint32_t fs);
-
-/****************************************************************************
- * WebRtcNs_set_policy_core(...)
- *
- * This changes the aggressiveness of the noise suppression method.
- *
- * Input:
- * - self : Instance that should be initialized
- * - mode : 0: Mild (6dB), 1: Medium (10dB), 2: Aggressive (15dB)
- *
- * Output:
- * - self : Initialized instance
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int WebRtcNs_set_policy_core(NoiseSuppressionC* self, int mode);
-
-/****************************************************************************
- * WebRtcNs_AnalyzeCore
- *
- * Estimate the background noise.
- *
- * Input:
- * - self : Instance that should be initialized
- * - speechFrame : Input speech frame for lower band
- *
- * Output:
- * - self : Updated instance
- */
-void WebRtcNs_AnalyzeCore(NoiseSuppressionC* self, const float* speechFrame);
-
-/****************************************************************************
- * WebRtcNs_ProcessCore
- *
- * Do noise suppression.
- *
- * Input:
- * - self : Instance that should be initialized
- * - inFrame : Input speech frame for each band
- * - num_bands : Number of bands
- *
- * Output:
- * - self : Updated instance
- * - outFrame : Output speech frame for each band
- */
-void WebRtcNs_ProcessCore(NoiseSuppressionC* self,
- const float* const* inFrame,
- size_t num_bands,
- float* const* outFrame);
-
-#ifdef __cplusplus
-}
-#endif
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_NS_CORE_H_
diff --git a/webrtc/modules/audio_processing/ns/ns_fft.cc b/webrtc/modules/audio_processing/ns/ns_fft.cc
new file mode 100644
index 0000000..264c469
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/ns_fft.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/ns_fft.h"
+
+#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
+
+namespace webrtc {
+
+NrFft::NrFft() : bit_reversal_state_(kFftSize / 2), tables_(kFftSize / 2) {
+ // Initialize WebRtc_rdt (setting (bit_reversal_state_[0] to 0 triggers
+ // initialization)
+ bit_reversal_state_[0] = 0.f;
+ std::array<float, kFftSize> tmp_buffer;
+ tmp_buffer.fill(0.f);
+ WebRtc_rdft(kFftSize, 1, tmp_buffer.data(), bit_reversal_state_.data(),
+ tables_.data());
+}
+
+void NrFft::Fft(rtc::ArrayView<float, kFftSize> time_data,
+ rtc::ArrayView<float, kFftSize> real,
+ rtc::ArrayView<float, kFftSize> imag) {
+ WebRtc_rdft(kFftSize, 1, time_data.data(), bit_reversal_state_.data(),
+ tables_.data());
+
+ imag[0] = 0;
+ real[0] = time_data[0];
+
+ imag[kFftSizeBy2Plus1 - 1] = 0;
+ real[kFftSizeBy2Plus1 - 1] = time_data[1];
+
+ for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) {
+ real[i] = time_data[2 * i];
+ imag[i] = time_data[2 * i + 1];
+ }
+}
+
+void NrFft::Ifft(rtc::ArrayView<const float> real,
+ rtc::ArrayView<const float> imag,
+ rtc::ArrayView<float> time_data) {
+ time_data[0] = real[0];
+ time_data[1] = real[kFftSizeBy2Plus1 - 1];
+ for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) {
+ time_data[2 * i] = real[i];
+ time_data[2 * i + 1] = imag[i];
+ }
+ WebRtc_rdft(kFftSize, -1, time_data.data(), bit_reversal_state_.data(),
+ tables_.data());
+
+ // Scale the output
+ constexpr float kScaling = 2.f / kFftSize;
+ for (float& d : time_data) {
+ d *= kScaling;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/ns_fft.h b/webrtc/modules/audio_processing/ns/ns_fft.h
new file mode 100644
index 0000000..539251e
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/ns_fft.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_
+#define MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+
+namespace webrtc {
+
+// Wrapper class providing 256 point FFT functionality.
+class NrFft {
+ public:
+ NrFft();
+ NrFft(const NrFft&) = delete;
+ NrFft& operator=(const NrFft&) = delete;
+
+ // Transforms the signal from time to frequency domain.
+ void Fft(rtc::ArrayView<float, kFftSize> time_data,
+ rtc::ArrayView<float, kFftSize> real,
+ rtc::ArrayView<float, kFftSize> imag);
+
+ // Transforms the signal from frequency to time domain.
+ void Ifft(rtc::ArrayView<const float> real,
+ rtc::ArrayView<const float> imag,
+ rtc::ArrayView<float> time_data);
+
+ private:
+ std::vector<size_t> bit_reversal_state_;
+ std::vector<float> tables_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_
diff --git a/webrtc/modules/audio_processing/ns/nsx_core.c b/webrtc/modules/audio_processing/ns/nsx_core.c
deleted file mode 100644
index 7144579..0000000
--- a/webrtc/modules/audio_processing/ns/nsx_core.c
+++ /dev/null
@@ -1,2112 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/ns/include/noise_suppression_x.h"
-
-#include <assert.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "webrtc/common_audio/signal_processing/include/real_fft.h"
-#include "webrtc/modules/audio_processing/ns/nsx_core.h"
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
-
-#if (defined WEBRTC_DETECT_NEON || defined WEBRTC_HAS_NEON)
-/* Tables are defined in ARM assembly files. */
-extern const int16_t WebRtcNsx_kLogTable[9];
-extern const int16_t WebRtcNsx_kCounterDiv[201];
-extern const int16_t WebRtcNsx_kLogTableFrac[256];
-#else
-static const int16_t WebRtcNsx_kLogTable[9] = {
- 0, 177, 355, 532, 710, 887, 1065, 1242, 1420
-};
-
-static const int16_t WebRtcNsx_kCounterDiv[201] = {
- 32767, 16384, 10923, 8192, 6554, 5461, 4681, 4096, 3641, 3277, 2979, 2731,
- 2521, 2341, 2185, 2048, 1928, 1820, 1725, 1638, 1560, 1489, 1425, 1365, 1311,
- 1260, 1214, 1170, 1130, 1092, 1057, 1024, 993, 964, 936, 910, 886, 862, 840,
- 819, 799, 780, 762, 745, 728, 712, 697, 683, 669, 655, 643, 630, 618, 607,
- 596, 585, 575, 565, 555, 546, 537, 529, 520, 512, 504, 496, 489, 482, 475,
- 468, 462, 455, 449, 443, 437, 431, 426, 420, 415, 410, 405, 400, 395, 390,
- 386, 381, 377, 372, 368, 364, 360, 356, 352, 349, 345, 341, 338, 334, 331,
- 328, 324, 321, 318, 315, 312, 309, 306, 303, 301, 298, 295, 293, 290, 287,
- 285, 282, 280, 278, 275, 273, 271, 269, 266, 264, 262, 260, 258, 256, 254,
- 252, 250, 248, 246, 245, 243, 241, 239, 237, 236, 234, 232, 231, 229, 228,
- 226, 224, 223, 221, 220, 218, 217, 216, 214, 213, 211, 210, 209, 207, 206,
- 205, 204, 202, 201, 200, 199, 197, 196, 195, 194, 193, 192, 191, 189, 188,
- 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173,
- 172, 172, 171, 170, 169, 168, 167, 166, 165, 165, 164, 163
-};
-
-static const int16_t WebRtcNsx_kLogTableFrac[256] = {
- 0, 1, 3, 4, 6, 7, 9, 10, 11, 13, 14, 16, 17, 18, 20, 21,
- 22, 24, 25, 26, 28, 29, 30, 32, 33, 34, 36, 37, 38, 40, 41, 42,
- 44, 45, 46, 47, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62,
- 63, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81,
- 82, 84, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99,
- 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116,
- 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131,
- 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
- 147, 148, 149, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160,
- 161, 162, 163, 164, 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 174,
- 175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 184, 185, 185, 186, 187,
- 188, 189, 190, 191, 192, 192, 193, 194, 195, 196, 197, 198, 198, 199, 200,
- 201, 202, 203, 203, 204, 205, 206, 207, 208, 208, 209, 210, 211, 212, 212,
- 213, 214, 215, 216, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
- 225, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236,
- 237, 238, 238, 239, 240, 241, 241, 242, 243, 244, 244, 245, 246, 247, 247,
- 248, 249, 249, 250, 251, 252, 252, 253, 254, 255, 255
-};
-#endif // WEBRTC_DETECT_NEON || WEBRTC_HAS_NEON
-
-// Skip first frequency bins during estimation. (0 <= value < 64)
-static const size_t kStartBand = 5;
-
-// hybrib Hanning & flat window
-static const int16_t kBlocks80w128x[128] = {
- 0, 536, 1072, 1606, 2139, 2669, 3196, 3720, 4240, 4756, 5266,
- 5771, 6270, 6762, 7246, 7723, 8192, 8652, 9102, 9543, 9974, 10394,
- 10803, 11200, 11585, 11958, 12318, 12665, 12998, 13318, 13623, 13913, 14189,
- 14449, 14694, 14924, 15137, 15334, 15515, 15679, 15826, 15956, 16069, 16165,
- 16244, 16305, 16349, 16375, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16375, 16349, 16305, 16244, 16165, 16069, 15956,
- 15826, 15679, 15515, 15334, 15137, 14924, 14694, 14449, 14189, 13913, 13623,
- 13318, 12998, 12665, 12318, 11958, 11585, 11200, 10803, 10394, 9974, 9543,
- 9102, 8652, 8192, 7723, 7246, 6762, 6270, 5771, 5266, 4756, 4240,
- 3720, 3196, 2669, 2139, 1606, 1072, 536
-};
-
-// hybrib Hanning & flat window
-static const int16_t kBlocks160w256x[256] = {
- 0, 268, 536, 804, 1072, 1339, 1606, 1872,
- 2139, 2404, 2669, 2933, 3196, 3459, 3720, 3981,
- 4240, 4499, 4756, 5012, 5266, 5520, 5771, 6021,
- 6270, 6517, 6762, 7005, 7246, 7486, 7723, 7959,
- 8192, 8423, 8652, 8878, 9102, 9324, 9543, 9760,
- 9974, 10185, 10394, 10600, 10803, 11003, 11200, 11394,
- 11585, 11773, 11958, 12140, 12318, 12493, 12665, 12833,
- 12998, 13160, 13318, 13472, 13623, 13770, 13913, 14053,
- 14189, 14321, 14449, 14574, 14694, 14811, 14924, 15032,
- 15137, 15237, 15334, 15426, 15515, 15599, 15679, 15754,
- 15826, 15893, 15956, 16015, 16069, 16119, 16165, 16207,
- 16244, 16277, 16305, 16329, 16349, 16364, 16375, 16382,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
- 16384, 16382, 16375, 16364, 16349, 16329, 16305, 16277,
- 16244, 16207, 16165, 16119, 16069, 16015, 15956, 15893,
- 15826, 15754, 15679, 15599, 15515, 15426, 15334, 15237,
- 15137, 15032, 14924, 14811, 14694, 14574, 14449, 14321,
- 14189, 14053, 13913, 13770, 13623, 13472, 13318, 13160,
- 12998, 12833, 12665, 12493, 12318, 12140, 11958, 11773,
- 11585, 11394, 11200, 11003, 10803, 10600, 10394, 10185,
- 9974, 9760, 9543, 9324, 9102, 8878, 8652, 8423,
- 8192, 7959, 7723, 7486, 7246, 7005, 6762, 6517,
- 6270, 6021, 5771, 5520, 5266, 5012, 4756, 4499,
- 4240, 3981, 3720, 3459, 3196, 2933, 2669, 2404,
- 2139, 1872, 1606, 1339, 1072, 804, 536, 268
-};
-
-// Gain factor1 table: Input value in Q8 and output value in Q13
-// original floating point code
-// if (gain > blim) {
-// factor1 = 1.0 + 1.3 * (gain - blim);
-// if (gain * factor1 > 1.0) {
-// factor1 = 1.0 / gain;
-// }
-// } else {
-// factor1 = 1.0;
-// }
-static const int16_t kFactor1Table[257] = {
- 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8233, 8274, 8315, 8355, 8396, 8436, 8475, 8515, 8554, 8592, 8631, 8669,
- 8707, 8745, 8783, 8820, 8857, 8894, 8931, 8967, 9003, 9039, 9075, 9111, 9146, 9181,
- 9216, 9251, 9286, 9320, 9354, 9388, 9422, 9456, 9489, 9523, 9556, 9589, 9622, 9655,
- 9687, 9719, 9752, 9784, 9816, 9848, 9879, 9911, 9942, 9973, 10004, 10035, 10066,
- 10097, 10128, 10158, 10188, 10218, 10249, 10279, 10308, 10338, 10368, 10397, 10426,
- 10456, 10485, 10514, 10543, 10572, 10600, 10629, 10657, 10686, 10714, 10742, 10770,
- 10798, 10826, 10854, 10882, 10847, 10810, 10774, 10737, 10701, 10666, 10631, 10596,
- 10562, 10527, 10494, 10460, 10427, 10394, 10362, 10329, 10297, 10266, 10235, 10203,
- 10173, 10142, 10112, 10082, 10052, 10023, 9994, 9965, 9936, 9908, 9879, 9851, 9824,
- 9796, 9769, 9742, 9715, 9689, 9662, 9636, 9610, 9584, 9559, 9534, 9508, 9484, 9459,
- 9434, 9410, 9386, 9362, 9338, 9314, 9291, 9268, 9245, 9222, 9199, 9176, 9154, 9132,
- 9110, 9088, 9066, 9044, 9023, 9002, 8980, 8959, 8939, 8918, 8897, 8877, 8857, 8836,
- 8816, 8796, 8777, 8757, 8738, 8718, 8699, 8680, 8661, 8642, 8623, 8605, 8586, 8568,
- 8550, 8532, 8514, 8496, 8478, 8460, 8443, 8425, 8408, 8391, 8373, 8356, 8339, 8323,
- 8306, 8289, 8273, 8256, 8240, 8224, 8208, 8192
-};
-
-// For Factor2 tables
-// original floating point code
-// if (gain > blim) {
-// factor2 = 1.0;
-// } else {
-// factor2 = 1.0 - 0.3 * (blim - gain);
-// if (gain <= inst->denoiseBound) {
-// factor2 = 1.0 - 0.3 * (blim - inst->denoiseBound);
-// }
-// }
-//
-// Gain factor table: Input value in Q8 and output value in Q13
-static const int16_t kFactor2Aggressiveness1[257] = {
- 7577, 7577, 7577, 7577, 7577, 7577,
- 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7596, 7614, 7632,
- 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
- 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
- 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
- 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
-};
-
-// Gain factor table: Input value in Q8 and output value in Q13
-static const int16_t kFactor2Aggressiveness2[257] = {
- 7270, 7270, 7270, 7270, 7270, 7306,
- 7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632,
- 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
- 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
- 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
- 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
-};
-
-// Gain factor table: Input value in Q8 and output value in Q13
-static const int16_t kFactor2Aggressiveness3[257] = {
- 7184, 7184, 7184, 7229, 7270, 7306,
- 7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632,
- 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
- 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
- 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
- 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
- 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
-};
-
-// sum of log2(i) from table index to inst->anaLen2 in Q5
-// Note that the first table value is invalid, since log2(0) = -infinity
-static const int16_t kSumLogIndex[66] = {
- 0, 22917, 22917, 22885, 22834, 22770, 22696, 22613,
- 22524, 22428, 22326, 22220, 22109, 21994, 21876, 21754,
- 21629, 21501, 21370, 21237, 21101, 20963, 20822, 20679,
- 20535, 20388, 20239, 20089, 19937, 19783, 19628, 19470,
- 19312, 19152, 18991, 18828, 18664, 18498, 18331, 18164,
- 17994, 17824, 17653, 17480, 17306, 17132, 16956, 16779,
- 16602, 16423, 16243, 16063, 15881, 15699, 15515, 15331,
- 15146, 14960, 14774, 14586, 14398, 14209, 14019, 13829,
- 13637, 13445
-};
-
-// sum of log2(i)^2 from table index to inst->anaLen2 in Q2
-// Note that the first table value is invalid, since log2(0) = -infinity
-static const int16_t kSumSquareLogIndex[66] = {
- 0, 16959, 16959, 16955, 16945, 16929, 16908, 16881,
- 16850, 16814, 16773, 16729, 16681, 16630, 16575, 16517,
- 16456, 16392, 16325, 16256, 16184, 16109, 16032, 15952,
- 15870, 15786, 15700, 15612, 15521, 15429, 15334, 15238,
- 15140, 15040, 14938, 14834, 14729, 14622, 14514, 14404,
- 14292, 14179, 14064, 13947, 13830, 13710, 13590, 13468,
- 13344, 13220, 13094, 12966, 12837, 12707, 12576, 12444,
- 12310, 12175, 12039, 11902, 11763, 11624, 11483, 11341,
- 11198, 11054
-};
-
-// log2(table index) in Q12
-// Note that the first table value is invalid, since log2(0) = -infinity
-static const int16_t kLogIndex[129] = {
- 0, 0, 4096, 6492, 8192, 9511, 10588, 11499,
- 12288, 12984, 13607, 14170, 14684, 15157, 15595, 16003,
- 16384, 16742, 17080, 17400, 17703, 17991, 18266, 18529,
- 18780, 19021, 19253, 19476, 19691, 19898, 20099, 20292,
- 20480, 20662, 20838, 21010, 21176, 21338, 21496, 21649,
- 21799, 21945, 22087, 22226, 22362, 22495, 22625, 22752,
- 22876, 22998, 23117, 23234, 23349, 23462, 23572, 23680,
- 23787, 23892, 23994, 24095, 24195, 24292, 24388, 24483,
- 24576, 24668, 24758, 24847, 24934, 25021, 25106, 25189,
- 25272, 25354, 25434, 25513, 25592, 25669, 25745, 25820,
- 25895, 25968, 26041, 26112, 26183, 26253, 26322, 26390,
- 26458, 26525, 26591, 26656, 26721, 26784, 26848, 26910,
- 26972, 27033, 27094, 27154, 27213, 27272, 27330, 27388,
- 27445, 27502, 27558, 27613, 27668, 27722, 27776, 27830,
- 27883, 27935, 27988, 28039, 28090, 28141, 28191, 28241,
- 28291, 28340, 28388, 28437, 28484, 28532, 28579, 28626,
- 28672
-};
-
-// determinant of estimation matrix in Q0 corresponding to the log2 tables above
-// Note that the first table value is invalid, since log2(0) = -infinity
-static const int16_t kDeterminantEstMatrix[66] = {
- 0, 29814, 25574, 22640, 20351, 18469, 16873, 15491,
- 14277, 13199, 12233, 11362, 10571, 9851, 9192, 8587,
- 8030, 7515, 7038, 6596, 6186, 5804, 5448, 5115,
- 4805, 4514, 4242, 3988, 3749, 3524, 3314, 3116,
- 2930, 2755, 2590, 2435, 2289, 2152, 2022, 1900,
- 1785, 1677, 1575, 1478, 1388, 1302, 1221, 1145,
- 1073, 1005, 942, 881, 825, 771, 721, 674,
- 629, 587, 547, 510, 475, 442, 411, 382,
- 355, 330
-};
-
-// Update the noise estimation information.
-static void UpdateNoiseEstimate(NoiseSuppressionFixedC* inst, int offset) {
- int32_t tmp32no1 = 0;
- int32_t tmp32no2 = 0;
- int16_t tmp16 = 0;
- const int16_t kExp2Const = 11819; // Q13
-
- size_t i = 0;
-
- tmp16 = WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset,
- inst->magnLen);
- // Guarantee a Q-domain as high as possible and still fit in int16
- inst->qNoise = 14 - (int) WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- kExp2Const, tmp16, 21);
- for (i = 0; i < inst->magnLen; i++) {
- // inst->quantile[i]=exp(inst->lquantile[offset+i]);
- // in Q21
- tmp32no2 = kExp2Const * inst->noiseEstLogQuantile[offset + i];
- tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac
- tmp16 = (int16_t)(tmp32no2 >> 21);
- tmp16 -= 21;// shift 21 to get result in Q0
- tmp16 += (int16_t) inst->qNoise; //shift to get result in Q(qNoise)
- if (tmp16 < 0) {
- tmp32no1 >>= -tmp16;
- } else {
- tmp32no1 <<= tmp16;
- }
- inst->noiseEstQuantile[i] = WebRtcSpl_SatW32ToW16(tmp32no1);
- }
-}
-
-// Noise Estimation
-static void NoiseEstimationC(NoiseSuppressionFixedC* inst,
- uint16_t* magn,
- uint32_t* noise,
- int16_t* q_noise) {
- int16_t lmagn[HALF_ANAL_BLOCKL], counter, countDiv;
- int16_t countProd, delta, zeros, frac;
- int16_t log2, tabind, logval, tmp16, tmp16no1, tmp16no2;
- const int16_t log2_const = 22713; // Q15
- const int16_t width_factor = 21845;
-
- size_t i, s, offset;
-
- tabind = inst->stages - inst->normData;
- assert(tabind < 9);
- assert(tabind > -9);
- if (tabind < 0) {
- logval = -WebRtcNsx_kLogTable[-tabind];
- } else {
- logval = WebRtcNsx_kLogTable[tabind];
- }
-
- // lmagn(i)=log(magn(i))=log(2)*log2(magn(i))
- // magn is in Q(-stages), and the real lmagn values are:
- // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages)
- // lmagn in Q8
- for (i = 0; i < inst->magnLen; i++) {
- if (magn[i]) {
- zeros = WebRtcSpl_NormU32((uint32_t)magn[i]);
- frac = (int16_t)((((uint32_t)magn[i] << zeros)
- & 0x7FFFFFFF) >> 23);
- // log2(magn(i))
- assert(frac < 256);
- log2 = (int16_t)(((31 - zeros) << 8)
- + WebRtcNsx_kLogTableFrac[frac]);
- // log2(magn(i))*log(2)
- lmagn[i] = (int16_t)((log2 * log2_const) >> 15);
- // + log(2^stages)
- lmagn[i] += logval;
- } else {
- lmagn[i] = logval;//0;
- }
- }
-
- // loop over simultaneous estimates
- for (s = 0; s < SIMULT; s++) {
- offset = s * inst->magnLen;
-
- // Get counter values from state
- counter = inst->noiseEstCounter[s];
- assert(counter < 201);
- countDiv = WebRtcNsx_kCounterDiv[counter];
- countProd = (int16_t)(counter * countDiv);
-
- // quant_est(...)
- for (i = 0; i < inst->magnLen; i++) {
- // compute delta
- if (inst->noiseEstDensity[offset + i] > 512) {
- // Get the value for delta by shifting intead of dividing.
- int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i]);
- delta = (int16_t)(FACTOR_Q16 >> (14 - factor));
- } else {
- delta = FACTOR_Q7;
- if (inst->blockIndex < END_STARTUP_LONG) {
- // Smaller step size during startup. This prevents from using
- // unrealistic values causing overflow.
- delta = FACTOR_Q7_STARTUP;
- }
- }
-
- // update log quantile estimate
- tmp16 = (int16_t)((delta * countDiv) >> 14);
- if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) {
- // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2
- // CounterDiv=1/(inst->counter[s]+1) in Q15
- tmp16 += 2;
- inst->noiseEstLogQuantile[offset + i] += tmp16 / 4;
- } else {
- tmp16 += 1;
- // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2
- // TODO(bjornv): investigate why we need to truncate twice.
- tmp16no2 = (int16_t)((tmp16 / 2) * 3 / 2);
- inst->noiseEstLogQuantile[offset + i] -= tmp16no2;
- if (inst->noiseEstLogQuantile[offset + i] < logval) {
- // This is the smallest fixed point representation we can
- // have, hence we limit the output.
- inst->noiseEstLogQuantile[offset + i] = logval;
- }
- }
-
- // update density estimate
- if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i])
- < WIDTH_Q8) {
- tmp16no1 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- inst->noiseEstDensity[offset + i], countProd, 15);
- tmp16no2 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- width_factor, countDiv, 15);
- inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2;
- }
- } // end loop over magnitude spectrum
-
- if (counter >= END_STARTUP_LONG) {
- inst->noiseEstCounter[s] = 0;
- if (inst->blockIndex >= END_STARTUP_LONG) {
- UpdateNoiseEstimate(inst, offset);
- }
- }
- inst->noiseEstCounter[s]++;
-
- } // end loop over simultaneous estimates
-
- // Sequentially update the noise during startup
- if (inst->blockIndex < END_STARTUP_LONG) {
- UpdateNoiseEstimate(inst, offset);
- }
-
- for (i = 0; i < inst->magnLen; i++) {
- noise[i] = (uint32_t)(inst->noiseEstQuantile[i]); // Q(qNoise)
- }
- (*q_noise) = (int16_t)inst->qNoise;
-}
-
-// Filter the data in the frequency domain, and create spectrum.
-static void PrepareSpectrumC(NoiseSuppressionFixedC* inst, int16_t* freq_buf) {
- size_t i = 0, j = 0;
-
- for (i = 0; i < inst->magnLen; i++) {
- inst->real[i] = (int16_t)((inst->real[i] *
- (int16_t)(inst->noiseSupFilter[i])) >> 14); // Q(normData-stages)
- inst->imag[i] = (int16_t)((inst->imag[i] *
- (int16_t)(inst->noiseSupFilter[i])) >> 14); // Q(normData-stages)
- }
-
- freq_buf[0] = inst->real[0];
- freq_buf[1] = -inst->imag[0];
- for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
- freq_buf[j] = inst->real[i];
- freq_buf[j + 1] = -inst->imag[i];
- }
- freq_buf[inst->anaLen] = inst->real[inst->anaLen2];
- freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2];
-}
-
-// Denormalize the real-valued signal |in|, the output from inverse FFT.
-static void DenormalizeC(NoiseSuppressionFixedC* inst,
- int16_t* in,
- int factor) {
- size_t i = 0;
- int32_t tmp32 = 0;
- for (i = 0; i < inst->anaLen; i += 1) {
- tmp32 = WEBRTC_SPL_SHIFT_W32((int32_t)in[i],
- factor - inst->normData);
- inst->real[i] = WebRtcSpl_SatW32ToW16(tmp32); // Q0
- }
-}
-
-// For the noise supression process, synthesis, read out fully processed
-// segment, and update synthesis buffer.
-static void SynthesisUpdateC(NoiseSuppressionFixedC* inst,
- int16_t* out_frame,
- int16_t gain_factor) {
- size_t i = 0;
- int16_t tmp16a = 0;
- int16_t tmp16b = 0;
- int32_t tmp32 = 0;
-
- // synthesis
- for (i = 0; i < inst->anaLen; i++) {
- tmp16a = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- inst->window[i], inst->real[i], 14); // Q0, window in Q14
- tmp32 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16a, gain_factor, 13); // Q0
- // Down shift with rounding
- tmp16b = WebRtcSpl_SatW32ToW16(tmp32); // Q0
- inst->synthesisBuffer[i] = WebRtcSpl_AddSatW16(inst->synthesisBuffer[i],
- tmp16b); // Q0
- }
-
- // read out fully processed segment
- for (i = 0; i < inst->blockLen10ms; i++) {
- out_frame[i] = inst->synthesisBuffer[i]; // Q0
- }
-
- // update synthesis buffer
- memcpy(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms,
- (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->synthesisBuffer));
- WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer
- + inst->anaLen - inst->blockLen10ms, inst->blockLen10ms);
-}
-
-// Update analysis buffer for lower band, and window data before FFT.
-static void AnalysisUpdateC(NoiseSuppressionFixedC* inst,
- int16_t* out,
- int16_t* new_speech) {
- size_t i = 0;
-
- // For lower band update analysis buffer.
- memcpy(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms,
- (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->analysisBuffer));
- memcpy(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms, new_speech,
- inst->blockLen10ms * sizeof(*inst->analysisBuffer));
-
- // Window data before FFT.
- for (i = 0; i < inst->anaLen; i++) {
- out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- inst->window[i], inst->analysisBuffer[i], 14); // Q0
- }
-}
-
-// Normalize the real-valued signal |in|, the input to forward FFT.
-static void NormalizeRealBufferC(NoiseSuppressionFixedC* inst,
- const int16_t* in,
- int16_t* out) {
- size_t i = 0;
- assert(inst->normData >= 0);
- for (i = 0; i < inst->anaLen; ++i) {
- out[i] = in[i] << inst->normData; // Q(normData)
- }
-}
-
-// Declare function pointers.
-NoiseEstimation WebRtcNsx_NoiseEstimation;
-PrepareSpectrum WebRtcNsx_PrepareSpectrum;
-SynthesisUpdate WebRtcNsx_SynthesisUpdate;
-AnalysisUpdate WebRtcNsx_AnalysisUpdate;
-Denormalize WebRtcNsx_Denormalize;
-NormalizeRealBuffer WebRtcNsx_NormalizeRealBuffer;
-
-#if (defined WEBRTC_DETECT_NEON || defined WEBRTC_HAS_NEON)
-// Initialize function pointers for ARM Neon platform.
-static void WebRtcNsx_InitNeon(void) {
- WebRtcNsx_NoiseEstimation = WebRtcNsx_NoiseEstimationNeon;
- WebRtcNsx_PrepareSpectrum = WebRtcNsx_PrepareSpectrumNeon;
- WebRtcNsx_SynthesisUpdate = WebRtcNsx_SynthesisUpdateNeon;
- WebRtcNsx_AnalysisUpdate = WebRtcNsx_AnalysisUpdateNeon;
-}
-#endif
-
-#if defined(MIPS32_LE)
-// Initialize function pointers for MIPS platform.
-static void WebRtcNsx_InitMips(void) {
- WebRtcNsx_PrepareSpectrum = WebRtcNsx_PrepareSpectrum_mips;
- WebRtcNsx_SynthesisUpdate = WebRtcNsx_SynthesisUpdate_mips;
- WebRtcNsx_AnalysisUpdate = WebRtcNsx_AnalysisUpdate_mips;
- WebRtcNsx_NormalizeRealBuffer = WebRtcNsx_NormalizeRealBuffer_mips;
-#if defined(MIPS_DSP_R1_LE)
- WebRtcNsx_Denormalize = WebRtcNsx_Denormalize_mips;
-#endif
-}
-#endif
-
-void WebRtcNsx_CalcParametricNoiseEstimate(NoiseSuppressionFixedC* inst,
- int16_t pink_noise_exp_avg,
- int32_t pink_noise_num_avg,
- int freq_index,
- uint32_t* noise_estimate,
- uint32_t* noise_estimate_avg) {
- int32_t tmp32no1 = 0;
- int32_t tmp32no2 = 0;
-
- int16_t int_part = 0;
- int16_t frac_part = 0;
-
- // Use pink noise estimate
- // noise_estimate = 2^(pinkNoiseNumerator + pinkNoiseExp * log2(j))
- assert(freq_index >= 0);
- assert(freq_index < 129);
- tmp32no2 = (pink_noise_exp_avg * kLogIndex[freq_index]) >> 15; // Q11
- tmp32no1 = pink_noise_num_avg - tmp32no2; // Q11
-
- // Calculate output: 2^tmp32no1
- // Output in Q(minNorm-stages)
- tmp32no1 += (inst->minNorm - inst->stages) << 11;
- if (tmp32no1 > 0) {
- int_part = (int16_t)(tmp32no1 >> 11);
- frac_part = (int16_t)(tmp32no1 & 0x000007ff); // Q11
- // Piecewise linear approximation of 'b' in
- // 2^(int_part+frac_part) = 2^int_part * (1 + b)
- // 'b' is given in Q11 and below stored in frac_part.
- if (frac_part >> 10) {
- // Upper fractional part
- tmp32no2 = (2048 - frac_part) * 1244; // Q21
- tmp32no2 = 2048 - (tmp32no2 >> 10);
- } else {
- // Lower fractional part
- tmp32no2 = (frac_part * 804) >> 10;
- }
- // Shift fractional part to Q(minNorm-stages)
- tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, int_part - 11);
- *noise_estimate_avg = (1 << int_part) + (uint32_t)tmp32no2;
- // Scale up to initMagnEst, which is not block averaged
- *noise_estimate = (*noise_estimate_avg) * (uint32_t)(inst->blockIndex + 1);
- }
-}
-
-// Initialize state
-int32_t WebRtcNsx_InitCore(NoiseSuppressionFixedC* inst, uint32_t fs) {
- int i;
-
- //check for valid pointer
- if (inst == NULL) {
- return -1;
- }
- //
-
- // Initialization of struct
- if (fs == 8000 || fs == 16000 || fs == 32000 || fs == 48000) {
- inst->fs = fs;
- } else {
- return -1;
- }
-
- if (fs == 8000) {
- inst->blockLen10ms = 80;
- inst->anaLen = 128;
- inst->stages = 7;
- inst->window = kBlocks80w128x;
- inst->thresholdLogLrt = 131072; //default threshold for LRT feature
- inst->maxLrt = 0x0040000;
- inst->minLrt = 52429;
- } else {
- inst->blockLen10ms = 160;
- inst->anaLen = 256;
- inst->stages = 8;
- inst->window = kBlocks160w256x;
- inst->thresholdLogLrt = 212644; //default threshold for LRT feature
- inst->maxLrt = 0x0080000;
- inst->minLrt = 104858;
- }
- inst->anaLen2 = inst->anaLen / 2;
- inst->magnLen = inst->anaLen2 + 1;
-
- if (inst->real_fft != NULL) {
- WebRtcSpl_FreeRealFFT(inst->real_fft);
- }
- inst->real_fft = WebRtcSpl_CreateRealFFT(inst->stages);
- if (inst->real_fft == NULL) {
- return -1;
- }
-
- WebRtcSpl_ZerosArrayW16(inst->analysisBuffer, ANAL_BLOCKL_MAX);
- WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer, ANAL_BLOCKL_MAX);
-
- // for HB processing
- WebRtcSpl_ZerosArrayW16(inst->dataBufHBFX[0],
- NUM_HIGH_BANDS_MAX * ANAL_BLOCKL_MAX);
- // for quantile noise estimation
- WebRtcSpl_ZerosArrayW16(inst->noiseEstQuantile, HALF_ANAL_BLOCKL);
- for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) {
- inst->noiseEstLogQuantile[i] = 2048; // Q8
- inst->noiseEstDensity[i] = 153; // Q9
- }
- for (i = 0; i < SIMULT; i++) {
- inst->noiseEstCounter[i] = (int16_t)(END_STARTUP_LONG * (i + 1)) / SIMULT;
- }
-
- // Initialize suppression filter with ones
- WebRtcSpl_MemSetW16((int16_t*)inst->noiseSupFilter, 16384, HALF_ANAL_BLOCKL);
-
- // Set the aggressiveness: default
- inst->aggrMode = 0;
-
- //initialize variables for new method
- inst->priorNonSpeechProb = 8192; // Q14(0.5) prior probability for speech/noise
- for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
- inst->prevMagnU16[i] = 0;
- inst->prevNoiseU32[i] = 0; //previous noise-spectrum
- inst->logLrtTimeAvgW32[i] = 0; //smooth LR ratio
- inst->avgMagnPause[i] = 0; //conservative noise spectrum estimate
- inst->initMagnEst[i] = 0; //initial average magnitude spectrum
- }
-
- //feature quantities
- inst->thresholdSpecDiff = 50; //threshold for difference feature: determined on-line
- inst->thresholdSpecFlat = 20480; //threshold for flatness: determined on-line
- inst->featureLogLrt = inst->thresholdLogLrt; //average LRT factor (= threshold)
- inst->featureSpecFlat = inst->thresholdSpecFlat; //spectral flatness (= threshold)
- inst->featureSpecDiff = inst->thresholdSpecDiff; //spectral difference (= threshold)
- inst->weightLogLrt = 6; //default weighting par for LRT feature
- inst->weightSpecFlat = 0; //default weighting par for spectral flatness feature
- inst->weightSpecDiff = 0; //default weighting par for spectral difference feature
-
- inst->curAvgMagnEnergy = 0; //window time-average of input magnitude spectrum
- inst->timeAvgMagnEnergy = 0; //normalization for spectral difference
- inst->timeAvgMagnEnergyTmp = 0; //normalization for spectral difference
-
- //histogram quantities: used to estimate/update thresholds for features
- WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST);
- WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST);
- WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST);
-
- inst->blockIndex = -1; //frame counter
-
- //inst->modelUpdate = 500; //window for update
- inst->modelUpdate = (1 << STAT_UPDATES); //window for update
- inst->cntThresUpdate = 0; //counter feature thresholds updates
-
- inst->sumMagn = 0;
- inst->magnEnergy = 0;
- inst->prevQMagn = 0;
- inst->qNoise = 0;
- inst->prevQNoise = 0;
-
- inst->energyIn = 0;
- inst->scaleEnergyIn = 0;
-
- inst->whiteNoiseLevel = 0;
- inst->pinkNoiseNumerator = 0;
- inst->pinkNoiseExp = 0;
- inst->minNorm = 15; // Start with full scale
- inst->zeroInputSignal = 0;
-
- //default mode
- WebRtcNsx_set_policy_core(inst, 0);
-
-#ifdef NS_FILEDEBUG
- inst->infile = fopen("indebug.pcm", "wb");
- inst->outfile = fopen("outdebug.pcm", "wb");
- inst->file1 = fopen("file1.pcm", "wb");
- inst->file2 = fopen("file2.pcm", "wb");
- inst->file3 = fopen("file3.pcm", "wb");
- inst->file4 = fopen("file4.pcm", "wb");
- inst->file5 = fopen("file5.pcm", "wb");
-#endif
-
- // Initialize function pointers.
- WebRtcNsx_NoiseEstimation = NoiseEstimationC;
- WebRtcNsx_PrepareSpectrum = PrepareSpectrumC;
- WebRtcNsx_SynthesisUpdate = SynthesisUpdateC;
- WebRtcNsx_AnalysisUpdate = AnalysisUpdateC;
- WebRtcNsx_Denormalize = DenormalizeC;
- WebRtcNsx_NormalizeRealBuffer = NormalizeRealBufferC;
-
-#ifdef WEBRTC_DETECT_NEON
- uint64_t features = WebRtc_GetCPUFeaturesARM();
- if ((features & kCPUFeatureNEON) != 0) {
- WebRtcNsx_InitNeon();
- }
-#elif defined(WEBRTC_HAS_NEON)
- WebRtcNsx_InitNeon();
-#endif
-
-#if defined(MIPS32_LE)
- WebRtcNsx_InitMips();
-#endif
-
- inst->initFlag = 1;
-
- return 0;
-}
-
-int WebRtcNsx_set_policy_core(NoiseSuppressionFixedC* inst, int mode) {
- // allow for modes:0,1,2,3
- if (mode < 0 || mode > 3) {
- return -1;
- }
-
- inst->aggrMode = mode;
- if (mode == 0) {
- inst->overdrive = 256; // Q8(1.0)
- inst->denoiseBound = 8192; // Q14(0.5)
- inst->gainMap = 0; // No gain compensation
- } else if (mode == 1) {
- inst->overdrive = 256; // Q8(1.0)
- inst->denoiseBound = 4096; // Q14(0.25)
- inst->factor2Table = kFactor2Aggressiveness1;
- inst->gainMap = 1;
- } else if (mode == 2) {
- inst->overdrive = 282; // ~= Q8(1.1)
- inst->denoiseBound = 2048; // Q14(0.125)
- inst->factor2Table = kFactor2Aggressiveness2;
- inst->gainMap = 1;
- } else if (mode == 3) {
- inst->overdrive = 320; // Q8(1.25)
- inst->denoiseBound = 1475; // ~= Q14(0.09)
- inst->factor2Table = kFactor2Aggressiveness3;
- inst->gainMap = 1;
- }
- return 0;
-}
-
-// Extract thresholds for feature parameters
-// histograms are computed over some window_size (given by window_pars)
-// thresholds and weights are extracted every window
-// flag 0 means update histogram only, flag 1 means compute the thresholds/weights
-// threshold and weights are returned in: inst->priorModelPars
-void WebRtcNsx_FeatureParameterExtraction(NoiseSuppressionFixedC* inst,
- int flag) {
- uint32_t tmpU32;
- uint32_t histIndex;
- uint32_t posPeak1SpecFlatFX, posPeak2SpecFlatFX;
- uint32_t posPeak1SpecDiffFX, posPeak2SpecDiffFX;
-
- int32_t tmp32;
- int32_t fluctLrtFX, thresFluctLrtFX;
- int32_t avgHistLrtFX, avgSquareHistLrtFX, avgHistLrtComplFX;
-
- int16_t j;
- int16_t numHistLrt;
-
- int i;
- int useFeatureSpecFlat, useFeatureSpecDiff, featureSum;
- int maxPeak1, maxPeak2;
- int weightPeak1SpecFlat, weightPeak2SpecFlat;
- int weightPeak1SpecDiff, weightPeak2SpecDiff;
-
- //update histograms
- if (!flag) {
- // LRT
- // Type casting to UWord32 is safe since negative values will not be wrapped to larger
- // values than HIST_PAR_EST
- histIndex = (uint32_t)(inst->featureLogLrt);
- if (histIndex < HIST_PAR_EST) {
- inst->histLrt[histIndex]++;
- }
- // Spectral flatness
- // (inst->featureSpecFlat*20)>>10 = (inst->featureSpecFlat*5)>>8
- histIndex = (inst->featureSpecFlat * 5) >> 8;
- if (histIndex < HIST_PAR_EST) {
- inst->histSpecFlat[histIndex]++;
- }
- // Spectral difference
- histIndex = HIST_PAR_EST;
- if (inst->timeAvgMagnEnergy > 0) {
- // Guard against division by zero
- // If timeAvgMagnEnergy == 0 we have no normalizing statistics and
- // therefore can't update the histogram
- histIndex = ((inst->featureSpecDiff * 5) >> inst->stages) /
- inst->timeAvgMagnEnergy;
- }
- if (histIndex < HIST_PAR_EST) {
- inst->histSpecDiff[histIndex]++;
- }
- }
-
- // extract parameters for speech/noise probability
- if (flag) {
- useFeatureSpecDiff = 1;
- //for LRT feature:
- // compute the average over inst->featureExtractionParams.rangeAvgHistLrt
- avgHistLrtFX = 0;
- avgSquareHistLrtFX = 0;
- numHistLrt = 0;
- for (i = 0; i < BIN_SIZE_LRT; i++) {
- j = (2 * i + 1);
- tmp32 = inst->histLrt[i] * j;
- avgHistLrtFX += tmp32;
- numHistLrt += inst->histLrt[i];
- avgSquareHistLrtFX += tmp32 * j;
- }
- avgHistLrtComplFX = avgHistLrtFX;
- for (; i < HIST_PAR_EST; i++) {
- j = (2 * i + 1);
- tmp32 = inst->histLrt[i] * j;
- avgHistLrtComplFX += tmp32;
- avgSquareHistLrtFX += tmp32 * j;
- }
- fluctLrtFX = avgSquareHistLrtFX * numHistLrt -
- avgHistLrtFX * avgHistLrtComplFX;
- thresFluctLrtFX = THRES_FLUCT_LRT * numHistLrt;
- // get threshold for LRT feature:
- tmpU32 = (FACTOR_1_LRT_DIFF * (uint32_t)avgHistLrtFX);
- if ((fluctLrtFX < thresFluctLrtFX) || (numHistLrt == 0) ||
- (tmpU32 > (uint32_t)(100 * numHistLrt))) {
- //very low fluctuation, so likely noise
- inst->thresholdLogLrt = inst->maxLrt;
- } else {
- tmp32 = (int32_t)((tmpU32 << (9 + inst->stages)) / numHistLrt /
- 25);
- // check if value is within min/max range
- inst->thresholdLogLrt = WEBRTC_SPL_SAT(inst->maxLrt,
- tmp32,
- inst->minLrt);
- }
- if (fluctLrtFX < thresFluctLrtFX) {
- // Do not use difference feature if fluctuation of LRT feature is very low:
- // most likely just noise state
- useFeatureSpecDiff = 0;
- }
-
- // for spectral flatness and spectral difference: compute the main peaks of histogram
- maxPeak1 = 0;
- maxPeak2 = 0;
- posPeak1SpecFlatFX = 0;
- posPeak2SpecFlatFX = 0;
- weightPeak1SpecFlat = 0;
- weightPeak2SpecFlat = 0;
-
- // peaks for flatness
- for (i = 0; i < HIST_PAR_EST; i++) {
- if (inst->histSpecFlat[i] > maxPeak1) {
- // Found new "first" peak
- maxPeak2 = maxPeak1;
- weightPeak2SpecFlat = weightPeak1SpecFlat;
- posPeak2SpecFlatFX = posPeak1SpecFlatFX;
-
- maxPeak1 = inst->histSpecFlat[i];
- weightPeak1SpecFlat = inst->histSpecFlat[i];
- posPeak1SpecFlatFX = (uint32_t)(2 * i + 1);
- } else if (inst->histSpecFlat[i] > maxPeak2) {
- // Found new "second" peak
- maxPeak2 = inst->histSpecFlat[i];
- weightPeak2SpecFlat = inst->histSpecFlat[i];
- posPeak2SpecFlatFX = (uint32_t)(2 * i + 1);
- }
- }
-
- // for spectral flatness feature
- useFeatureSpecFlat = 1;
- // merge the two peaks if they are close
- if ((posPeak1SpecFlatFX - posPeak2SpecFlatFX < LIM_PEAK_SPACE_FLAT_DIFF)
- && (weightPeak2SpecFlat * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecFlat)) {
- weightPeak1SpecFlat += weightPeak2SpecFlat;
- posPeak1SpecFlatFX = (posPeak1SpecFlatFX + posPeak2SpecFlatFX) >> 1;
- }
- //reject if weight of peaks is not large enough, or peak value too small
- if (weightPeak1SpecFlat < THRES_WEIGHT_FLAT_DIFF || posPeak1SpecFlatFX
- < THRES_PEAK_FLAT) {
- useFeatureSpecFlat = 0;
- } else { // if selected, get the threshold
- // compute the threshold and check if value is within min/max range
- inst->thresholdSpecFlat = WEBRTC_SPL_SAT(MAX_FLAT_Q10, FACTOR_2_FLAT_Q10
- * posPeak1SpecFlatFX, MIN_FLAT_Q10); //Q10
- }
- // done with flatness feature
-
- if (useFeatureSpecDiff) {
- //compute two peaks for spectral difference
- maxPeak1 = 0;
- maxPeak2 = 0;
- posPeak1SpecDiffFX = 0;
- posPeak2SpecDiffFX = 0;
- weightPeak1SpecDiff = 0;
- weightPeak2SpecDiff = 0;
- // peaks for spectral difference
- for (i = 0; i < HIST_PAR_EST; i++) {
- if (inst->histSpecDiff[i] > maxPeak1) {
- // Found new "first" peak
- maxPeak2 = maxPeak1;
- weightPeak2SpecDiff = weightPeak1SpecDiff;
- posPeak2SpecDiffFX = posPeak1SpecDiffFX;
-
- maxPeak1 = inst->histSpecDiff[i];
- weightPeak1SpecDiff = inst->histSpecDiff[i];
- posPeak1SpecDiffFX = (uint32_t)(2 * i + 1);
- } else if (inst->histSpecDiff[i] > maxPeak2) {
- // Found new "second" peak
- maxPeak2 = inst->histSpecDiff[i];
- weightPeak2SpecDiff = inst->histSpecDiff[i];
- posPeak2SpecDiffFX = (uint32_t)(2 * i + 1);
- }
- }
-
- // merge the two peaks if they are close
- if ((posPeak1SpecDiffFX - posPeak2SpecDiffFX < LIM_PEAK_SPACE_FLAT_DIFF)
- && (weightPeak2SpecDiff * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecDiff)) {
- weightPeak1SpecDiff += weightPeak2SpecDiff;
- posPeak1SpecDiffFX = (posPeak1SpecDiffFX + posPeak2SpecDiffFX) >> 1;
- }
- // get the threshold value and check if value is within min/max range
- inst->thresholdSpecDiff = WEBRTC_SPL_SAT(MAX_DIFF, FACTOR_1_LRT_DIFF
- * posPeak1SpecDiffFX, MIN_DIFF); //5x bigger
- //reject if weight of peaks is not large enough
- if (weightPeak1SpecDiff < THRES_WEIGHT_FLAT_DIFF) {
- useFeatureSpecDiff = 0;
- }
- // done with spectral difference feature
- }
-
- // select the weights between the features
- // inst->priorModelPars[4] is weight for LRT: always selected
- featureSum = 6 / (1 + useFeatureSpecFlat + useFeatureSpecDiff);
- inst->weightLogLrt = featureSum;
- inst->weightSpecFlat = useFeatureSpecFlat * featureSum;
- inst->weightSpecDiff = useFeatureSpecDiff * featureSum;
-
- // set histograms to zero for next update
- WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST);
- WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST);
- WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST);
- } // end of flag == 1
-}
-
-
-// Compute spectral flatness on input spectrum
-// magn is the magnitude spectrum
-// spectral flatness is returned in inst->featureSpecFlat
-void WebRtcNsx_ComputeSpectralFlatness(NoiseSuppressionFixedC* inst,
- uint16_t* magn) {
- uint32_t tmpU32;
- uint32_t avgSpectralFlatnessNum, avgSpectralFlatnessDen;
-
- int32_t tmp32;
- int32_t currentSpectralFlatness, logCurSpectralFlatness;
-
- int16_t zeros, frac, intPart;
-
- size_t i;
-
- // for flatness
- avgSpectralFlatnessNum = 0;
- avgSpectralFlatnessDen = inst->sumMagn - (uint32_t)magn[0]; // Q(normData-stages)
-
- // compute log of ratio of the geometric to arithmetic mean: check for log(0) case
- // flatness = exp( sum(log(magn[i]))/N - log(sum(magn[i])/N) )
- // = exp( sum(log(magn[i]))/N ) * N / sum(magn[i])
- // = 2^( sum(log2(magn[i]))/N - (log2(sum(magn[i])) - log2(N)) ) [This is used]
- for (i = 1; i < inst->magnLen; i++) {
- // First bin is excluded from spectrum measures. Number of bins is now a power of 2
- if (magn[i]) {
- zeros = WebRtcSpl_NormU32((uint32_t)magn[i]);
- frac = (int16_t)(((uint32_t)((uint32_t)(magn[i]) << zeros)
- & 0x7FFFFFFF) >> 23);
- // log2(magn(i))
- assert(frac < 256);
- tmpU32 = (uint32_t)(((31 - zeros) << 8)
- + WebRtcNsx_kLogTableFrac[frac]); // Q8
- avgSpectralFlatnessNum += tmpU32; // Q8
- } else {
- //if at least one frequency component is zero, treat separately
- tmpU32 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecFlat, SPECT_FLAT_TAVG_Q14); // Q24
- inst->featureSpecFlat -= tmpU32 >> 14; // Q10
- return;
- }
- }
- //ratio and inverse log: check for case of log(0)
- zeros = WebRtcSpl_NormU32(avgSpectralFlatnessDen);
- frac = (int16_t)(((avgSpectralFlatnessDen << zeros) & 0x7FFFFFFF) >> 23);
- // log2(avgSpectralFlatnessDen)
- assert(frac < 256);
- tmp32 = (int32_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); // Q8
- logCurSpectralFlatness = (int32_t)avgSpectralFlatnessNum;
- logCurSpectralFlatness += ((int32_t)(inst->stages - 1) << (inst->stages + 7)); // Q(8+stages-1)
- logCurSpectralFlatness -= (tmp32 << (inst->stages - 1));
- logCurSpectralFlatness <<= (10 - inst->stages); // Q17
- tmp32 = (int32_t)(0x00020000 | (WEBRTC_SPL_ABS_W32(logCurSpectralFlatness)
- & 0x0001FFFF)); //Q17
- intPart = 7 - (logCurSpectralFlatness >> 17); // Add 7 for output in Q10.
- if (intPart > 0) {
- currentSpectralFlatness = tmp32 >> intPart;
- } else {
- currentSpectralFlatness = tmp32 << -intPart;
- }
-
- //time average update of spectral flatness feature
- tmp32 = currentSpectralFlatness - (int32_t)inst->featureSpecFlat; // Q10
- tmp32 *= SPECT_FLAT_TAVG_Q14; // Q24
- inst->featureSpecFlat += tmp32 >> 14; // Q10
- // done with flatness feature
-}
-
-
-// Compute the difference measure between input spectrum and a template/learned noise spectrum
-// magn_tmp is the input spectrum
-// the reference/template spectrum is inst->magn_avg_pause[i]
-// returns (normalized) spectral difference in inst->featureSpecDiff
-void WebRtcNsx_ComputeSpectralDifference(NoiseSuppressionFixedC* inst,
- uint16_t* magnIn) {
- // This is to be calculated:
- // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause)
-
- uint32_t tmpU32no1, tmpU32no2;
- uint32_t varMagnUFX, varPauseUFX, avgDiffNormMagnUFX;
-
- int32_t tmp32no1, tmp32no2;
- int32_t avgPauseFX, avgMagnFX, covMagnPauseFX;
- int32_t maxPause, minPause;
-
- int16_t tmp16no1;
-
- size_t i;
- int norm32, nShifts;
-
- avgPauseFX = 0;
- maxPause = 0;
- minPause = inst->avgMagnPause[0]; // Q(prevQMagn)
- // compute average quantities
- for (i = 0; i < inst->magnLen; i++) {
- // Compute mean of magn_pause
- avgPauseFX += inst->avgMagnPause[i]; // in Q(prevQMagn)
- maxPause = WEBRTC_SPL_MAX(maxPause, inst->avgMagnPause[i]);
- minPause = WEBRTC_SPL_MIN(minPause, inst->avgMagnPause[i]);
- }
- // normalize by replacing div of "inst->magnLen" with "inst->stages-1" shifts
- avgPauseFX >>= inst->stages - 1;
- avgMagnFX = inst->sumMagn >> (inst->stages - 1);
- // Largest possible deviation in magnPause for (co)var calculations
- tmp32no1 = WEBRTC_SPL_MAX(maxPause - avgPauseFX, avgPauseFX - minPause);
- // Get number of shifts to make sure we don't get wrap around in varPause
- nShifts = WEBRTC_SPL_MAX(0, 10 + inst->stages - WebRtcSpl_NormW32(tmp32no1));
-
- varMagnUFX = 0;
- varPauseUFX = 0;
- covMagnPauseFX = 0;
- for (i = 0; i < inst->magnLen; i++) {
- // Compute var and cov of magn and magn_pause
- tmp16no1 = (int16_t)((int32_t)magnIn[i] - avgMagnFX);
- tmp32no2 = inst->avgMagnPause[i] - avgPauseFX;
- varMagnUFX += (uint32_t)(tmp16no1 * tmp16no1); // Q(2*qMagn)
- tmp32no1 = tmp32no2 * tmp16no1; // Q(prevQMagn+qMagn)
- covMagnPauseFX += tmp32no1; // Q(prevQMagn+qMagn)
- tmp32no1 = tmp32no2 >> nShifts; // Q(prevQMagn-minPause).
- varPauseUFX += tmp32no1 * tmp32no1; // Q(2*(prevQMagn-minPause))
- }
- //update of average magnitude spectrum: Q(-2*stages) and averaging replaced by shifts
- inst->curAvgMagnEnergy +=
- inst->magnEnergy >> (2 * inst->normData + inst->stages - 1);
-
- avgDiffNormMagnUFX = varMagnUFX; // Q(2*qMagn)
- if ((varPauseUFX) && (covMagnPauseFX)) {
- tmpU32no1 = (uint32_t)WEBRTC_SPL_ABS_W32(covMagnPauseFX); // Q(prevQMagn+qMagn)
- norm32 = WebRtcSpl_NormU32(tmpU32no1) - 16;
- if (norm32 > 0) {
- tmpU32no1 <<= norm32; // Q(prevQMagn+qMagn+norm32)
- } else {
- tmpU32no1 >>= -norm32; // Q(prevQMagn+qMagn+norm32)
- }
- tmpU32no2 = WEBRTC_SPL_UMUL(tmpU32no1, tmpU32no1); // Q(2*(prevQMagn+qMagn-norm32))
-
- nShifts += norm32;
- nShifts <<= 1;
- if (nShifts < 0) {
- varPauseUFX >>= (-nShifts); // Q(2*(qMagn+norm32+minPause))
- nShifts = 0;
- }
- if (varPauseUFX > 0) {
- // Q(2*(qMagn+norm32-16+minPause))
- tmpU32no1 = tmpU32no2 / varPauseUFX;
- tmpU32no1 >>= nShifts;
-
- // Q(2*qMagn)
- avgDiffNormMagnUFX -= WEBRTC_SPL_MIN(avgDiffNormMagnUFX, tmpU32no1);
- } else {
- avgDiffNormMagnUFX = 0;
- }
- }
- //normalize and compute time average update of difference feature
- tmpU32no1 = avgDiffNormMagnUFX >> (2 * inst->normData);
- if (inst->featureSpecDiff > tmpU32no1) {
- tmpU32no2 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecDiff - tmpU32no1,
- SPECT_DIFF_TAVG_Q8); // Q(8-2*stages)
- inst->featureSpecDiff -= tmpU32no2 >> 8; // Q(-2*stages)
- } else {
- tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no1 - inst->featureSpecDiff,
- SPECT_DIFF_TAVG_Q8); // Q(8-2*stages)
- inst->featureSpecDiff += tmpU32no2 >> 8; // Q(-2*stages)
- }
-}
-
-// Transform input (speechFrame) to frequency domain magnitude (magnU16)
-void WebRtcNsx_DataAnalysis(NoiseSuppressionFixedC* inst,
- short* speechFrame,
- uint16_t* magnU16) {
- uint32_t tmpU32no1;
-
- int32_t tmp_1_w32 = 0;
- int32_t tmp_2_w32 = 0;
- int32_t sum_log_magn = 0;
- int32_t sum_log_i_log_magn = 0;
-
- uint16_t sum_log_magn_u16 = 0;
- uint16_t tmp_u16 = 0;
-
- int16_t sum_log_i = 0;
- int16_t sum_log_i_square = 0;
- int16_t frac = 0;
- int16_t log2 = 0;
- int16_t matrix_determinant = 0;
- int16_t maxWinData;
-
- size_t i, j;
- int zeros;
- int net_norm = 0;
- int right_shifts_in_magnU16 = 0;
- int right_shifts_in_initMagnEst = 0;
-
- int16_t winData_buff[ANAL_BLOCKL_MAX * 2 + 16];
- int16_t realImag_buff[ANAL_BLOCKL_MAX * 2 + 16];
-
- // Align the structures to 32-byte boundary for the FFT function.
- int16_t* winData = (int16_t*) (((uintptr_t)winData_buff + 31) & ~31);
- int16_t* realImag = (int16_t*) (((uintptr_t) realImag_buff + 31) & ~31);
-
- // Update analysis buffer for lower band, and window data before FFT.
- WebRtcNsx_AnalysisUpdate(inst, winData, speechFrame);
-
- // Get input energy
- inst->energyIn =
- WebRtcSpl_Energy(winData, inst->anaLen, &inst->scaleEnergyIn);
-
- // Reset zero input flag
- inst->zeroInputSignal = 0;
- // Acquire norm for winData
- maxWinData = WebRtcSpl_MaxAbsValueW16(winData, inst->anaLen);
- inst->normData = WebRtcSpl_NormW16(maxWinData);
- if (maxWinData == 0) {
- // Treat zero input separately.
- inst->zeroInputSignal = 1;
- return;
- }
-
- // Determine the net normalization in the frequency domain
- net_norm = inst->stages - inst->normData;
- // Track lowest normalization factor and use it to prevent wrap around in shifting
- right_shifts_in_magnU16 = inst->normData - inst->minNorm;
- right_shifts_in_initMagnEst = WEBRTC_SPL_MAX(-right_shifts_in_magnU16, 0);
- inst->minNorm -= right_shifts_in_initMagnEst;
- right_shifts_in_magnU16 = WEBRTC_SPL_MAX(right_shifts_in_magnU16, 0);
-
- // create realImag as winData interleaved with zeros (= imag. part), normalize it
- WebRtcNsx_NormalizeRealBuffer(inst, winData, realImag);
-
- // FFT output will be in winData[].
- WebRtcSpl_RealForwardFFT(inst->real_fft, realImag, winData);
-
- inst->imag[0] = 0; // Q(normData-stages)
- inst->imag[inst->anaLen2] = 0;
- inst->real[0] = winData[0]; // Q(normData-stages)
- inst->real[inst->anaLen2] = winData[inst->anaLen];
- // Q(2*(normData-stages))
- inst->magnEnergy = (uint32_t)(inst->real[0] * inst->real[0]);
- inst->magnEnergy += (uint32_t)(inst->real[inst->anaLen2] *
- inst->real[inst->anaLen2]);
- magnU16[0] = (uint16_t)WEBRTC_SPL_ABS_W16(inst->real[0]); // Q(normData-stages)
- magnU16[inst->anaLen2] = (uint16_t)WEBRTC_SPL_ABS_W16(inst->real[inst->anaLen2]);
- inst->sumMagn = (uint32_t)magnU16[0]; // Q(normData-stages)
- inst->sumMagn += (uint32_t)magnU16[inst->anaLen2];
-
- if (inst->blockIndex >= END_STARTUP_SHORT) {
- for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
- inst->real[i] = winData[j];
- inst->imag[i] = -winData[j + 1];
- // magnitude spectrum
- // energy in Q(2*(normData-stages))
- tmpU32no1 = (uint32_t)(winData[j] * winData[j]);
- tmpU32no1 += (uint32_t)(winData[j + 1] * winData[j + 1]);
- inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages))
-
- magnU16[i] = (uint16_t)WebRtcSpl_SqrtFloor(tmpU32no1); // Q(normData-stages)
- inst->sumMagn += (uint32_t)magnU16[i]; // Q(normData-stages)
- }
- } else {
- //
- // Gather information during startup for noise parameter estimation
- //
-
- // Switch initMagnEst to Q(minNorm-stages)
- inst->initMagnEst[0] >>= right_shifts_in_initMagnEst;
- inst->initMagnEst[inst->anaLen2] >>= right_shifts_in_initMagnEst;
-
- // Update initMagnEst with magnU16 in Q(minNorm-stages).
- inst->initMagnEst[0] += magnU16[0] >> right_shifts_in_magnU16;
- inst->initMagnEst[inst->anaLen2] +=
- magnU16[inst->anaLen2] >> right_shifts_in_magnU16;
-
- log2 = 0;
- if (magnU16[inst->anaLen2]) {
- // Calculate log2(magnU16[inst->anaLen2])
- zeros = WebRtcSpl_NormU32((uint32_t)magnU16[inst->anaLen2]);
- frac = (int16_t)((((uint32_t)magnU16[inst->anaLen2] << zeros) &
- 0x7FFFFFFF) >> 23); // Q8
- // log2(magnU16(i)) in Q8
- assert(frac < 256);
- log2 = (int16_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]);
- }
-
- sum_log_magn = (int32_t)log2; // Q8
- // sum_log_i_log_magn in Q17
- sum_log_i_log_magn = (kLogIndex[inst->anaLen2] * log2) >> 3;
-
- for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
- inst->real[i] = winData[j];
- inst->imag[i] = -winData[j + 1];
- // magnitude spectrum
- // energy in Q(2*(normData-stages))
- tmpU32no1 = (uint32_t)(winData[j] * winData[j]);
- tmpU32no1 += (uint32_t)(winData[j + 1] * winData[j + 1]);
- inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages))
-
- magnU16[i] = (uint16_t)WebRtcSpl_SqrtFloor(tmpU32no1); // Q(normData-stages)
- inst->sumMagn += (uint32_t)magnU16[i]; // Q(normData-stages)
-
- // Switch initMagnEst to Q(minNorm-stages)
- inst->initMagnEst[i] >>= right_shifts_in_initMagnEst;
-
- // Update initMagnEst with magnU16 in Q(minNorm-stages).
- inst->initMagnEst[i] += magnU16[i] >> right_shifts_in_magnU16;
-
- if (i >= kStartBand) {
- // For pink noise estimation. Collect data neglecting lower frequency band
- log2 = 0;
- if (magnU16[i]) {
- zeros = WebRtcSpl_NormU32((uint32_t)magnU16[i]);
- frac = (int16_t)((((uint32_t)magnU16[i] << zeros) &
- 0x7FFFFFFF) >> 23);
- // log2(magnU16(i)) in Q8
- assert(frac < 256);
- log2 = (int16_t)(((31 - zeros) << 8)
- + WebRtcNsx_kLogTableFrac[frac]);
- }
- sum_log_magn += (int32_t)log2; // Q8
- // sum_log_i_log_magn in Q17
- sum_log_i_log_magn += (kLogIndex[i] * log2) >> 3;
- }
- }
-
- //
- //compute simplified noise model during startup
- //
-
- // Estimate White noise
-
- // Switch whiteNoiseLevel to Q(minNorm-stages)
- inst->whiteNoiseLevel >>= right_shifts_in_initMagnEst;
-
- // Update the average magnitude spectrum, used as noise estimate.
- tmpU32no1 = WEBRTC_SPL_UMUL_32_16(inst->sumMagn, inst->overdrive);
- tmpU32no1 >>= inst->stages + 8;
-
- // Replacing division above with 'stages' shifts
- // Shift to same Q-domain as whiteNoiseLevel
- tmpU32no1 >>= right_shifts_in_magnU16;
- // This operation is safe from wrap around as long as END_STARTUP_SHORT < 128
- assert(END_STARTUP_SHORT < 128);
- inst->whiteNoiseLevel += tmpU32no1; // Q(minNorm-stages)
-
- // Estimate Pink noise parameters
- // Denominator used in both parameter estimates.
- // The value is only dependent on the size of the frequency band (kStartBand)
- // and to reduce computational complexity stored in a table (kDeterminantEstMatrix[])
- assert(kStartBand < 66);
- matrix_determinant = kDeterminantEstMatrix[kStartBand]; // Q0
- sum_log_i = kSumLogIndex[kStartBand]; // Q5
- sum_log_i_square = kSumSquareLogIndex[kStartBand]; // Q2
- if (inst->fs == 8000) {
- // Adjust values to shorter blocks in narrow band.
- tmp_1_w32 = (int32_t)matrix_determinant;
- tmp_1_w32 += (kSumLogIndex[65] * sum_log_i) >> 9;
- tmp_1_w32 -= (kSumLogIndex[65] * kSumLogIndex[65]) >> 10;
- tmp_1_w32 -= (int32_t)sum_log_i_square << 4;
- tmp_1_w32 -= ((inst->magnLen - kStartBand) * kSumSquareLogIndex[65]) >> 2;
- matrix_determinant = (int16_t)tmp_1_w32;
- sum_log_i -= kSumLogIndex[65]; // Q5
- sum_log_i_square -= kSumSquareLogIndex[65]; // Q2
- }
-
- // Necessary number of shifts to fit sum_log_magn in a word16
- zeros = 16 - WebRtcSpl_NormW32(sum_log_magn);
- if (zeros < 0) {
- zeros = 0;
- }
- tmp_1_w32 = sum_log_magn << 1; // Q9
- sum_log_magn_u16 = (uint16_t)(tmp_1_w32 >> zeros); // Q(9-zeros).
-
- // Calculate and update pinkNoiseNumerator. Result in Q11.
- tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i_square, sum_log_magn_u16); // Q(11-zeros)
- tmpU32no1 = sum_log_i_log_magn >> 12; // Q5
-
- // Shift the largest value of sum_log_i and tmp32no3 before multiplication
- tmp_u16 = ((uint16_t)sum_log_i << 1); // Q6
- if ((uint32_t)sum_log_i > tmpU32no1) {
- tmp_u16 >>= zeros;
- } else {
- tmpU32no1 >>= zeros;
- }
- tmp_2_w32 -= (int32_t)WEBRTC_SPL_UMUL_32_16(tmpU32no1, tmp_u16); // Q(11-zeros)
- matrix_determinant >>= zeros; // Q(-zeros)
- tmp_2_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q11
- tmp_2_w32 += (int32_t)net_norm << 11; // Q11
- if (tmp_2_w32 < 0) {
- tmp_2_w32 = 0;
- }
- inst->pinkNoiseNumerator += tmp_2_w32; // Q11
-
- // Calculate and update pinkNoiseExp. Result in Q14.
- tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i, sum_log_magn_u16); // Q(14-zeros)
- tmp_1_w32 = sum_log_i_log_magn >> (3 + zeros);
- tmp_1_w32 *= inst->magnLen - kStartBand;
- tmp_2_w32 -= tmp_1_w32; // Q(14-zeros)
- if (tmp_2_w32 > 0) {
- // If the exponential parameter is negative force it to zero, which means a
- // flat spectrum.
- tmp_1_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q14
- inst->pinkNoiseExp += WEBRTC_SPL_SAT(16384, tmp_1_w32, 0); // Q14
- }
- }
-}
-
-void WebRtcNsx_DataSynthesis(NoiseSuppressionFixedC* inst, short* outFrame) {
- int32_t energyOut;
-
- int16_t realImag_buff[ANAL_BLOCKL_MAX * 2 + 16];
- int16_t rfft_out_buff[ANAL_BLOCKL_MAX * 2 + 16];
-
- // Align the structures to 32-byte boundary for the FFT function.
- int16_t* realImag = (int16_t*) (((uintptr_t)realImag_buff + 31) & ~31);
- int16_t* rfft_out = (int16_t*) (((uintptr_t) rfft_out_buff + 31) & ~31);
-
- int16_t tmp16no1, tmp16no2;
- int16_t energyRatio;
- int16_t gainFactor, gainFactor1, gainFactor2;
-
- size_t i;
- int outCIFFT;
- int scaleEnergyOut = 0;
-
- if (inst->zeroInputSignal) {
- // synthesize the special case of zero input
- // read out fully processed segment
- for (i = 0; i < inst->blockLen10ms; i++) {
- outFrame[i] = inst->synthesisBuffer[i]; // Q0
- }
- // update synthesis buffer
- memcpy(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms,
- (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->synthesisBuffer));
- WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms,
- inst->blockLen10ms);
- return;
- }
-
- // Filter the data in the frequency domain, and create spectrum.
- WebRtcNsx_PrepareSpectrum(inst, realImag);
-
- // Inverse FFT output will be in rfft_out[].
- outCIFFT = WebRtcSpl_RealInverseFFT(inst->real_fft, realImag, rfft_out);
-
- WebRtcNsx_Denormalize(inst, rfft_out, outCIFFT);
-
- //scale factor: only do it after END_STARTUP_LONG time
- gainFactor = 8192; // 8192 = Q13(1.0)
- if (inst->gainMap == 1 &&
- inst->blockIndex > END_STARTUP_LONG &&
- inst->energyIn > 0) {
- // Q(-scaleEnergyOut)
- energyOut = WebRtcSpl_Energy(inst->real, inst->anaLen, &scaleEnergyOut);
- if (scaleEnergyOut == 0 && !(energyOut & 0x7f800000)) {
- energyOut = WEBRTC_SPL_SHIFT_W32(energyOut, 8 + scaleEnergyOut
- - inst->scaleEnergyIn);
- } else {
- // |energyIn| is currently in Q(|scaleEnergyIn|), but to later on end up
- // with an |energyRatio| in Q8 we need to change the Q-domain to
- // Q(-8-scaleEnergyOut).
- inst->energyIn >>= 8 + scaleEnergyOut - inst->scaleEnergyIn;
- }
-
- assert(inst->energyIn > 0);
- energyRatio = (energyOut + inst->energyIn / 2) / inst->energyIn; // Q8
- // Limit the ratio to [0, 1] in Q8, i.e., [0, 256]
- energyRatio = WEBRTC_SPL_SAT(256, energyRatio, 0);
-
- // all done in lookup tables now
- assert(energyRatio < 257);
- gainFactor1 = kFactor1Table[energyRatio]; // Q8
- gainFactor2 = inst->factor2Table[energyRatio]; // Q8
-
- //combine both scales with speech/noise prob: note prior (priorSpeechProb) is not frequency dependent
-
- // factor = inst->priorSpeechProb*factor1 + (1.0-inst->priorSpeechProb)*factor2; // original code
- tmp16no1 = (int16_t)(((16384 - inst->priorNonSpeechProb) * gainFactor1) >>
- 14); // in Q13, where 16384 = Q14(1.0)
- tmp16no2 = (int16_t)((inst->priorNonSpeechProb * gainFactor2) >> 14);
- gainFactor = tmp16no1 + tmp16no2; // Q13
- } // out of flag_gain_map==1
-
- // Synthesis, read out fully processed segment, and update synthesis buffer.
- WebRtcNsx_SynthesisUpdate(inst, outFrame, gainFactor);
-}
-
-void WebRtcNsx_ProcessCore(NoiseSuppressionFixedC* inst,
- const short* const* speechFrame,
- int num_bands,
- short* const* outFrame) {
- // main routine for noise suppression
-
- uint32_t tmpU32no1, tmpU32no2, tmpU32no3;
- uint32_t satMax, maxNoiseU32;
- uint32_t tmpMagnU32, tmpNoiseU32;
- uint32_t nearMagnEst;
- uint32_t noiseUpdateU32;
- uint32_t noiseU32[HALF_ANAL_BLOCKL];
- uint32_t postLocSnr[HALF_ANAL_BLOCKL];
- uint32_t priorLocSnr[HALF_ANAL_BLOCKL];
- uint32_t prevNearSnr[HALF_ANAL_BLOCKL];
- uint32_t curNearSnr;
- uint32_t priorSnr;
- uint32_t noise_estimate = 0;
- uint32_t noise_estimate_avg = 0;
- uint32_t numerator = 0;
-
- int32_t tmp32no1, tmp32no2;
- int32_t pink_noise_num_avg = 0;
-
- uint16_t tmpU16no1;
- uint16_t magnU16[HALF_ANAL_BLOCKL];
- uint16_t prevNoiseU16[HALF_ANAL_BLOCKL];
- uint16_t nonSpeechProbFinal[HALF_ANAL_BLOCKL];
- uint16_t gammaNoise, prevGammaNoise;
- uint16_t noiseSupFilterTmp[HALF_ANAL_BLOCKL];
-
- int16_t qMagn, qNoise;
- int16_t avgProbSpeechHB, gainModHB, avgFilterGainHB, gainTimeDomainHB;
- int16_t pink_noise_exp_avg = 0;
-
- size_t i, j;
- int nShifts, postShifts;
- int norm32no1, norm32no2;
- int flag, sign;
- int q_domain_to_use = 0;
-
- // Code for ARMv7-Neon platform assumes the following:
- assert(inst->anaLen > 0);
- assert(inst->anaLen2 > 0);
- assert(inst->anaLen % 16 == 0);
- assert(inst->anaLen2 % 8 == 0);
- assert(inst->blockLen10ms > 0);
- assert(inst->blockLen10ms % 16 == 0);
- assert(inst->magnLen == inst->anaLen2 + 1);
-
-#ifdef NS_FILEDEBUG
- if (fwrite(spframe, sizeof(short),
- inst->blockLen10ms, inst->infile) != inst->blockLen10ms) {
- assert(false);
- }
-#endif
-
- // Check that initialization has been done
- assert(inst->initFlag == 1);
- assert((num_bands - 1) <= NUM_HIGH_BANDS_MAX);
-
- const short* const* speechFrameHB = NULL;
- short* const* outFrameHB = NULL;
- size_t num_high_bands = 0;
- if (num_bands > 1) {
- speechFrameHB = &speechFrame[1];
- outFrameHB = &outFrame[1];
- num_high_bands = (size_t)(num_bands - 1);
- }
-
- // Store speechFrame and transform to frequency domain
- WebRtcNsx_DataAnalysis(inst, (short*)speechFrame[0], magnU16);
-
- if (inst->zeroInputSignal) {
- WebRtcNsx_DataSynthesis(inst, outFrame[0]);
-
- if (num_bands > 1) {
- // update analysis buffer for H band
- // append new data to buffer FX
- for (i = 0; i < num_high_bands; ++i) {
- int block_shift = inst->anaLen - inst->blockLen10ms;
- memcpy(inst->dataBufHBFX[i], inst->dataBufHBFX[i] + inst->blockLen10ms,
- block_shift * sizeof(*inst->dataBufHBFX[i]));
- memcpy(inst->dataBufHBFX[i] + block_shift, speechFrameHB[i],
- inst->blockLen10ms * sizeof(*inst->dataBufHBFX[i]));
- for (j = 0; j < inst->blockLen10ms; j++) {
- outFrameHB[i][j] = inst->dataBufHBFX[i][j]; // Q0
- }
- }
- } // end of H band gain computation
- return;
- }
-
- // Update block index when we have something to process
- inst->blockIndex++;
- //
-
- // Norm of magn
- qMagn = inst->normData - inst->stages;
-
- // Compute spectral flatness on input spectrum
- WebRtcNsx_ComputeSpectralFlatness(inst, magnU16);
-
- // quantile noise estimate
- WebRtcNsx_NoiseEstimation(inst, magnU16, noiseU32, &qNoise);
-
- //noise estimate from previous frame
- for (i = 0; i < inst->magnLen; i++) {
- prevNoiseU16[i] = (uint16_t)(inst->prevNoiseU32[i] >> 11); // Q(prevQNoise)
- }
-
- if (inst->blockIndex < END_STARTUP_SHORT) {
- // Noise Q-domain to be used later; see description at end of section.
- q_domain_to_use = WEBRTC_SPL_MIN((int)qNoise, inst->minNorm - inst->stages);
-
- // Calculate frequency independent parts in parametric noise estimate and calculate
- // the estimate for the lower frequency band (same values for all frequency bins)
- if (inst->pinkNoiseExp) {
- pink_noise_exp_avg = (int16_t)WebRtcSpl_DivW32W16(inst->pinkNoiseExp,
- (int16_t)(inst->blockIndex + 1)); // Q14
- pink_noise_num_avg = WebRtcSpl_DivW32W16(inst->pinkNoiseNumerator,
- (int16_t)(inst->blockIndex + 1)); // Q11
- WebRtcNsx_CalcParametricNoiseEstimate(inst,
- pink_noise_exp_avg,
- pink_noise_num_avg,
- kStartBand,
- &noise_estimate,
- &noise_estimate_avg);
- } else {
- // Use white noise estimate if we have poor pink noise parameter estimates
- noise_estimate = inst->whiteNoiseLevel; // Q(minNorm-stages)
- noise_estimate_avg = noise_estimate / (inst->blockIndex + 1); // Q(minNorm-stages)
- }
- for (i = 0; i < inst->magnLen; i++) {
- // Estimate the background noise using the pink noise parameters if permitted
- if ((inst->pinkNoiseExp) && (i >= kStartBand)) {
- // Reset noise_estimate
- noise_estimate = 0;
- noise_estimate_avg = 0;
- // Calculate the parametric noise estimate for current frequency bin
- WebRtcNsx_CalcParametricNoiseEstimate(inst,
- pink_noise_exp_avg,
- pink_noise_num_avg,
- i,
- &noise_estimate,
- &noise_estimate_avg);
- }
- // Calculate parametric Wiener filter
- noiseSupFilterTmp[i] = inst->denoiseBound;
- if (inst->initMagnEst[i]) {
- // numerator = (initMagnEst - noise_estimate * overdrive)
- // Result in Q(8+minNorm-stages)
- tmpU32no1 = WEBRTC_SPL_UMUL_32_16(noise_estimate, inst->overdrive);
- numerator = inst->initMagnEst[i] << 8;
- if (numerator > tmpU32no1) {
- // Suppression filter coefficient larger than zero, so calculate.
- numerator -= tmpU32no1;
-
- // Determine number of left shifts in numerator for best accuracy after
- // division
- nShifts = WebRtcSpl_NormU32(numerator);
- nShifts = WEBRTC_SPL_SAT(6, nShifts, 0);
-
- // Shift numerator to Q(nShifts+8+minNorm-stages)
- numerator <<= nShifts;
-
- // Shift denominator to Q(nShifts-6+minNorm-stages)
- tmpU32no1 = inst->initMagnEst[i] >> (6 - nShifts);
- if (tmpU32no1 == 0) {
- // This is only possible if numerator = 0, in which case
- // we don't need any division.
- tmpU32no1 = 1;
- }
- tmpU32no2 = numerator / tmpU32no1; // Q14
- noiseSupFilterTmp[i] = (uint16_t)WEBRTC_SPL_SAT(16384, tmpU32no2,
- (uint32_t)(inst->denoiseBound)); // Q14
- }
- }
- // Weight quantile noise 'noiseU32' with modeled noise 'noise_estimate_avg'
- // 'noiseU32 is in Q(qNoise) and 'noise_estimate' in Q(minNorm-stages)
- // To guarantee that we do not get wrap around when shifting to the same domain
- // we use the lowest one. Furthermore, we need to save 6 bits for the weighting.
- // 'noise_estimate_avg' can handle this operation by construction, but 'noiseU32'
- // may not.
-
- // Shift 'noiseU32' to 'q_domain_to_use'
- tmpU32no1 = noiseU32[i] >> (qNoise - q_domain_to_use);
- // Shift 'noise_estimate_avg' to 'q_domain_to_use'
- tmpU32no2 = noise_estimate_avg >>
- (inst->minNorm - inst->stages - q_domain_to_use);
- // Make a simple check to see if we have enough room for weighting 'tmpU32no1'
- // without wrap around
- nShifts = 0;
- if (tmpU32no1 & 0xfc000000) {
- tmpU32no1 >>= 6;
- tmpU32no2 >>= 6;
- nShifts = 6;
- }
- tmpU32no1 *= inst->blockIndex;
- tmpU32no2 *= (END_STARTUP_SHORT - inst->blockIndex);
- // Add them together and divide by startup length
- noiseU32[i] = WebRtcSpl_DivU32U16(tmpU32no1 + tmpU32no2, END_STARTUP_SHORT);
- // Shift back if necessary
- noiseU32[i] <<= nShifts;
- }
- // Update new Q-domain for 'noiseU32'
- qNoise = q_domain_to_use;
- }
- // compute average signal during END_STARTUP_LONG time:
- // used to normalize spectral difference measure
- if (inst->blockIndex < END_STARTUP_LONG) {
- // substituting division with shift ending up in Q(-2*stages)
- inst->timeAvgMagnEnergyTmp +=
- inst->magnEnergy >> (2 * inst->normData + inst->stages - 1);
- inst->timeAvgMagnEnergy = WebRtcSpl_DivU32U16(inst->timeAvgMagnEnergyTmp,
- inst->blockIndex + 1);
- }
-
- //start processing at frames == converged+1
- // STEP 1: compute prior and post SNR based on quantile noise estimates
-
- // compute direct decision (DD) estimate of prior SNR: needed for new method
- satMax = (uint32_t)1048575;// Largest possible value without getting overflow despite shifting 12 steps
- postShifts = 6 + qMagn - qNoise;
- nShifts = 5 - inst->prevQMagn + inst->prevQNoise;
- for (i = 0; i < inst->magnLen; i++) {
- // FLOAT:
- // post SNR
- // postLocSnr[i] = 0.0;
- // if (magn[i] > noise[i])
- // {
- // postLocSnr[i] = magn[i] / (noise[i] + 0.0001);
- // }
- // // previous post SNR
- // // previous estimate: based on previous frame with gain filter (smooth is previous filter)
- //
- // prevNearSnr[i] = inst->prevMagnU16[i] / (inst->noisePrev[i] + 0.0001) * (inst->smooth[i]);
- //
- // // DD estimate is sum of two terms: current estimate and previous estimate
- // // directed decision update of priorSnr (or we actually store [2*priorSnr+1])
- //
- // priorLocSnr[i] = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * (postLocSnr[i] - 1.0);
-
- // calculate post SNR: output in Q11
- postLocSnr[i] = 2048; // 1.0 in Q11
- tmpU32no1 = (uint32_t)magnU16[i] << 6; // Q(6+qMagn)
- if (postShifts < 0) {
- tmpU32no2 = noiseU32[i] >> -postShifts; // Q(6+qMagn)
- } else {
- tmpU32no2 = noiseU32[i] << postShifts; // Q(6+qMagn)
- }
- if (tmpU32no1 > tmpU32no2) {
- // Current magnitude larger than noise
- tmpU32no1 <<= 11; // Q(17+qMagn)
- if (tmpU32no2 > 0) {
- tmpU32no1 /= tmpU32no2; // Q11
- postLocSnr[i] = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
- } else {
- postLocSnr[i] = satMax;
- }
- }
-
- // calculate prevNearSnr[i] and save for later instead of recalculating it later
- // |nearMagnEst| in Q(prevQMagn + 14)
- nearMagnEst = inst->prevMagnU16[i] * inst->noiseSupFilter[i];
- tmpU32no1 = nearMagnEst << 3; // Q(prevQMagn+17)
- tmpU32no2 = inst->prevNoiseU32[i] >> nShifts; // Q(prevQMagn+6)
-
- if (tmpU32no2 > 0) {
- tmpU32no1 /= tmpU32no2; // Q11
- tmpU32no1 = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
- } else {
- tmpU32no1 = satMax; // Q11
- }
- prevNearSnr[i] = tmpU32no1; // Q11
-
- //directed decision update of priorSnr
- tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22
- tmpU32no2 = WEBRTC_SPL_UMUL_32_16(postLocSnr[i] - 2048, ONE_MINUS_DD_PR_SNR_Q11); // Q22
- priorSnr = tmpU32no1 + tmpU32no2 + 512; // Q22 (added 512 for rounding)
- // priorLocSnr = 1 + 2*priorSnr
- priorLocSnr[i] = 2048 + (priorSnr >> 10); // Q11
- } // end of loop over frequencies
- // done with step 1: DD computation of prior and post SNR
-
- // STEP 2: compute speech/noise likelihood
-
- //compute difference of input spectrum with learned/estimated noise spectrum
- WebRtcNsx_ComputeSpectralDifference(inst, magnU16);
- //compute histograms for determination of parameters (thresholds and weights for features)
- //parameters are extracted once every window time (=inst->modelUpdate)
- //counter update
- inst->cntThresUpdate++;
- flag = (int)(inst->cntThresUpdate == inst->modelUpdate);
- //update histogram
- WebRtcNsx_FeatureParameterExtraction(inst, flag);
- //compute model parameters
- if (flag) {
- inst->cntThresUpdate = 0; // Reset counter
- //update every window:
- // get normalization for spectral difference for next window estimate
-
- // Shift to Q(-2*stages)
- inst->curAvgMagnEnergy >>= STAT_UPDATES;
-
- tmpU32no1 = (inst->curAvgMagnEnergy + inst->timeAvgMagnEnergy + 1) >> 1; //Q(-2*stages)
- // Update featureSpecDiff
- if ((tmpU32no1 != inst->timeAvgMagnEnergy) && (inst->featureSpecDiff) &&
- (inst->timeAvgMagnEnergy > 0)) {
- norm32no1 = 0;
- tmpU32no3 = tmpU32no1;
- while (0xFFFF0000 & tmpU32no3) {
- tmpU32no3 >>= 1;
- norm32no1++;
- }
- tmpU32no2 = inst->featureSpecDiff;
- while (0xFFFF0000 & tmpU32no2) {
- tmpU32no2 >>= 1;
- norm32no1++;
- }
- tmpU32no3 = WEBRTC_SPL_UMUL(tmpU32no3, tmpU32no2);
- tmpU32no3 /= inst->timeAvgMagnEnergy;
- if (WebRtcSpl_NormU32(tmpU32no3) < norm32no1) {
- inst->featureSpecDiff = 0x007FFFFF;
- } else {
- inst->featureSpecDiff = WEBRTC_SPL_MIN(0x007FFFFF,
- tmpU32no3 << norm32no1);
- }
- }
-
- inst->timeAvgMagnEnergy = tmpU32no1; // Q(-2*stages)
- inst->curAvgMagnEnergy = 0;
- }
-
- //compute speech/noise probability
- WebRtcNsx_SpeechNoiseProb(inst, nonSpeechProbFinal, priorLocSnr, postLocSnr);
-
- //time-avg parameter for noise update
- gammaNoise = NOISE_UPDATE_Q8; // Q8
-
- maxNoiseU32 = 0;
- postShifts = inst->prevQNoise - qMagn;
- nShifts = inst->prevQMagn - qMagn;
- for (i = 0; i < inst->magnLen; i++) {
- // temporary noise update: use it for speech frames if update value is less than previous
- // the formula has been rewritten into:
- // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i])
-
- if (postShifts < 0) {
- tmpU32no2 = magnU16[i] >> -postShifts; // Q(prevQNoise)
- } else {
- tmpU32no2 = (uint32_t)magnU16[i] << postShifts; // Q(prevQNoise)
- }
- if (prevNoiseU16[i] > tmpU32no2) {
- sign = -1;
- tmpU32no1 = prevNoiseU16[i] - tmpU32no2;
- } else {
- sign = 1;
- tmpU32no1 = tmpU32no2 - prevNoiseU16[i];
- }
- noiseUpdateU32 = inst->prevNoiseU32[i]; // Q(prevQNoise+11)
- tmpU32no3 = 0;
- if ((tmpU32no1) && (nonSpeechProbFinal[i])) {
- // This value will be used later, if gammaNoise changes
- tmpU32no3 = WEBRTC_SPL_UMUL_32_16(tmpU32no1, nonSpeechProbFinal[i]); // Q(prevQNoise+8)
- if (0x7c000000 & tmpU32no3) {
- // Shifting required before multiplication
- tmpU32no2 = (tmpU32no3 >> 5) * gammaNoise; // Q(prevQNoise+11)
- } else {
- // We can do shifting after multiplication
- tmpU32no2 = (tmpU32no3 * gammaNoise) >> 5; // Q(prevQNoise+11)
- }
- if (sign > 0) {
- noiseUpdateU32 += tmpU32no2; // Q(prevQNoise+11)
- } else {
- // This operation is safe. We can never get wrap around, since worst
- // case scenario means magnU16 = 0
- noiseUpdateU32 -= tmpU32no2; // Q(prevQNoise+11)
- }
- }
-
- //increase gamma (i.e., less noise update) for frame likely to be speech
- prevGammaNoise = gammaNoise;
- gammaNoise = NOISE_UPDATE_Q8;
- //time-constant based on speech/noise state
- //increase gamma (i.e., less noise update) for frames likely to be speech
- if (nonSpeechProbFinal[i] < ONE_MINUS_PROB_RANGE_Q8) {
- gammaNoise = GAMMA_NOISE_TRANS_AND_SPEECH_Q8;
- }
-
- if (prevGammaNoise != gammaNoise) {
- // new noise update
- // this line is the same as above, only that the result is stored in a different variable and the gammaNoise
- // has changed
- //
- // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i])
-
- if (0x7c000000 & tmpU32no3) {
- // Shifting required before multiplication
- tmpU32no2 = (tmpU32no3 >> 5) * gammaNoise; // Q(prevQNoise+11)
- } else {
- // We can do shifting after multiplication
- tmpU32no2 = (tmpU32no3 * gammaNoise) >> 5; // Q(prevQNoise+11)
- }
- if (sign > 0) {
- tmpU32no1 = inst->prevNoiseU32[i] + tmpU32no2; // Q(prevQNoise+11)
- } else {
- tmpU32no1 = inst->prevNoiseU32[i] - tmpU32no2; // Q(prevQNoise+11)
- }
- if (noiseUpdateU32 > tmpU32no1) {
- noiseUpdateU32 = tmpU32no1; // Q(prevQNoise+11)
- }
- }
- noiseU32[i] = noiseUpdateU32; // Q(prevQNoise+11)
- if (noiseUpdateU32 > maxNoiseU32) {
- maxNoiseU32 = noiseUpdateU32;
- }
-
- // conservative noise update
- // // original FLOAT code
- // if (prob_speech < PROB_RANGE) {
- // inst->avgMagnPause[i] = inst->avgMagnPause[i] + (1.0 - gamma_pause)*(magn[i] - inst->avgMagnPause[i]);
- // }
-
- tmp32no2 = WEBRTC_SPL_SHIFT_W32(inst->avgMagnPause[i], -nShifts);
- if (nonSpeechProbFinal[i] > ONE_MINUS_PROB_RANGE_Q8) {
- if (nShifts < 0) {
- tmp32no1 = (int32_t)magnU16[i] - tmp32no2; // Q(qMagn)
- tmp32no1 *= ONE_MINUS_GAMMA_PAUSE_Q8; // Q(8+prevQMagn+nShifts)
- tmp32no1 = (tmp32no1 + 128) >> 8; // Q(qMagn).
- } else {
- // In Q(qMagn+nShifts)
- tmp32no1 = ((int32_t)magnU16[i] << nShifts) - inst->avgMagnPause[i];
- tmp32no1 *= ONE_MINUS_GAMMA_PAUSE_Q8; // Q(8+prevQMagn+nShifts)
- tmp32no1 = (tmp32no1 + (128 << nShifts)) >> (8 + nShifts); // Q(qMagn).
- }
- tmp32no2 += tmp32no1; // Q(qMagn)
- }
- inst->avgMagnPause[i] = tmp32no2;
- } // end of frequency loop
-
- norm32no1 = WebRtcSpl_NormU32(maxNoiseU32);
- qNoise = inst->prevQNoise + norm32no1 - 5;
- // done with step 2: noise update
-
- // STEP 3: compute dd update of prior snr and post snr based on new noise estimate
- nShifts = inst->prevQNoise + 11 - qMagn;
- for (i = 0; i < inst->magnLen; i++) {
- // FLOAT code
- // // post and prior SNR
- // curNearSnr = 0.0;
- // if (magn[i] > noise[i])
- // {
- // curNearSnr = magn[i] / (noise[i] + 0.0001) - 1.0;
- // }
- // // DD estimate is sum of two terms: current estimate and previous estimate
- // // directed decision update of snrPrior
- // snrPrior = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * curNearSnr;
- // // gain filter
- // tmpFloat1 = inst->overdrive + snrPrior;
- // tmpFloat2 = snrPrior / tmpFloat1;
- // theFilter[i] = tmpFloat2;
-
- // calculate curNearSnr again, this is necessary because a new noise estimate has been made since then. for the original
- curNearSnr = 0; // Q11
- if (nShifts < 0) {
- // This case is equivalent with magn < noise which implies curNearSnr = 0;
- tmpMagnU32 = (uint32_t)magnU16[i]; // Q(qMagn)
- tmpNoiseU32 = noiseU32[i] << -nShifts; // Q(qMagn)
- } else if (nShifts > 17) {
- tmpMagnU32 = (uint32_t)magnU16[i] << 17; // Q(qMagn+17)
- tmpNoiseU32 = noiseU32[i] >> (nShifts - 17); // Q(qMagn+17)
- } else {
- tmpMagnU32 = (uint32_t)magnU16[i] << nShifts; // Q(qNoise_prev+11)
- tmpNoiseU32 = noiseU32[i]; // Q(qNoise_prev+11)
- }
- if (tmpMagnU32 > tmpNoiseU32) {
- tmpU32no1 = tmpMagnU32 - tmpNoiseU32; // Q(qCur)
- norm32no2 = WEBRTC_SPL_MIN(11, WebRtcSpl_NormU32(tmpU32no1));
- tmpU32no1 <<= norm32no2; // Q(qCur+norm32no2)
- tmpU32no2 = tmpNoiseU32 >> (11 - norm32no2); // Q(qCur+norm32no2-11)
- if (tmpU32no2 > 0) {
- tmpU32no1 /= tmpU32no2; // Q11
- }
- curNearSnr = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
- }
-
- //directed decision update of priorSnr
- // FLOAT
- // priorSnr = DD_PR_SNR * prevNearSnr + (1.0-DD_PR_SNR) * curNearSnr;
-
- tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22
- tmpU32no2 = WEBRTC_SPL_UMUL_32_16(curNearSnr, ONE_MINUS_DD_PR_SNR_Q11); // Q22
- priorSnr = tmpU32no1 + tmpU32no2; // Q22
-
- //gain filter
- tmpU32no1 = inst->overdrive + ((priorSnr + 8192) >> 14); // Q8
- assert(inst->overdrive > 0);
- tmpU16no1 = (priorSnr + tmpU32no1 / 2) / tmpU32no1; // Q14
- inst->noiseSupFilter[i] = WEBRTC_SPL_SAT(16384, tmpU16no1, inst->denoiseBound); // 16384 = Q14(1.0) // Q14
-
- // Weight in the parametric Wiener filter during startup
- if (inst->blockIndex < END_STARTUP_SHORT) {
- // Weight the two suppression filters
- tmpU32no1 = inst->noiseSupFilter[i] * inst->blockIndex;
- tmpU32no2 = noiseSupFilterTmp[i] *
- (END_STARTUP_SHORT - inst->blockIndex);
- tmpU32no1 += tmpU32no2;
- inst->noiseSupFilter[i] = (uint16_t)WebRtcSpl_DivU32U16(tmpU32no1,
- END_STARTUP_SHORT);
- }
- } // end of loop over frequencies
- //done with step3
-
- // save noise and magnitude spectrum for next frame
- inst->prevQNoise = qNoise;
- inst->prevQMagn = qMagn;
- if (norm32no1 > 5) {
- for (i = 0; i < inst->magnLen; i++) {
- inst->prevNoiseU32[i] = noiseU32[i] << (norm32no1 - 5); // Q(qNoise+11)
- inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn)
- }
- } else {
- for (i = 0; i < inst->magnLen; i++) {
- inst->prevNoiseU32[i] = noiseU32[i] >> (5 - norm32no1); // Q(qNoise+11)
- inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn)
- }
- }
-
- WebRtcNsx_DataSynthesis(inst, outFrame[0]);
-#ifdef NS_FILEDEBUG
- if (fwrite(outframe, sizeof(short),
- inst->blockLen10ms, inst->outfile) != inst->blockLen10ms) {
- assert(false);
- }
-#endif
-
- //for H band:
- // only update data buffer, then apply time-domain gain is applied derived from L band
- if (num_bands > 1) {
- // update analysis buffer for H band
- // append new data to buffer FX
- for (i = 0; i < num_high_bands; ++i) {
- memcpy(inst->dataBufHBFX[i], inst->dataBufHBFX[i] + inst->blockLen10ms,
- (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->dataBufHBFX[i]));
- memcpy(inst->dataBufHBFX[i] + inst->anaLen - inst->blockLen10ms,
- speechFrameHB[i], inst->blockLen10ms * sizeof(*inst->dataBufHBFX[i]));
- }
- // range for averaging low band quantities for H band gain
-
- gainTimeDomainHB = 16384; // 16384 = Q14(1.0)
- //average speech prob from low band
- //average filter gain from low band
- //avg over second half (i.e., 4->8kHz) of freq. spectrum
- tmpU32no1 = 0; // Q12
- tmpU16no1 = 0; // Q8
- for (i = inst->anaLen2 - (inst->anaLen2 >> 2); i < inst->anaLen2; i++) {
- tmpU16no1 += nonSpeechProbFinal[i]; // Q8
- tmpU32no1 += (uint32_t)(inst->noiseSupFilter[i]); // Q14
- }
- assert(inst->stages >= 7);
- avgProbSpeechHB = (4096 - (tmpU16no1 >> (inst->stages - 7))); // Q12
- avgFilterGainHB = (int16_t)(tmpU32no1 >> (inst->stages - 3)); // Q14
-
- // // original FLOAT code
- // // gain based on speech probability:
- // avg_prob_speech_tt=(float)2.0*avg_prob_speech-(float)1.0;
- // gain_mod=(float)0.5*((float)1.0+(float)tanh(avg_prob_speech_tt)); // between 0 and 1
-
- // gain based on speech probability:
- // original expression: "0.5 * (1 + tanh(2x-1))"
- // avgProbSpeechHB has been anyway saturated to a value between 0 and 1 so the other cases don't have to be dealt with
- // avgProbSpeechHB and gainModHB are in Q12, 3607 = Q12(0.880615234375) which is a zero point of
- // |0.5 * (1 + tanh(2x-1)) - x| - |0.5 * (1 + tanh(2x-1)) - 0.880615234375| meaning that from that point the error of approximating
- // the expression with f(x) = x would be greater than the error of approximating the expression with f(x) = 0.880615234375
- // error: "|0.5 * (1 + tanh(2x-1)) - x| from x=0 to 0.880615234375" -> http://www.wolframalpha.com/input/?i=|0.5+*+(1+%2B+tanh(2x-1))+-+x|+from+x%3D0+to+0.880615234375
- // and: "|0.5 * (1 + tanh(2x-1)) - 0.880615234375| from x=0.880615234375 to 1" -> http://www.wolframalpha.com/input/?i=+|0.5+*+(1+%2B+tanh(2x-1))+-+0.880615234375|+from+x%3D0.880615234375+to+1
- gainModHB = WEBRTC_SPL_MIN(avgProbSpeechHB, 3607);
-
- // // original FLOAT code
- // //combine gain with low band gain
- // if (avg_prob_speech < (float)0.5) {
- // gain_time_domain_HB=(float)0.5*gain_mod+(float)0.5*avg_filter_gain;
- // }
- // else {
- // gain_time_domain_HB=(float)0.25*gain_mod+(float)0.75*avg_filter_gain;
- // }
-
-
- //combine gain with low band gain
- if (avgProbSpeechHB < 2048) {
- // 2048 = Q12(0.5)
- // the next two lines in float are "gain_time_domain = 0.5 * gain_mod + 0.5 * avg_filter_gain"; Q2(0.5) = 2 equals one left shift
- gainTimeDomainHB = (gainModHB << 1) + (avgFilterGainHB >> 1); // Q14
- } else {
- // "gain_time_domain = 0.25 * gain_mod + 0.75 * agv_filter_gain;"
- gainTimeDomainHB = (int16_t)((3 * avgFilterGainHB) >> 2); // 3 = Q2(0.75)
- gainTimeDomainHB += gainModHB; // Q14
- }
- //make sure gain is within flooring range
- gainTimeDomainHB
- = WEBRTC_SPL_SAT(16384, gainTimeDomainHB, (int16_t)(inst->denoiseBound)); // 16384 = Q14(1.0)
-
-
- //apply gain
- for (i = 0; i < num_high_bands; ++i) {
- for (j = 0; j < inst->blockLen10ms; j++) {
- outFrameHB[i][j] = (int16_t)((gainTimeDomainHB *
- inst->dataBufHBFX[i][j]) >> 14); // Q0
- }
- }
- } // end of H band gain computation
-}
diff --git a/webrtc/modules/audio_processing/ns/nsx_core.h b/webrtc/modules/audio_processing/ns/nsx_core.h
deleted file mode 100644
index f463dbb..0000000
--- a/webrtc/modules/audio_processing/ns/nsx_core.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_
-
-#ifdef NS_FILEDEBUG
-#include <stdio.h>
-#endif
-
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/ns/nsx_defines.h"
-#include "webrtc/typedefs.h"
-
-typedef struct NoiseSuppressionFixedC_ {
- uint32_t fs;
-
- const int16_t* window;
- int16_t analysisBuffer[ANAL_BLOCKL_MAX];
- int16_t synthesisBuffer[ANAL_BLOCKL_MAX];
- uint16_t noiseSupFilter[HALF_ANAL_BLOCKL];
- uint16_t overdrive; /* Q8 */
- uint16_t denoiseBound; /* Q14 */
- const int16_t* factor2Table;
- int16_t noiseEstLogQuantile[SIMULT* HALF_ANAL_BLOCKL];
- int16_t noiseEstDensity[SIMULT* HALF_ANAL_BLOCKL];
- int16_t noiseEstCounter[SIMULT];
- int16_t noiseEstQuantile[HALF_ANAL_BLOCKL];
-
- size_t anaLen;
- size_t anaLen2;
- size_t magnLen;
- int aggrMode;
- int stages;
- int initFlag;
- int gainMap;
-
- int32_t maxLrt;
- int32_t minLrt;
- // Log LRT factor with time-smoothing in Q8.
- int32_t logLrtTimeAvgW32[HALF_ANAL_BLOCKL];
- int32_t featureLogLrt;
- int32_t thresholdLogLrt;
- int16_t weightLogLrt;
-
- uint32_t featureSpecDiff;
- uint32_t thresholdSpecDiff;
- int16_t weightSpecDiff;
-
- uint32_t featureSpecFlat;
- uint32_t thresholdSpecFlat;
- int16_t weightSpecFlat;
-
- // Conservative estimate of noise spectrum.
- int32_t avgMagnPause[HALF_ANAL_BLOCKL];
- uint32_t magnEnergy;
- uint32_t sumMagn;
- uint32_t curAvgMagnEnergy;
- uint32_t timeAvgMagnEnergy;
- uint32_t timeAvgMagnEnergyTmp;
-
- uint32_t whiteNoiseLevel; // Initial noise estimate.
- // Initial magnitude spectrum estimate.
- uint32_t initMagnEst[HALF_ANAL_BLOCKL];
- // Pink noise parameters:
- int32_t pinkNoiseNumerator; // Numerator.
- int32_t pinkNoiseExp; // Power of freq.
- int minNorm; // Smallest normalization factor.
- int zeroInputSignal; // Zero input signal flag.
-
- // Noise spectrum from previous frame.
- uint32_t prevNoiseU32[HALF_ANAL_BLOCKL];
- // Magnitude spectrum from previous frame.
- uint16_t prevMagnU16[HALF_ANAL_BLOCKL];
- // Prior speech/noise probability in Q14.
- int16_t priorNonSpeechProb;
-
- int blockIndex; // Frame index counter.
- // Parameter for updating or estimating thresholds/weights for prior model.
- int modelUpdate;
- int cntThresUpdate;
-
- // Histograms for parameter estimation.
- int16_t histLrt[HIST_PAR_EST];
- int16_t histSpecFlat[HIST_PAR_EST];
- int16_t histSpecDiff[HIST_PAR_EST];
-
- // Quantities for high band estimate.
- int16_t dataBufHBFX[NUM_HIGH_BANDS_MAX][ANAL_BLOCKL_MAX];
-
- int qNoise;
- int prevQNoise;
- int prevQMagn;
- size_t blockLen10ms;
-
- int16_t real[ANAL_BLOCKL_MAX];
- int16_t imag[ANAL_BLOCKL_MAX];
- int32_t energyIn;
- int scaleEnergyIn;
- int normData;
-
- struct RealFFT* real_fft;
-} NoiseSuppressionFixedC;
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/****************************************************************************
- * WebRtcNsx_InitCore(...)
- *
- * This function initializes a noise suppression instance
- *
- * Input:
- * - inst : Instance that should be initialized
- * - fs : Sampling frequency
- *
- * Output:
- * - inst : Initialized instance
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int32_t WebRtcNsx_InitCore(NoiseSuppressionFixedC* inst, uint32_t fs);
-
-/****************************************************************************
- * WebRtcNsx_set_policy_core(...)
- *
- * This changes the aggressiveness of the noise suppression method.
- *
- * Input:
- * - inst : Instance that should be initialized
- * - mode : 0: Mild (6 dB), 1: Medium (10 dB), 2: Aggressive (15 dB)
- *
- * Output:
- * - inst : Initialized instance
- *
- * Return value : 0 - Ok
- * -1 - Error
- */
-int WebRtcNsx_set_policy_core(NoiseSuppressionFixedC* inst, int mode);
-
-/****************************************************************************
- * WebRtcNsx_ProcessCore
- *
- * Do noise suppression.
- *
- * Input:
- * - inst : Instance that should be initialized
- * - inFrame : Input speech frame for each band
- * - num_bands : Number of bands
- *
- * Output:
- * - inst : Updated instance
- * - outFrame : Output speech frame for each band
- */
-void WebRtcNsx_ProcessCore(NoiseSuppressionFixedC* inst,
- const short* const* inFrame,
- int num_bands,
- short* const* outFrame);
-
-/****************************************************************************
- * Some function pointers, for internal functions shared by ARM NEON and
- * generic C code.
- */
-// Noise Estimation.
-typedef void (*NoiseEstimation)(NoiseSuppressionFixedC* inst,
- uint16_t* magn,
- uint32_t* noise,
- int16_t* q_noise);
-extern NoiseEstimation WebRtcNsx_NoiseEstimation;
-
-// Filter the data in the frequency domain, and create spectrum.
-typedef void (*PrepareSpectrum)(NoiseSuppressionFixedC* inst,
- int16_t* freq_buff);
-extern PrepareSpectrum WebRtcNsx_PrepareSpectrum;
-
-// For the noise supression process, synthesis, read out fully processed
-// segment, and update synthesis buffer.
-typedef void (*SynthesisUpdate)(NoiseSuppressionFixedC* inst,
- int16_t* out_frame,
- int16_t gain_factor);
-extern SynthesisUpdate WebRtcNsx_SynthesisUpdate;
-
-// Update analysis buffer for lower band, and window data before FFT.
-typedef void (*AnalysisUpdate)(NoiseSuppressionFixedC* inst,
- int16_t* out,
- int16_t* new_speech);
-extern AnalysisUpdate WebRtcNsx_AnalysisUpdate;
-
-// Denormalize the real-valued signal |in|, the output from inverse FFT.
-typedef void (*Denormalize)(NoiseSuppressionFixedC* inst,
- int16_t* in,
- int factor);
-extern Denormalize WebRtcNsx_Denormalize;
-
-// Normalize the real-valued signal |in|, the input to forward FFT.
-typedef void (*NormalizeRealBuffer)(NoiseSuppressionFixedC* inst,
- const int16_t* in,
- int16_t* out);
-extern NormalizeRealBuffer WebRtcNsx_NormalizeRealBuffer;
-
-// Compute speech/noise probability.
-// Intended to be private.
-void WebRtcNsx_SpeechNoiseProb(NoiseSuppressionFixedC* inst,
- uint16_t* nonSpeechProbFinal,
- uint32_t* priorLocSnr,
- uint32_t* postLocSnr);
-
-#if (defined WEBRTC_DETECT_NEON || defined WEBRTC_HAS_NEON)
-// For the above function pointers, functions for generic platforms are declared
-// and defined as static in file nsx_core.c, while those for ARM Neon platforms
-// are declared below and defined in file nsx_core_neon.c.
-void WebRtcNsx_NoiseEstimationNeon(NoiseSuppressionFixedC* inst,
- uint16_t* magn,
- uint32_t* noise,
- int16_t* q_noise);
-void WebRtcNsx_SynthesisUpdateNeon(NoiseSuppressionFixedC* inst,
- int16_t* out_frame,
- int16_t gain_factor);
-void WebRtcNsx_AnalysisUpdateNeon(NoiseSuppressionFixedC* inst,
- int16_t* out,
- int16_t* new_speech);
-void WebRtcNsx_PrepareSpectrumNeon(NoiseSuppressionFixedC* inst,
- int16_t* freq_buff);
-#endif
-
-#if defined(MIPS32_LE)
-// For the above function pointers, functions for generic platforms are declared
-// and defined as static in file nsx_core.c, while those for MIPS platforms
-// are declared below and defined in file nsx_core_mips.c.
-void WebRtcNsx_SynthesisUpdate_mips(NoiseSuppressionFixedC* inst,
- int16_t* out_frame,
- int16_t gain_factor);
-void WebRtcNsx_AnalysisUpdate_mips(NoiseSuppressionFixedC* inst,
- int16_t* out,
- int16_t* new_speech);
-void WebRtcNsx_PrepareSpectrum_mips(NoiseSuppressionFixedC* inst,
- int16_t* freq_buff);
-void WebRtcNsx_NormalizeRealBuffer_mips(NoiseSuppressionFixedC* inst,
- const int16_t* in,
- int16_t* out);
-#if defined(MIPS_DSP_R1_LE)
-void WebRtcNsx_Denormalize_mips(NoiseSuppressionFixedC* inst,
- int16_t* in,
- int factor);
-#endif
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_
diff --git a/webrtc/modules/audio_processing/ns/nsx_core_c.c b/webrtc/modules/audio_processing/ns/nsx_core_c.c
deleted file mode 100644
index 14322d3..0000000
--- a/webrtc/modules/audio_processing/ns/nsx_core_c.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <assert.h>
-
-#include "webrtc/modules/audio_processing/ns/include/noise_suppression_x.h"
-#include "webrtc/modules/audio_processing/ns/nsx_core.h"
-#include "webrtc/modules/audio_processing/ns/nsx_defines.h"
-
-static const int16_t kIndicatorTable[17] = {
- 0, 2017, 3809, 5227, 6258, 6963, 7424, 7718,
- 7901, 8014, 8084, 8126, 8152, 8168, 8177, 8183, 8187
-};
-
-// Compute speech/noise probability
-// speech/noise probability is returned in: probSpeechFinal
-//snrLocPrior is the prior SNR for each frequency (in Q11)
-//snrLocPost is the post SNR for each frequency (in Q11)
-void WebRtcNsx_SpeechNoiseProb(NoiseSuppressionFixedC* inst,
- uint16_t* nonSpeechProbFinal,
- uint32_t* priorLocSnr,
- uint32_t* postLocSnr) {
- uint32_t zeros, num, den, tmpU32no1, tmpU32no2, tmpU32no3;
- int32_t invLrtFX, indPriorFX, tmp32, tmp32no1, tmp32no2, besselTmpFX32;
- int32_t frac32, logTmp;
- int32_t logLrtTimeAvgKsumFX;
- int16_t indPriorFX16;
- int16_t tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac, intPart;
- size_t i;
- int normTmp, normTmp2, nShifts;
-
- // compute feature based on average LR factor
- // this is the average over all frequencies of the smooth log LRT
- logLrtTimeAvgKsumFX = 0;
- for (i = 0; i < inst->magnLen; i++) {
- besselTmpFX32 = (int32_t)postLocSnr[i]; // Q11
- normTmp = WebRtcSpl_NormU32(postLocSnr[i]);
- num = postLocSnr[i] << normTmp; // Q(11+normTmp)
- if (normTmp > 10) {
- den = priorLocSnr[i] << (normTmp - 11); // Q(normTmp)
- } else {
- den = priorLocSnr[i] >> (11 - normTmp); // Q(normTmp)
- }
- if (den > 0) {
- besselTmpFX32 -= num / den; // Q11
- } else {
- besselTmpFX32 = 0;
- }
-
- // inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - log(snrLocPrior)
- // - inst->logLrtTimeAvg[i]);
- // Here, LRT_TAVG = 0.5
- zeros = WebRtcSpl_NormU32(priorLocSnr[i]);
- frac32 = (int32_t)(((priorLocSnr[i] << zeros) & 0x7FFFFFFF) >> 19);
- tmp32 = (frac32 * frac32 * -43) >> 19;
- tmp32 += ((int16_t)frac32 * 5412) >> 12;
- frac32 = tmp32 + 37;
- // tmp32 = log2(priorLocSnr[i])
- tmp32 = (int32_t)(((31 - zeros) << 12) + frac32) - (11 << 12); // Q12
- logTmp = (tmp32 * 178) >> 8; // log2(priorLocSnr[i])*log(2)
- // tmp32no1 = LRT_TAVG * (log(snrLocPrior) + inst->logLrtTimeAvg[i]) in Q12.
- tmp32no1 = (logTmp + inst->logLrtTimeAvgW32[i]) / 2;
- inst->logLrtTimeAvgW32[i] += (besselTmpFX32 - tmp32no1); // Q12
-
- logLrtTimeAvgKsumFX += inst->logLrtTimeAvgW32[i]; // Q12
- }
- inst->featureLogLrt = (logLrtTimeAvgKsumFX * BIN_SIZE_LRT) >>
- (inst->stages + 11);
-
- // done with computation of LR factor
-
- //
- //compute the indicator functions
- //
-
- // average LRT feature
- // FLOAT code
- // indicator0 = 0.5 * (tanh(widthPrior *
- // (logLrtTimeAvgKsum - threshPrior0)) + 1.0);
- tmpIndFX = 16384; // Q14(1.0)
- tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12
- nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5;
- //use larger width in tanh map for pause regions
- if (tmp32no1 < 0) {
- tmpIndFX = 0;
- tmp32no1 = -tmp32no1;
- //widthPrior = widthPrior * 2.0;
- nShifts++;
- }
- tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14
- // compute indicator function: sigmoid map
- tableIndex = (int16_t)(tmp32no1 >> 14);
- if ((tableIndex < 16) && (tableIndex >= 0)) {
- tmp16no2 = kIndicatorTable[tableIndex];
- tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
- frac = (int16_t)(tmp32no1 & 0x00003fff); // Q14
- tmp16no2 += (int16_t)((tmp16no1 * frac) >> 14);
- if (tmpIndFX == 0) {
- tmpIndFX = 8192 - tmp16no2; // Q14
- } else {
- tmpIndFX = 8192 + tmp16no2; // Q14
- }
- }
- indPriorFX = inst->weightLogLrt * tmpIndFX; // 6*Q14
-
- //spectral flatness feature
- if (inst->weightSpecFlat) {
- tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10
- tmpIndFX = 16384; // Q14(1.0)
- //use larger width in tanh map for pause regions
- tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10
- nShifts = 4;
- if (inst->thresholdSpecFlat < tmpU32no1) {
- tmpIndFX = 0;
- tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat;
- //widthPrior = widthPrior * 2.0;
- nShifts++;
- }
- tmpU32no1 = WebRtcSpl_DivU32U16(tmpU32no2 << nShifts, 25); // Q14
- // compute indicator function: sigmoid map
- // FLOAT code
- // indicator1 = 0.5 * (tanh(sgnMap * widthPrior *
- // (threshPrior1 - tmpFloat1)) + 1.0);
- tableIndex = (int16_t)(tmpU32no1 >> 14);
- if (tableIndex < 16) {
- tmp16no2 = kIndicatorTable[tableIndex];
- tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
- frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14
- tmp16no2 += (int16_t)((tmp16no1 * frac) >> 14);
- if (tmpIndFX) {
- tmpIndFX = 8192 + tmp16no2; // Q14
- } else {
- tmpIndFX = 8192 - tmp16no2; // Q14
- }
- }
- indPriorFX += inst->weightSpecFlat * tmpIndFX; // 6*Q14
- }
-
- //for template spectral-difference
- if (inst->weightSpecDiff) {
- tmpU32no1 = 0;
- if (inst->featureSpecDiff) {
- normTmp = WEBRTC_SPL_MIN(20 - inst->stages,
- WebRtcSpl_NormU32(inst->featureSpecDiff));
- assert(normTmp >= 0);
- tmpU32no1 = inst->featureSpecDiff << normTmp; // Q(normTmp-2*stages)
- tmpU32no2 = inst->timeAvgMagnEnergy >> (20 - inst->stages - normTmp);
- if (tmpU32no2 > 0) {
- // Q(20 - inst->stages)
- tmpU32no1 /= tmpU32no2;
- } else {
- tmpU32no1 = (uint32_t)(0x7fffffff);
- }
- }
- tmpU32no3 = (inst->thresholdSpecDiff << 17) / 25;
- tmpU32no2 = tmpU32no1 - tmpU32no3;
- nShifts = 1;
- tmpIndFX = 16384; // Q14(1.0)
- //use larger width in tanh map for pause regions
- if (tmpU32no2 & 0x80000000) {
- tmpIndFX = 0;
- tmpU32no2 = tmpU32no3 - tmpU32no1;
- //widthPrior = widthPrior * 2.0;
- nShifts--;
- }
- tmpU32no1 = tmpU32no2 >> nShifts;
- // compute indicator function: sigmoid map
- /* FLOAT code
- indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0);
- */
- tableIndex = (int16_t)(tmpU32no1 >> 14);
- if (tableIndex < 16) {
- tmp16no2 = kIndicatorTable[tableIndex];
- tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
- frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14
- tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- tmp16no1, frac, 14);
- if (tmpIndFX) {
- tmpIndFX = 8192 + tmp16no2;
- } else {
- tmpIndFX = 8192 - tmp16no2;
- }
- }
- indPriorFX += inst->weightSpecDiff * tmpIndFX; // 6*Q14
- }
-
- //combine the indicator function with the feature weights
- // FLOAT code
- // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 *
- // indicator1 + weightIndPrior2 * indicator2);
- indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14
- // done with computing indicator function
-
- //compute the prior probability
- // FLOAT code
- // inst->priorNonSpeechProb += PRIOR_UPDATE *
- // (indPriorNonSpeech - inst->priorNonSpeechProb);
- tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14
- inst->priorNonSpeechProb += (int16_t)((PRIOR_UPDATE_Q14 * tmp16) >> 14);
-
- //final speech probability: combine prior model with LR factor:
-
- memset(nonSpeechProbFinal, 0, sizeof(uint16_t) * inst->magnLen);
-
- if (inst->priorNonSpeechProb > 0) {
- for (i = 0; i < inst->magnLen; i++) {
- // FLOAT code
- // invLrt = exp(inst->logLrtTimeAvg[i]);
- // invLrt = inst->priorSpeechProb * invLrt;
- // nonSpeechProbFinal[i] = (1.0 - inst->priorSpeechProb) /
- // (1.0 - inst->priorSpeechProb + invLrt);
- // invLrt = (1.0 - inst->priorNonSpeechProb) * invLrt;
- // nonSpeechProbFinal[i] = inst->priorNonSpeechProb /
- // (inst->priorNonSpeechProb + invLrt);
- if (inst->logLrtTimeAvgW32[i] < 65300) {
- tmp32no1 = (inst->logLrtTimeAvgW32[i] * 23637) >> 14; // Q12
- intPart = (int16_t)(tmp32no1 >> 12);
- if (intPart < -8) {
- intPart = -8;
- }
- frac = (int16_t)(tmp32no1 & 0x00000fff); // Q12
-
- // Quadratic approximation of 2^frac
- tmp32no2 = (frac * frac * 44) >> 19; // Q12.
- tmp32no2 += (frac * 84) >> 7; // Q12
- invLrtFX = (1 << (8 + intPart)) +
- WEBRTC_SPL_SHIFT_W32(tmp32no2, intPart - 4); // Q8
-
- normTmp = WebRtcSpl_NormW32(invLrtFX);
- normTmp2 = WebRtcSpl_NormW16((16384 - inst->priorNonSpeechProb));
- if (normTmp + normTmp2 >= 7) {
- if (normTmp + normTmp2 < 15) {
- invLrtFX >>= 15 - normTmp2 - normTmp;
- // Q(normTmp+normTmp2-7)
- tmp32no1 = invLrtFX * (16384 - inst->priorNonSpeechProb);
- // Q(normTmp+normTmp2+7)
- invLrtFX = WEBRTC_SPL_SHIFT_W32(tmp32no1, 7 - normTmp - normTmp2);
- // Q14
- } else {
- tmp32no1 = invLrtFX * (16384 - inst->priorNonSpeechProb);
- // Q22
- invLrtFX = tmp32no1 >> 8; // Q14.
- }
-
- tmp32no1 = (int32_t)inst->priorNonSpeechProb << 8; // Q22
-
- nonSpeechProbFinal[i] = tmp32no1 /
- (inst->priorNonSpeechProb + invLrtFX); // Q8
- }
- }
- }
- }
-}
-
diff --git a/webrtc/modules/audio_processing/ns/nsx_core_mips.c b/webrtc/modules/audio_processing/ns/nsx_core_mips.c
deleted file mode 100644
index d99be87..0000000
--- a/webrtc/modules/audio_processing/ns/nsx_core_mips.c
+++ /dev/null
@@ -1,1002 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <assert.h>
-#include <string.h>
-
-#include "webrtc/modules/audio_processing/ns/include/noise_suppression_x.h"
-#include "webrtc/modules/audio_processing/ns/nsx_core.h"
-
-static const int16_t kIndicatorTable[17] = {
- 0, 2017, 3809, 5227, 6258, 6963, 7424, 7718,
- 7901, 8014, 8084, 8126, 8152, 8168, 8177, 8183, 8187
-};
-
-// Compute speech/noise probability
-// speech/noise probability is returned in: probSpeechFinal
-//snrLocPrior is the prior SNR for each frequency (in Q11)
-//snrLocPost is the post SNR for each frequency (in Q11)
-void WebRtcNsx_SpeechNoiseProb(NoiseSuppressionFixedC* inst,
- uint16_t* nonSpeechProbFinal,
- uint32_t* priorLocSnr,
- uint32_t* postLocSnr) {
- uint32_t tmpU32no1, tmpU32no2, tmpU32no3;
- int32_t indPriorFX, tmp32no1;
- int32_t logLrtTimeAvgKsumFX;
- int16_t indPriorFX16;
- int16_t tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac;
- size_t i;
- int normTmp, nShifts;
-
- int32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9;
- int32_t const_max = 0x7fffffff;
- int32_t const_neg43 = -43;
- int32_t const_5412 = 5412;
- int32_t const_11rsh12 = (11 << 12);
- int32_t const_178 = 178;
-
-
- // compute feature based on average LR factor
- // this is the average over all frequencies of the smooth log LRT
- logLrtTimeAvgKsumFX = 0;
- for (i = 0; i < inst->magnLen; i++) {
- r0 = postLocSnr[i]; // Q11
- r1 = priorLocSnr[i];
- r2 = inst->logLrtTimeAvgW32[i];
-
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "clz %[r3], %[r0] \n\t"
- "clz %[r5], %[r1] \n\t"
- "slti %[r4], %[r3], 32 \n\t"
- "slti %[r6], %[r5], 32 \n\t"
- "movz %[r3], $0, %[r4] \n\t"
- "movz %[r5], $0, %[r6] \n\t"
- "slti %[r4], %[r3], 11 \n\t"
- "addiu %[r6], %[r3], -11 \n\t"
- "neg %[r7], %[r6] \n\t"
- "sllv %[r6], %[r1], %[r6] \n\t"
- "srav %[r7], %[r1], %[r7] \n\t"
- "movn %[r6], %[r7], %[r4] \n\t"
- "sllv %[r1], %[r1], %[r5] \n\t"
- "and %[r1], %[r1], %[const_max] \n\t"
- "sra %[r1], %[r1], 19 \n\t"
- "mul %[r7], %[r1], %[r1] \n\t"
- "sllv %[r3], %[r0], %[r3] \n\t"
- "divu %[r8], %[r3], %[r6] \n\t"
- "slti %[r6], %[r6], 1 \n\t"
- "mul %[r7], %[r7], %[const_neg43] \n\t"
- "sra %[r7], %[r7], 19 \n\t"
- "movz %[r3], %[r8], %[r6] \n\t"
- "subu %[r0], %[r0], %[r3] \n\t"
- "movn %[r0], $0, %[r6] \n\t"
- "mul %[r1], %[r1], %[const_5412] \n\t"
- "sra %[r1], %[r1], 12 \n\t"
- "addu %[r7], %[r7], %[r1] \n\t"
- "addiu %[r1], %[r7], 37 \n\t"
- "addiu %[r5], %[r5], -31 \n\t"
- "neg %[r5], %[r5] \n\t"
- "sll %[r5], %[r5], 12 \n\t"
- "addu %[r5], %[r5], %[r1] \n\t"
- "subu %[r7], %[r5], %[const_11rsh12] \n\t"
- "mul %[r7], %[r7], %[const_178] \n\t"
- "sra %[r7], %[r7], 8 \n\t"
- "addu %[r7], %[r7], %[r2] \n\t"
- "sra %[r7], %[r7], 1 \n\t"
- "subu %[r2], %[r2], %[r7] \n\t"
- "addu %[r2], %[r2], %[r0] \n\t"
- ".set pop \n\t"
- : [r0] "+r" (r0), [r1] "+r" (r1), [r2] "+r" (r2),
- [r3] "=&r" (r3), [r4] "=&r" (r4), [r5] "=&r" (r5),
- [r6] "=&r" (r6), [r7] "=&r" (r7), [r8] "=&r" (r8)
- : [const_max] "r" (const_max), [const_neg43] "r" (const_neg43),
- [const_5412] "r" (const_5412), [const_11rsh12] "r" (const_11rsh12),
- [const_178] "r" (const_178)
- : "hi", "lo"
- );
- inst->logLrtTimeAvgW32[i] = r2;
- logLrtTimeAvgKsumFX += r2;
- }
-
- inst->featureLogLrt = (logLrtTimeAvgKsumFX * BIN_SIZE_LRT) >>
- (inst->stages + 11);
-
- // done with computation of LR factor
-
- //
- // compute the indicator functions
- //
-
- // average LRT feature
- // FLOAT code
- // indicator0 = 0.5 * (tanh(widthPrior *
- // (logLrtTimeAvgKsum - threshPrior0)) + 1.0);
- tmpIndFX = 16384; // Q14(1.0)
- tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12
- nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5;
- //use larger width in tanh map for pause regions
- if (tmp32no1 < 0) {
- tmpIndFX = 0;
- tmp32no1 = -tmp32no1;
- //widthPrior = widthPrior * 2.0;
- nShifts++;
- }
- tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14
- // compute indicator function: sigmoid map
- tableIndex = (int16_t)(tmp32no1 >> 14);
- if ((tableIndex < 16) && (tableIndex >= 0)) {
- tmp16no2 = kIndicatorTable[tableIndex];
- tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
- frac = (int16_t)(tmp32no1 & 0x00003fff); // Q14
- tmp16no2 += (int16_t)((tmp16no1 * frac) >> 14);
- if (tmpIndFX == 0) {
- tmpIndFX = 8192 - tmp16no2; // Q14
- } else {
- tmpIndFX = 8192 + tmp16no2; // Q14
- }
- }
- indPriorFX = inst->weightLogLrt * tmpIndFX; // 6*Q14
-
- //spectral flatness feature
- if (inst->weightSpecFlat) {
- tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10
- tmpIndFX = 16384; // Q14(1.0)
- //use larger width in tanh map for pause regions
- tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10
- nShifts = 4;
- if (inst->thresholdSpecFlat < tmpU32no1) {
- tmpIndFX = 0;
- tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat;
- //widthPrior = widthPrior * 2.0;
- nShifts++;
- }
- tmpU32no1 = WebRtcSpl_DivU32U16(tmpU32no2 << nShifts, 25); //Q14
- // compute indicator function: sigmoid map
- // FLOAT code
- // indicator1 = 0.5 * (tanh(sgnMap * widthPrior *
- // (threshPrior1 - tmpFloat1)) + 1.0);
- tableIndex = (int16_t)(tmpU32no1 >> 14);
- if (tableIndex < 16) {
- tmp16no2 = kIndicatorTable[tableIndex];
- tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
- frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14
- tmp16no2 += (int16_t)((tmp16no1 * frac) >> 14);
- if (tmpIndFX) {
- tmpIndFX = 8192 + tmp16no2; // Q14
- } else {
- tmpIndFX = 8192 - tmp16no2; // Q14
- }
- }
- indPriorFX += inst->weightSpecFlat * tmpIndFX; // 6*Q14
- }
-
- //for template spectral-difference
- if (inst->weightSpecDiff) {
- tmpU32no1 = 0;
- if (inst->featureSpecDiff) {
- normTmp = WEBRTC_SPL_MIN(20 - inst->stages,
- WebRtcSpl_NormU32(inst->featureSpecDiff));
- assert(normTmp >= 0);
- tmpU32no1 = inst->featureSpecDiff << normTmp; // Q(normTmp-2*stages)
- tmpU32no2 = inst->timeAvgMagnEnergy >> (20 - inst->stages - normTmp);
- if (tmpU32no2 > 0) {
- // Q(20 - inst->stages)
- tmpU32no1 /= tmpU32no2;
- } else {
- tmpU32no1 = (uint32_t)(0x7fffffff);
- }
- }
- tmpU32no3 = (inst->thresholdSpecDiff << 17) / 25;
- tmpU32no2 = tmpU32no1 - tmpU32no3;
- nShifts = 1;
- tmpIndFX = 16384; // Q14(1.0)
- //use larger width in tanh map for pause regions
- if (tmpU32no2 & 0x80000000) {
- tmpIndFX = 0;
- tmpU32no2 = tmpU32no3 - tmpU32no1;
- //widthPrior = widthPrior * 2.0;
- nShifts--;
- }
- tmpU32no1 = tmpU32no2 >> nShifts;
- // compute indicator function: sigmoid map
- /* FLOAT code
- indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0);
- */
- tableIndex = (int16_t)(tmpU32no1 >> 14);
- if (tableIndex < 16) {
- tmp16no2 = kIndicatorTable[tableIndex];
- tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
- frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14
- tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- tmp16no1, frac, 14);
- if (tmpIndFX) {
- tmpIndFX = 8192 + tmp16no2;
- } else {
- tmpIndFX = 8192 - tmp16no2;
- }
- }
- indPriorFX += inst->weightSpecDiff * tmpIndFX; // 6*Q14
- }
-
- //combine the indicator function with the feature weights
- // FLOAT code
- // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 *
- // indicator1 + weightIndPrior2 * indicator2);
- indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14
- // done with computing indicator function
-
- //compute the prior probability
- // FLOAT code
- // inst->priorNonSpeechProb += PRIOR_UPDATE *
- // (indPriorNonSpeech - inst->priorNonSpeechProb);
- tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14
- inst->priorNonSpeechProb += (int16_t)((PRIOR_UPDATE_Q14 * tmp16) >> 14);
-
- //final speech probability: combine prior model with LR factor:
-
- memset(nonSpeechProbFinal, 0, sizeof(uint16_t) * inst->magnLen);
-
- if (inst->priorNonSpeechProb > 0) {
- r0 = inst->priorNonSpeechProb;
- r1 = 16384 - r0;
- int32_t const_23637 = 23637;
- int32_t const_44 = 44;
- int32_t const_84 = 84;
- int32_t const_1 = 1;
- int32_t const_neg8 = -8;
- for (i = 0; i < inst->magnLen; i++) {
- r2 = inst->logLrtTimeAvgW32[i];
- if (r2 < 65300) {
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "mul %[r2], %[r2], %[const_23637] \n\t"
- "sll %[r6], %[r1], 16 \n\t"
- "clz %[r7], %[r6] \n\t"
- "clo %[r8], %[r6] \n\t"
- "slt %[r9], %[r6], $0 \n\t"
- "movn %[r7], %[r8], %[r9] \n\t"
- "sra %[r2], %[r2], 14 \n\t"
- "andi %[r3], %[r2], 0xfff \n\t"
- "mul %[r4], %[r3], %[r3] \n\t"
- "mul %[r3], %[r3], %[const_84] \n\t"
- "sra %[r2], %[r2], 12 \n\t"
- "slt %[r5], %[r2], %[const_neg8] \n\t"
- "movn %[r2], %[const_neg8], %[r5] \n\t"
- "mul %[r4], %[r4], %[const_44] \n\t"
- "sra %[r3], %[r3], 7 \n\t"
- "addiu %[r7], %[r7], -1 \n\t"
- "slti %[r9], %[r7], 31 \n\t"
- "movz %[r7], $0, %[r9] \n\t"
- "sra %[r4], %[r4], 19 \n\t"
- "addu %[r4], %[r4], %[r3] \n\t"
- "addiu %[r3], %[r2], 8 \n\t"
- "addiu %[r2], %[r2], -4 \n\t"
- "neg %[r5], %[r2] \n\t"
- "sllv %[r6], %[r4], %[r2] \n\t"
- "srav %[r5], %[r4], %[r5] \n\t"
- "slt %[r2], %[r2], $0 \n\t"
- "movn %[r6], %[r5], %[r2] \n\t"
- "sllv %[r3], %[const_1], %[r3] \n\t"
- "addu %[r2], %[r3], %[r6] \n\t"
- "clz %[r4], %[r2] \n\t"
- "clo %[r5], %[r2] \n\t"
- "slt %[r8], %[r2], $0 \n\t"
- "movn %[r4], %[r5], %[r8] \n\t"
- "addiu %[r4], %[r4], -1 \n\t"
- "slt %[r5], $0, %[r2] \n\t"
- "or %[r5], %[r5], %[r7] \n\t"
- "movz %[r4], $0, %[r5] \n\t"
- "addiu %[r6], %[r7], -7 \n\t"
- "addu %[r6], %[r6], %[r4] \n\t"
- "bltz %[r6], 1f \n\t"
- " nop \n\t"
- "addiu %[r4], %[r6], -8 \n\t"
- "neg %[r3], %[r4] \n\t"
- "srav %[r5], %[r2], %[r3] \n\t"
- "mul %[r5], %[r5], %[r1] \n\t"
- "mul %[r2], %[r2], %[r1] \n\t"
- "slt %[r4], %[r4], $0 \n\t"
- "srav %[r5], %[r5], %[r6] \n\t"
- "sra %[r2], %[r2], 8 \n\t"
- "movn %[r2], %[r5], %[r4] \n\t"
- "sll %[r3], %[r0], 8 \n\t"
- "addu %[r2], %[r0], %[r2] \n\t"
- "divu %[r3], %[r3], %[r2] \n\t"
- "1: \n\t"
- ".set pop \n\t"
- : [r2] "+r" (r2), [r3] "=&r" (r3), [r4] "=&r" (r4),
- [r5] "=&r" (r5), [r6] "=&r" (r6), [r7] "=&r" (r7),
- [r8] "=&r" (r8), [r9] "=&r" (r9)
- : [r0] "r" (r0), [r1] "r" (r1), [const_23637] "r" (const_23637),
- [const_neg8] "r" (const_neg8), [const_84] "r" (const_84),
- [const_1] "r" (const_1), [const_44] "r" (const_44)
- : "hi", "lo"
- );
- nonSpeechProbFinal[i] = r3;
- }
- }
- }
-}
-
-// Update analysis buffer for lower band, and window data before FFT.
-void WebRtcNsx_AnalysisUpdate_mips(NoiseSuppressionFixedC* inst,
- int16_t* out,
- int16_t* new_speech) {
- int iters, after;
- int anaLen = (int)inst->anaLen;
- int *window = (int*)inst->window;
- int *anaBuf = (int*)inst->analysisBuffer;
- int *outBuf = (int*)out;
- int r0, r1, r2, r3, r4, r5, r6, r7;
-#if defined(MIPS_DSP_R1_LE)
- int r8;
-#endif
-
- // For lower band update analysis buffer.
- memcpy(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms,
- (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->analysisBuffer));
- memcpy(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms, new_speech,
- inst->blockLen10ms * sizeof(*inst->analysisBuffer));
-
- // Window data before FFT.
-#if defined(MIPS_DSP_R1_LE)
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "sra %[iters], %[anaLen], 3 \n\t"
- "1: \n\t"
- "blez %[iters], 2f \n\t"
- " nop \n\t"
- "lw %[r0], 0(%[window]) \n\t"
- "lw %[r1], 0(%[anaBuf]) \n\t"
- "lw %[r2], 4(%[window]) \n\t"
- "lw %[r3], 4(%[anaBuf]) \n\t"
- "lw %[r4], 8(%[window]) \n\t"
- "lw %[r5], 8(%[anaBuf]) \n\t"
- "lw %[r6], 12(%[window]) \n\t"
- "lw %[r7], 12(%[anaBuf]) \n\t"
- "muleq_s.w.phl %[r8], %[r0], %[r1] \n\t"
- "muleq_s.w.phr %[r0], %[r0], %[r1] \n\t"
- "muleq_s.w.phl %[r1], %[r2], %[r3] \n\t"
- "muleq_s.w.phr %[r2], %[r2], %[r3] \n\t"
- "muleq_s.w.phl %[r3], %[r4], %[r5] \n\t"
- "muleq_s.w.phr %[r4], %[r4], %[r5] \n\t"
- "muleq_s.w.phl %[r5], %[r6], %[r7] \n\t"
- "muleq_s.w.phr %[r6], %[r6], %[r7] \n\t"
-#if defined(MIPS_DSP_R2_LE)
- "precr_sra_r.ph.w %[r8], %[r0], 15 \n\t"
- "precr_sra_r.ph.w %[r1], %[r2], 15 \n\t"
- "precr_sra_r.ph.w %[r3], %[r4], 15 \n\t"
- "precr_sra_r.ph.w %[r5], %[r6], 15 \n\t"
- "sw %[r8], 0(%[outBuf]) \n\t"
- "sw %[r1], 4(%[outBuf]) \n\t"
- "sw %[r3], 8(%[outBuf]) \n\t"
- "sw %[r5], 12(%[outBuf]) \n\t"
-#else
- "shra_r.w %[r8], %[r8], 15 \n\t"
- "shra_r.w %[r0], %[r0], 15 \n\t"
- "shra_r.w %[r1], %[r1], 15 \n\t"
- "shra_r.w %[r2], %[r2], 15 \n\t"
- "shra_r.w %[r3], %[r3], 15 \n\t"
- "shra_r.w %[r4], %[r4], 15 \n\t"
- "shra_r.w %[r5], %[r5], 15 \n\t"
- "shra_r.w %[r6], %[r6], 15 \n\t"
- "sll %[r0], %[r0], 16 \n\t"
- "sll %[r2], %[r2], 16 \n\t"
- "sll %[r4], %[r4], 16 \n\t"
- "sll %[r6], %[r6], 16 \n\t"
- "packrl.ph %[r0], %[r8], %[r0] \n\t"
- "packrl.ph %[r2], %[r1], %[r2] \n\t"
- "packrl.ph %[r4], %[r3], %[r4] \n\t"
- "packrl.ph %[r6], %[r5], %[r6] \n\t"
- "sw %[r0], 0(%[outBuf]) \n\t"
- "sw %[r2], 4(%[outBuf]) \n\t"
- "sw %[r4], 8(%[outBuf]) \n\t"
- "sw %[r6], 12(%[outBuf]) \n\t"
-#endif
- "addiu %[window], %[window], 16 \n\t"
- "addiu %[anaBuf], %[anaBuf], 16 \n\t"
- "addiu %[outBuf], %[outBuf], 16 \n\t"
- "b 1b \n\t"
- " addiu %[iters], %[iters], -1 \n\t"
- "2: \n\t"
- "andi %[after], %[anaLen], 7 \n\t"
- "3: \n\t"
- "blez %[after], 4f \n\t"
- " nop \n\t"
- "lh %[r0], 0(%[window]) \n\t"
- "lh %[r1], 0(%[anaBuf]) \n\t"
- "mul %[r0], %[r0], %[r1] \n\t"
- "addiu %[window], %[window], 2 \n\t"
- "addiu %[anaBuf], %[anaBuf], 2 \n\t"
- "addiu %[outBuf], %[outBuf], 2 \n\t"
- "shra_r.w %[r0], %[r0], 14 \n\t"
- "sh %[r0], -2(%[outBuf]) \n\t"
- "b 3b \n\t"
- " addiu %[after], %[after], -1 \n\t"
- "4: \n\t"
- ".set pop \n\t"
- : [r0] "=&r" (r0), [r1] "=&r" (r1), [r2] "=&r" (r2),
- [r3] "=&r" (r3), [r4] "=&r" (r4), [r5] "=&r" (r5),
- [r6] "=&r" (r6), [r7] "=&r" (r7), [r8] "=&r" (r8),
- [iters] "=&r" (iters), [after] "=&r" (after),
- [window] "+r" (window),[anaBuf] "+r" (anaBuf),
- [outBuf] "+r" (outBuf)
- : [anaLen] "r" (anaLen)
- : "memory", "hi", "lo"
- );
-#else
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "sra %[iters], %[anaLen], 2 \n\t"
- "1: \n\t"
- "blez %[iters], 2f \n\t"
- " nop \n\t"
- "lh %[r0], 0(%[window]) \n\t"
- "lh %[r1], 0(%[anaBuf]) \n\t"
- "lh %[r2], 2(%[window]) \n\t"
- "lh %[r3], 2(%[anaBuf]) \n\t"
- "lh %[r4], 4(%[window]) \n\t"
- "lh %[r5], 4(%[anaBuf]) \n\t"
- "lh %[r6], 6(%[window]) \n\t"
- "lh %[r7], 6(%[anaBuf]) \n\t"
- "mul %[r0], %[r0], %[r1] \n\t"
- "mul %[r2], %[r2], %[r3] \n\t"
- "mul %[r4], %[r4], %[r5] \n\t"
- "mul %[r6], %[r6], %[r7] \n\t"
- "addiu %[window], %[window], 8 \n\t"
- "addiu %[anaBuf], %[anaBuf], 8 \n\t"
- "addiu %[r0], %[r0], 0x2000 \n\t"
- "addiu %[r2], %[r2], 0x2000 \n\t"
- "addiu %[r4], %[r4], 0x2000 \n\t"
- "addiu %[r6], %[r6], 0x2000 \n\t"
- "sra %[r0], %[r0], 14 \n\t"
- "sra %[r2], %[r2], 14 \n\t"
- "sra %[r4], %[r4], 14 \n\t"
- "sra %[r6], %[r6], 14 \n\t"
- "sh %[r0], 0(%[outBuf]) \n\t"
- "sh %[r2], 2(%[outBuf]) \n\t"
- "sh %[r4], 4(%[outBuf]) \n\t"
- "sh %[r6], 6(%[outBuf]) \n\t"
- "addiu %[outBuf], %[outBuf], 8 \n\t"
- "b 1b \n\t"
- " addiu %[iters], %[iters], -1 \n\t"
- "2: \n\t"
- "andi %[after], %[anaLen], 3 \n\t"
- "3: \n\t"
- "blez %[after], 4f \n\t"
- " nop \n\t"
- "lh %[r0], 0(%[window]) \n\t"
- "lh %[r1], 0(%[anaBuf]) \n\t"
- "mul %[r0], %[r0], %[r1] \n\t"
- "addiu %[window], %[window], 2 \n\t"
- "addiu %[anaBuf], %[anaBuf], 2 \n\t"
- "addiu %[outBuf], %[outBuf], 2 \n\t"
- "addiu %[r0], %[r0], 0x2000 \n\t"
- "sra %[r0], %[r0], 14 \n\t"
- "sh %[r0], -2(%[outBuf]) \n\t"
- "b 3b \n\t"
- " addiu %[after], %[after], -1 \n\t"
- "4: \n\t"
- ".set pop \n\t"
- : [r0] "=&r" (r0), [r1] "=&r" (r1), [r2] "=&r" (r2),
- [r3] "=&r" (r3), [r4] "=&r" (r4), [r5] "=&r" (r5),
- [r6] "=&r" (r6), [r7] "=&r" (r7), [iters] "=&r" (iters),
- [after] "=&r" (after), [window] "+r" (window),
- [anaBuf] "+r" (anaBuf), [outBuf] "+r" (outBuf)
- : [anaLen] "r" (anaLen)
- : "memory", "hi", "lo"
- );
-#endif
-}
-
-// For the noise supression process, synthesis, read out fully processed
-// segment, and update synthesis buffer.
-void WebRtcNsx_SynthesisUpdate_mips(NoiseSuppressionFixedC* inst,
- int16_t* out_frame,
- int16_t gain_factor) {
- int iters = (int)inst->blockLen10ms >> 2;
- int after = inst->blockLen10ms & 3;
- int r0, r1, r2, r3, r4, r5, r6, r7;
- int16_t *window = (int16_t*)inst->window;
- int16_t *real = inst->real;
- int16_t *synthBuf = inst->synthesisBuffer;
- int16_t *out = out_frame;
- int sat_pos = 0x7fff;
- int sat_neg = 0xffff8000;
- int block10 = (int)inst->blockLen10ms;
- int anaLen = (int)inst->anaLen;
-
- __asm __volatile(
- ".set push \n\t"
- ".set noreorder \n\t"
- "1: \n\t"
- "blez %[iters], 2f \n\t"
- " nop \n\t"
- "lh %[r0], 0(%[window]) \n\t"
- "lh %[r1], 0(%[real]) \n\t"
- "lh %[r2], 2(%[window]) \n\t"
- "lh %[r3], 2(%[real]) \n\t"
- "lh %[r4], 4(%[window]) \n\t"
- "lh %[r5], 4(%[real]) \n\t"
- "lh %[r6], 6(%[window]) \n\t"
- "lh %[r7], 6(%[real]) \n\t"
- "mul %[r0], %[r0], %[r1] \n\t"
- "mul %[r2], %[r2], %[r3] \n\t"
- "mul %[r4], %[r4], %[r5] \n\t"
- "mul %[r6], %[r6], %[r7] \n\t"
- "addiu %[r0], %[r0], 0x2000 \n\t"
- "addiu %[r2], %[r2], 0x2000 \n\t"
- "addiu %[r4], %[r4], 0x2000 \n\t"
- "addiu %[r6], %[r6], 0x2000 \n\t"
- "sra %[r0], %[r0], 14 \n\t"
- "sra %[r2], %[r2], 14 \n\t"
- "sra %[r4], %[r4], 14 \n\t"
- "sra %[r6], %[r6], 14 \n\t"
- "mul %[r0], %[r0], %[gain_factor] \n\t"
- "mul %[r2], %[r2], %[gain_factor] \n\t"
- "mul %[r4], %[r4], %[gain_factor] \n\t"
- "mul %[r6], %[r6], %[gain_factor] \n\t"
- "addiu %[r0], %[r0], 0x1000 \n\t"
- "addiu %[r2], %[r2], 0x1000 \n\t"
- "addiu %[r4], %[r4], 0x1000 \n\t"
- "addiu %[r6], %[r6], 0x1000 \n\t"
- "sra %[r0], %[r0], 13 \n\t"
- "sra %[r2], %[r2], 13 \n\t"
- "sra %[r4], %[r4], 13 \n\t"
- "sra %[r6], %[r6], 13 \n\t"
- "slt %[r1], %[r0], %[sat_pos] \n\t"
- "slt %[r3], %[r2], %[sat_pos] \n\t"
- "slt %[r5], %[r4], %[sat_pos] \n\t"
- "slt %[r7], %[r6], %[sat_pos] \n\t"
- "movz %[r0], %[sat_pos], %[r1] \n\t"
- "movz %[r2], %[sat_pos], %[r3] \n\t"
- "movz %[r4], %[sat_pos], %[r5] \n\t"
- "movz %[r6], %[sat_pos], %[r7] \n\t"
- "lh %[r1], 0(%[synthBuf]) \n\t"
- "lh %[r3], 2(%[synthBuf]) \n\t"
- "lh %[r5], 4(%[synthBuf]) \n\t"
- "lh %[r7], 6(%[synthBuf]) \n\t"
- "addu %[r0], %[r0], %[r1] \n\t"
- "addu %[r2], %[r2], %[r3] \n\t"
- "addu %[r4], %[r4], %[r5] \n\t"
- "addu %[r6], %[r6], %[r7] \n\t"
- "slt %[r1], %[r0], %[sat_pos] \n\t"
- "slt %[r3], %[r2], %[sat_pos] \n\t"
- "slt %[r5], %[r4], %[sat_pos] \n\t"
- "slt %[r7], %[r6], %[sat_pos] \n\t"
- "movz %[r0], %[sat_pos], %[r1] \n\t"
- "movz %[r2], %[sat_pos], %[r3] \n\t"
- "movz %[r4], %[sat_pos], %[r5] \n\t"
- "movz %[r6], %[sat_pos], %[r7] \n\t"
- "slt %[r1], %[r0], %[sat_neg] \n\t"
- "slt %[r3], %[r2], %[sat_neg] \n\t"
- "slt %[r5], %[r4], %[sat_neg] \n\t"
- "slt %[r7], %[r6], %[sat_neg] \n\t"
- "movn %[r0], %[sat_neg], %[r1] \n\t"
- "movn %[r2], %[sat_neg], %[r3] \n\t"
- "movn %[r4], %[sat_neg], %[r5] \n\t"
- "movn %[r6], %[sat_neg], %[r7] \n\t"
- "sh %[r0], 0(%[synthBuf]) \n\t"
- "sh %[r2], 2(%[synthBuf]) \n\t"
- "sh %[r4], 4(%[synthBuf]) \n\t"
- "sh %[r6], 6(%[synthBuf]) \n\t"
- "sh %[r0], 0(%[out]) \n\t"
- "sh %[r2], 2(%[out]) \n\t"
- "sh %[r4], 4(%[out]) \n\t"
- "sh %[r6], 6(%[out]) \n\t"
- "addiu %[window], %[window], 8 \n\t"
- "addiu %[real], %[real], 8 \n\t"
- "addiu %[synthBuf],%[synthBuf], 8 \n\t"
- "addiu %[out], %[out], 8 \n\t"
- "b 1b \n\t"
- " addiu %[iters], %[iters], -1 \n\t"
- "2: \n\t"
- "blez %[after], 3f \n\t"
- " subu %[block10], %[anaLen], %[block10] \n\t"
- "lh %[r0], 0(%[window]) \n\t"
- "lh %[r1], 0(%[real]) \n\t"
- "mul %[r0], %[r0], %[r1] \n\t"
- "addiu %[window], %[window], 2 \n\t"
- "addiu %[real], %[real], 2 \n\t"
- "addiu %[r0], %[r0], 0x2000 \n\t"
- "sra %[r0], %[r0], 14 \n\t"
- "mul %[r0], %[r0], %[gain_factor] \n\t"
- "addiu %[r0], %[r0], 0x1000 \n\t"
- "sra %[r0], %[r0], 13 \n\t"
- "slt %[r1], %[r0], %[sat_pos] \n\t"
- "movz %[r0], %[sat_pos], %[r1] \n\t"
- "lh %[r1], 0(%[synthBuf]) \n\t"
- "addu %[r0], %[r0], %[r1] \n\t"
- "slt %[r1], %[r0], %[sat_pos] \n\t"
- "movz %[r0], %[sat_pos], %[r1] \n\t"
- "slt %[r1], %[r0], %[sat_neg] \n\t"
- "movn %[r0], %[sat_neg], %[r1] \n\t"
- "sh %[r0], 0(%[synthBuf]) \n\t"
- "sh %[r0], 0(%[out]) \n\t"
- "addiu %[synthBuf],%[synthBuf], 2 \n\t"
- "addiu %[out], %[out], 2 \n\t"
- "b 2b \n\t"
- " addiu %[after], %[after], -1 \n\t"
- "3: \n\t"
- "sra %[iters], %[block10], 2 \n\t"
- "4: \n\t"
- "blez %[iters], 5f \n\t"
- " andi %[after], %[block10], 3 \n\t"
- "lh %[r0], 0(%[window]) \n\t"
- "lh %[r1], 0(%[real]) \n\t"
- "lh %[r2], 2(%[window]) \n\t"
- "lh %[r3], 2(%[real]) \n\t"
- "lh %[r4], 4(%[window]) \n\t"
- "lh %[r5], 4(%[real]) \n\t"
- "lh %[r6], 6(%[window]) \n\t"
- "lh %[r7], 6(%[real]) \n\t"
- "mul %[r0], %[r0], %[r1] \n\t"
- "mul %[r2], %[r2], %[r3] \n\t"
- "mul %[r4], %[r4], %[r5] \n\t"
- "mul %[r6], %[r6], %[r7] \n\t"
- "addiu %[r0], %[r0], 0x2000 \n\t"
- "addiu %[r2], %[r2], 0x2000 \n\t"
- "addiu %[r4], %[r4], 0x2000 \n\t"
- "addiu %[r6], %[r6], 0x2000 \n\t"
- "sra %[r0], %[r0], 14 \n\t"
- "sra %[r2], %[r2], 14 \n\t"
- "sra %[r4], %[r4], 14 \n\t"
- "sra %[r6], %[r6], 14 \n\t"
- "mul %[r0], %[r0], %[gain_factor] \n\t"
- "mul %[r2], %[r2], %[gain_factor] \n\t"
- "mul %[r4], %[r4], %[gain_factor] \n\t"
- "mul %[r6], %[r6], %[gain_factor] \n\t"
- "addiu %[r0], %[r0], 0x1000 \n\t"
- "addiu %[r2], %[r2], 0x1000 \n\t"
- "addiu %[r4], %[r4], 0x1000 \n\t"
- "addiu %[r6], %[r6], 0x1000 \n\t"
- "sra %[r0], %[r0], 13 \n\t"
- "sra %[r2], %[r2], 13 \n\t"
- "sra %[r4], %[r4], 13 \n\t"
- "sra %[r6], %[r6], 13 \n\t"
- "slt %[r1], %[r0], %[sat_pos] \n\t"
- "slt %[r3], %[r2], %[sat_pos] \n\t"
- "slt %[r5], %[r4], %[sat_pos] \n\t"
- "slt %[r7], %[r6], %[sat_pos] \n\t"
- "movz %[r0], %[sat_pos], %[r1] \n\t"
- "movz %[r2], %[sat_pos], %[r3] \n\t"
- "movz %[r4], %[sat_pos], %[r5] \n\t"
- "movz %[r6], %[sat_pos], %[r7] \n\t"
- "lh %[r1], 0(%[synthBuf]) \n\t"
- "lh %[r3], 2(%[synthBuf]) \n\t"
- "lh %[r5], 4(%[synthBuf]) \n\t"
- "lh %[r7], 6(%[synthBuf]) \n\t"
- "addu %[r0], %[r0], %[r1] \n\t"
- "addu %[r2], %[r2], %[r3] \n\t"
- "addu %[r4], %[r4], %[r5] \n\t"
- "addu %[r6], %[r6], %[r7] \n\t"
- "slt %[r1], %[r0], %[sat_pos] \n\t"
- "slt %[r3], %[r2], %[sat_pos] \n\t"
- "slt %[r5], %[r4], %[sat_pos] \n\t"
- "slt %[r7], %[r6], %[sat_pos] \n\t"
- "movz %[r0], %[sat_pos], %[r1] \n\t"
- "movz %[r2], %[sat_pos], %[r3] \n\t"
- "movz %[r4], %[sat_pos], %[r5] \n\t"
- "movz %[r6], %[sat_pos], %[r7] \n\t"
- "slt %[r1], %[r0], %[sat_neg] \n\t"
- "slt %[r3], %[r2], %[sat_neg] \n\t"
- "slt %[r5], %[r4], %[sat_neg] \n\t"
- "slt %[r7], %[r6], %[sat_neg] \n\t"
- "movn %[r0], %[sat_neg], %[r1] \n\t"
- "movn %[r2], %[sat_neg], %[r3] \n\t"
- "movn %[r4], %[sat_neg], %[r5] \n\t"
- "movn %[r6], %[sat_neg], %[r7] \n\t"
- "sh %[r0], 0(%[synthBuf]) \n\t"
- "sh %[r2], 2(%[synthBuf]) \n\t"
- "sh %[r4], 4(%[synthBuf]) \n\t"
- "sh %[r6], 6(%[synthBuf]) \n\t"
- "addiu %[window], %[window], 8 \n\t"
- "addiu %[real], %[real], 8 \n\t"
- "addiu %[synthBuf],%[synthBuf], 8 \n\t"
- "b 4b \n\t"
- " addiu %[iters], %[iters], -1 \n\t"
- "5: \n\t"
- "blez %[after], 6f \n\t"
- " nop \n\t"
- "lh %[r0], 0(%[window]) \n\t"
- "lh %[r1], 0(%[real]) \n\t"
- "mul %[r0], %[r0], %[r1] \n\t"
- "addiu %[window], %[window], 2 \n\t"
- "addiu %[real], %[real], 2 \n\t"
- "addiu %[r0], %[r0], 0x2000 \n\t"
- "sra %[r0], %[r0], 14 \n\t"
- "mul %[r0], %[r0], %[gain_factor] \n\t"
- "addiu %[r0], %[r0], 0x1000 \n\t"
- "sra %[r0], %[r0], 13 \n\t"
- "slt %[r1], %[r0], %[sat_pos] \n\t"
- "movz %[r0], %[sat_pos], %[r1] \n\t"
- "lh %[r1], 0(%[synthBuf]) \n\t"
- "addu %[r0], %[r0], %[r1] \n\t"
- "slt %[r1], %[r0], %[sat_pos] \n\t"
- "movz %[r0], %[sat_pos], %[r1] \n\t"
- "slt %[r1], %[r0], %[sat_neg] \n\t"
- "movn %[r0], %[sat_neg], %[r1] \n\t"
- "sh %[r0], 0(%[synthBuf]) \n\t"
- "addiu %[synthBuf],%[synthBuf], 2 \n\t"
- "b 2b \n\t"
- " addiu %[after], %[after], -1 \n\t"
- "6: \n\t"
- ".set pop \n\t"
- : [r0] "=&r" (r0), [r1] "=&r" (r1), [r2] "=&r" (r2),
- [r3] "=&r" (r3), [r4] "=&r" (r4), [r5] "=&r" (r5),
- [r6] "=&r" (r6), [r7] "=&r" (r7), [iters] "+r" (iters),
- [after] "+r" (after), [block10] "+r" (block10),
- [window] "+r" (window), [real] "+r" (real),
- [synthBuf] "+r" (synthBuf), [out] "+r" (out)
- : [gain_factor] "r" (gain_factor), [sat_pos] "r" (sat_pos),
- [sat_neg] "r" (sat_neg), [anaLen] "r" (anaLen)
- : "memory", "hi", "lo"
- );
-
- // update synthesis buffer
- memcpy(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms,
- (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->synthesisBuffer));
- WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer
- + inst->anaLen - inst->blockLen10ms, inst->blockLen10ms);
-}
-
-// Filter the data in the frequency domain, and create spectrum.
-void WebRtcNsx_PrepareSpectrum_mips(NoiseSuppressionFixedC* inst,
- int16_t* freq_buf) {
- uint16_t *noiseSupFilter = inst->noiseSupFilter;
- int16_t *real = inst->real;
- int16_t *imag = inst->imag;
- int32_t loop_count = 2;
- int16_t tmp_1, tmp_2, tmp_3, tmp_4, tmp_5, tmp_6;
- int16_t tmp16 = (int16_t)(inst->anaLen << 1) - 4;
- int16_t* freq_buf_f = freq_buf;
- int16_t* freq_buf_s = &freq_buf[tmp16];
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- //first sample
- "lh %[tmp_1], 0(%[noiseSupFilter]) \n\t"
- "lh %[tmp_2], 0(%[real]) \n\t"
- "lh %[tmp_3], 0(%[imag]) \n\t"
- "mul %[tmp_2], %[tmp_2], %[tmp_1] \n\t"
- "mul %[tmp_3], %[tmp_3], %[tmp_1] \n\t"
- "sra %[tmp_2], %[tmp_2], 14 \n\t"
- "sra %[tmp_3], %[tmp_3], 14 \n\t"
- "sh %[tmp_2], 0(%[real]) \n\t"
- "sh %[tmp_3], 0(%[imag]) \n\t"
- "negu %[tmp_3], %[tmp_3] \n\t"
- "sh %[tmp_2], 0(%[freq_buf_f]) \n\t"
- "sh %[tmp_3], 2(%[freq_buf_f]) \n\t"
- "addiu %[real], %[real], 2 \n\t"
- "addiu %[imag], %[imag], 2 \n\t"
- "addiu %[noiseSupFilter], %[noiseSupFilter], 2 \n\t"
- "addiu %[freq_buf_f], %[freq_buf_f], 4 \n\t"
- "1: \n\t"
- "lh %[tmp_1], 0(%[noiseSupFilter]) \n\t"
- "lh %[tmp_2], 0(%[real]) \n\t"
- "lh %[tmp_3], 0(%[imag]) \n\t"
- "lh %[tmp_4], 2(%[noiseSupFilter]) \n\t"
- "lh %[tmp_5], 2(%[real]) \n\t"
- "lh %[tmp_6], 2(%[imag]) \n\t"
- "mul %[tmp_2], %[tmp_2], %[tmp_1] \n\t"
- "mul %[tmp_3], %[tmp_3], %[tmp_1] \n\t"
- "mul %[tmp_5], %[tmp_5], %[tmp_4] \n\t"
- "mul %[tmp_6], %[tmp_6], %[tmp_4] \n\t"
- "addiu %[loop_count], %[loop_count], 2 \n\t"
- "sra %[tmp_2], %[tmp_2], 14 \n\t"
- "sra %[tmp_3], %[tmp_3], 14 \n\t"
- "sra %[tmp_5], %[tmp_5], 14 \n\t"
- "sra %[tmp_6], %[tmp_6], 14 \n\t"
- "addiu %[noiseSupFilter], %[noiseSupFilter], 4 \n\t"
- "sh %[tmp_2], 0(%[real]) \n\t"
- "sh %[tmp_2], 4(%[freq_buf_s]) \n\t"
- "sh %[tmp_3], 0(%[imag]) \n\t"
- "sh %[tmp_3], 6(%[freq_buf_s]) \n\t"
- "negu %[tmp_3], %[tmp_3] \n\t"
- "sh %[tmp_5], 2(%[real]) \n\t"
- "sh %[tmp_5], 0(%[freq_buf_s]) \n\t"
- "sh %[tmp_6], 2(%[imag]) \n\t"
- "sh %[tmp_6], 2(%[freq_buf_s]) \n\t"
- "negu %[tmp_6], %[tmp_6] \n\t"
- "addiu %[freq_buf_s], %[freq_buf_s], -8 \n\t"
- "addiu %[real], %[real], 4 \n\t"
- "addiu %[imag], %[imag], 4 \n\t"
- "sh %[tmp_2], 0(%[freq_buf_f]) \n\t"
- "sh %[tmp_3], 2(%[freq_buf_f]) \n\t"
- "sh %[tmp_5], 4(%[freq_buf_f]) \n\t"
- "sh %[tmp_6], 6(%[freq_buf_f]) \n\t"
- "blt %[loop_count], %[loop_size], 1b \n\t"
- " addiu %[freq_buf_f], %[freq_buf_f], 8 \n\t"
- //last two samples:
- "lh %[tmp_1], 0(%[noiseSupFilter]) \n\t"
- "lh %[tmp_2], 0(%[real]) \n\t"
- "lh %[tmp_3], 0(%[imag]) \n\t"
- "lh %[tmp_4], 2(%[noiseSupFilter]) \n\t"
- "lh %[tmp_5], 2(%[real]) \n\t"
- "lh %[tmp_6], 2(%[imag]) \n\t"
- "mul %[tmp_2], %[tmp_2], %[tmp_1] \n\t"
- "mul %[tmp_3], %[tmp_3], %[tmp_1] \n\t"
- "mul %[tmp_5], %[tmp_5], %[tmp_4] \n\t"
- "mul %[tmp_6], %[tmp_6], %[tmp_4] \n\t"
- "sra %[tmp_2], %[tmp_2], 14 \n\t"
- "sra %[tmp_3], %[tmp_3], 14 \n\t"
- "sra %[tmp_5], %[tmp_5], 14 \n\t"
- "sra %[tmp_6], %[tmp_6], 14 \n\t"
- "sh %[tmp_2], 0(%[real]) \n\t"
- "sh %[tmp_2], 4(%[freq_buf_s]) \n\t"
- "sh %[tmp_3], 0(%[imag]) \n\t"
- "sh %[tmp_3], 6(%[freq_buf_s]) \n\t"
- "negu %[tmp_3], %[tmp_3] \n\t"
- "sh %[tmp_2], 0(%[freq_buf_f]) \n\t"
- "sh %[tmp_3], 2(%[freq_buf_f]) \n\t"
- "sh %[tmp_5], 4(%[freq_buf_f]) \n\t"
- "sh %[tmp_6], 6(%[freq_buf_f]) \n\t"
- "sh %[tmp_5], 2(%[real]) \n\t"
- "sh %[tmp_6], 2(%[imag]) \n\t"
- ".set pop \n\t"
- : [real] "+r" (real), [imag] "+r" (imag),
- [freq_buf_f] "+r" (freq_buf_f), [freq_buf_s] "+r" (freq_buf_s),
- [loop_count] "+r" (loop_count), [noiseSupFilter] "+r" (noiseSupFilter),
- [tmp_1] "=&r" (tmp_1), [tmp_2] "=&r" (tmp_2), [tmp_3] "=&r" (tmp_3),
- [tmp_4] "=&r" (tmp_4), [tmp_5] "=&r" (tmp_5), [tmp_6] "=&r" (tmp_6)
- : [loop_size] "r" (inst->anaLen2)
- : "memory", "hi", "lo"
- );
-}
-
-#if defined(MIPS_DSP_R1_LE)
-// Denormalize the real-valued signal |in|, the output from inverse FFT.
-void WebRtcNsx_Denormalize_mips(NoiseSuppressionFixedC* inst,
- int16_t* in,
- int factor) {
- int32_t r0, r1, r2, r3, t0;
- int len = (int)inst->anaLen;
- int16_t *out = &inst->real[0];
- int shift = factor - inst->normData;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "beqz %[len], 8f \n\t"
- " nop \n\t"
- "bltz %[shift], 4f \n\t"
- " sra %[t0], %[len], 2 \n\t"
- "beqz %[t0], 2f \n\t"
- " andi %[len], %[len], 3 \n\t"
- "1: \n\t"
- "lh %[r0], 0(%[in]) \n\t"
- "lh %[r1], 2(%[in]) \n\t"
- "lh %[r2], 4(%[in]) \n\t"
- "lh %[r3], 6(%[in]) \n\t"
- "shllv_s.ph %[r0], %[r0], %[shift] \n\t"
- "shllv_s.ph %[r1], %[r1], %[shift] \n\t"
- "shllv_s.ph %[r2], %[r2], %[shift] \n\t"
- "shllv_s.ph %[r3], %[r3], %[shift] \n\t"
- "addiu %[in], %[in], 8 \n\t"
- "addiu %[t0], %[t0], -1 \n\t"
- "sh %[r0], 0(%[out]) \n\t"
- "sh %[r1], 2(%[out]) \n\t"
- "sh %[r2], 4(%[out]) \n\t"
- "sh %[r3], 6(%[out]) \n\t"
- "bgtz %[t0], 1b \n\t"
- " addiu %[out], %[out], 8 \n\t"
- "2: \n\t"
- "beqz %[len], 8f \n\t"
- " nop \n\t"
- "3: \n\t"
- "lh %[r0], 0(%[in]) \n\t"
- "addiu %[in], %[in], 2 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "shllv_s.ph %[r0], %[r0], %[shift] \n\t"
- "addiu %[out], %[out], 2 \n\t"
- "bgtz %[len], 3b \n\t"
- " sh %[r0], -2(%[out]) \n\t"
- "b 8f \n\t"
- "4: \n\t"
- "negu %[shift], %[shift] \n\t"
- "beqz %[t0], 6f \n\t"
- " andi %[len], %[len], 3 \n\t"
- "5: \n\t"
- "lh %[r0], 0(%[in]) \n\t"
- "lh %[r1], 2(%[in]) \n\t"
- "lh %[r2], 4(%[in]) \n\t"
- "lh %[r3], 6(%[in]) \n\t"
- "srav %[r0], %[r0], %[shift] \n\t"
- "srav %[r1], %[r1], %[shift] \n\t"
- "srav %[r2], %[r2], %[shift] \n\t"
- "srav %[r3], %[r3], %[shift] \n\t"
- "addiu %[in], %[in], 8 \n\t"
- "addiu %[t0], %[t0], -1 \n\t"
- "sh %[r0], 0(%[out]) \n\t"
- "sh %[r1], 2(%[out]) \n\t"
- "sh %[r2], 4(%[out]) \n\t"
- "sh %[r3], 6(%[out]) \n\t"
- "bgtz %[t0], 5b \n\t"
- " addiu %[out], %[out], 8 \n\t"
- "6: \n\t"
- "beqz %[len], 8f \n\t"
- " nop \n\t"
- "7: \n\t"
- "lh %[r0], 0(%[in]) \n\t"
- "addiu %[in], %[in], 2 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "srav %[r0], %[r0], %[shift] \n\t"
- "addiu %[out], %[out], 2 \n\t"
- "bgtz %[len], 7b \n\t"
- " sh %[r0], -2(%[out]) \n\t"
- "8: \n\t"
- ".set pop \n\t"
- : [t0] "=&r" (t0), [r0] "=&r" (r0), [r1] "=&r" (r1),
- [r2] "=&r" (r2), [r3] "=&r" (r3)
- : [len] "r" (len), [shift] "r" (shift), [in] "r" (in),
- [out] "r" (out)
- : "memory"
- );
-}
-#endif
-
-// Normalize the real-valued signal |in|, the input to forward FFT.
-void WebRtcNsx_NormalizeRealBuffer_mips(NoiseSuppressionFixedC* inst,
- const int16_t* in,
- int16_t* out) {
- int32_t r0, r1, r2, r3, t0;
- int len = (int)inst->anaLen;
- int shift = inst->normData;
-
- __asm __volatile (
- ".set push \n\t"
- ".set noreorder \n\t"
- "beqz %[len], 4f \n\t"
- " sra %[t0], %[len], 2 \n\t"
- "beqz %[t0], 2f \n\t"
- " andi %[len], %[len], 3 \n\t"
- "1: \n\t"
- "lh %[r0], 0(%[in]) \n\t"
- "lh %[r1], 2(%[in]) \n\t"
- "lh %[r2], 4(%[in]) \n\t"
- "lh %[r3], 6(%[in]) \n\t"
- "sllv %[r0], %[r0], %[shift] \n\t"
- "sllv %[r1], %[r1], %[shift] \n\t"
- "sllv %[r2], %[r2], %[shift] \n\t"
- "sllv %[r3], %[r3], %[shift] \n\t"
- "addiu %[in], %[in], 8 \n\t"
- "addiu %[t0], %[t0], -1 \n\t"
- "sh %[r0], 0(%[out]) \n\t"
- "sh %[r1], 2(%[out]) \n\t"
- "sh %[r2], 4(%[out]) \n\t"
- "sh %[r3], 6(%[out]) \n\t"
- "bgtz %[t0], 1b \n\t"
- " addiu %[out], %[out], 8 \n\t"
- "2: \n\t"
- "beqz %[len], 4f \n\t"
- " nop \n\t"
- "3: \n\t"
- "lh %[r0], 0(%[in]) \n\t"
- "addiu %[in], %[in], 2 \n\t"
- "addiu %[len], %[len], -1 \n\t"
- "sllv %[r0], %[r0], %[shift] \n\t"
- "addiu %[out], %[out], 2 \n\t"
- "bgtz %[len], 3b \n\t"
- " sh %[r0], -2(%[out]) \n\t"
- "4: \n\t"
- ".set pop \n\t"
- : [t0] "=&r" (t0), [r0] "=&r" (r0), [r1] "=&r" (r1),
- [r2] "=&r" (r2), [r3] "=&r" (r3)
- : [len] "r" (len), [shift] "r" (shift), [in] "r" (in),
- [out] "r" (out)
- : "memory"
- );
-}
-
diff --git a/webrtc/modules/audio_processing/ns/nsx_core_neon.c b/webrtc/modules/audio_processing/ns/nsx_core_neon.c
deleted file mode 100644
index 65788ae..0000000
--- a/webrtc/modules/audio_processing/ns/nsx_core_neon.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/ns/nsx_core.h"
-
-#include <arm_neon.h>
-#include <assert.h>
-
-// Constants to compensate for shifting signal log(2^shifts).
-const int16_t WebRtcNsx_kLogTable[9] = {
- 0, 177, 355, 532, 710, 887, 1065, 1242, 1420
-};
-
-const int16_t WebRtcNsx_kCounterDiv[201] = {
- 32767, 16384, 10923, 8192, 6554, 5461, 4681, 4096, 3641, 3277, 2979, 2731,
- 2521, 2341, 2185, 2048, 1928, 1820, 1725, 1638, 1560, 1489, 1425, 1365, 1311,
- 1260, 1214, 1170, 1130, 1092, 1057, 1024, 993, 964, 936, 910, 886, 862, 840,
- 819, 799, 780, 762, 745, 728, 712, 697, 683, 669, 655, 643, 630, 618, 607,
- 596, 585, 575, 565, 555, 546, 537, 529, 520, 512, 504, 496, 489, 482, 475,
- 468, 462, 455, 449, 443, 437, 431, 426, 420, 415, 410, 405, 400, 395, 390,
- 386, 381, 377, 372, 368, 364, 360, 356, 352, 349, 345, 341, 338, 334, 331,
- 328, 324, 321, 318, 315, 312, 309, 306, 303, 301, 298, 295, 293, 290, 287,
- 285, 282, 280, 278, 275, 273, 271, 269, 266, 264, 262, 260, 258, 256, 254,
- 252, 250, 248, 246, 245, 243, 241, 239, 237, 236, 234, 232, 231, 229, 228,
- 226, 224, 223, 221, 220, 218, 217, 216, 214, 213, 211, 210, 209, 207, 206,
- 205, 204, 202, 201, 200, 199, 197, 196, 195, 194, 193, 192, 191, 189, 188,
- 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173,
- 172, 172, 171, 170, 169, 168, 167, 166, 165, 165, 164, 163
-};
-
-const int16_t WebRtcNsx_kLogTableFrac[256] = {
- 0, 1, 3, 4, 6, 7, 9, 10, 11, 13, 14, 16, 17, 18, 20, 21,
- 22, 24, 25, 26, 28, 29, 30, 32, 33, 34, 36, 37, 38, 40, 41, 42,
- 44, 45, 46, 47, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62,
- 63, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81,
- 82, 84, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99,
- 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116,
- 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131,
- 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
- 147, 148, 149, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160,
- 161, 162, 163, 164, 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 174,
- 175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 184, 185, 185, 186, 187,
- 188, 189, 190, 191, 192, 192, 193, 194, 195, 196, 197, 198, 198, 199, 200,
- 201, 202, 203, 203, 204, 205, 206, 207, 208, 208, 209, 210, 211, 212, 212,
- 213, 214, 215, 216, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
- 225, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236,
- 237, 238, 238, 239, 240, 241, 241, 242, 243, 244, 244, 245, 246, 247, 247,
- 248, 249, 249, 250, 251, 252, 252, 253, 254, 255, 255
-};
-
-// Update the noise estimation information.
-static void UpdateNoiseEstimateNeon(NoiseSuppressionFixedC* inst, int offset) {
- const int16_t kExp2Const = 11819; // Q13
- int16_t* ptr_noiseEstLogQuantile = NULL;
- int16_t* ptr_noiseEstQuantile = NULL;
- int16x4_t kExp2Const16x4 = vdup_n_s16(kExp2Const);
- int32x4_t twentyOne32x4 = vdupq_n_s32(21);
- int32x4_t constA32x4 = vdupq_n_s32(0x1fffff);
- int32x4_t constB32x4 = vdupq_n_s32(0x200000);
-
- int16_t tmp16 = WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset,
- inst->magnLen);
-
- // Guarantee a Q-domain as high as possible and still fit in int16
- inst->qNoise = 14 - (int) WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2Const,
- tmp16,
- 21);
-
- int32x4_t qNoise32x4 = vdupq_n_s32(inst->qNoise);
-
- for (ptr_noiseEstLogQuantile = &inst->noiseEstLogQuantile[offset],
- ptr_noiseEstQuantile = &inst->noiseEstQuantile[0];
- ptr_noiseEstQuantile < &inst->noiseEstQuantile[inst->magnLen - 3];
- ptr_noiseEstQuantile += 4, ptr_noiseEstLogQuantile += 4) {
-
- // tmp32no2 = kExp2Const * inst->noiseEstLogQuantile[offset + i];
- int16x4_t v16x4 = vld1_s16(ptr_noiseEstLogQuantile);
- int32x4_t v32x4B = vmull_s16(v16x4, kExp2Const16x4);
-
- // tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac
- int32x4_t v32x4A = vandq_s32(v32x4B, constA32x4);
- v32x4A = vorrq_s32(v32x4A, constB32x4);
-
- // tmp16 = (int16_t)(tmp32no2 >> 21);
- v32x4B = vshrq_n_s32(v32x4B, 21);
-
- // tmp16 -= 21;// shift 21 to get result in Q0
- v32x4B = vsubq_s32(v32x4B, twentyOne32x4);
-
- // tmp16 += (int16_t) inst->qNoise;
- // shift to get result in Q(qNoise)
- v32x4B = vaddq_s32(v32x4B, qNoise32x4);
-
- // if (tmp16 < 0) {
- // tmp32no1 >>= -tmp16;
- // } else {
- // tmp32no1 <<= tmp16;
- // }
- v32x4B = vshlq_s32(v32x4A, v32x4B);
-
- // tmp16 = WebRtcSpl_SatW32ToW16(tmp32no1);
- v16x4 = vqmovn_s32(v32x4B);
-
- //inst->noiseEstQuantile[i] = tmp16;
- vst1_s16(ptr_noiseEstQuantile, v16x4);
- }
-
- // Last iteration:
-
- // inst->quantile[i]=exp(inst->lquantile[offset+i]);
- // in Q21
- int32_t tmp32no2 = kExp2Const * *ptr_noiseEstLogQuantile;
- int32_t tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac
-
- tmp16 = (int16_t)(tmp32no2 >> 21);
- tmp16 -= 21;// shift 21 to get result in Q0
- tmp16 += (int16_t) inst->qNoise; //shift to get result in Q(qNoise)
- if (tmp16 < 0) {
- tmp32no1 >>= -tmp16;
- } else {
- tmp32no1 <<= tmp16;
- }
- *ptr_noiseEstQuantile = WebRtcSpl_SatW32ToW16(tmp32no1);
-}
-
-// Noise Estimation
-void WebRtcNsx_NoiseEstimationNeon(NoiseSuppressionFixedC* inst,
- uint16_t* magn,
- uint32_t* noise,
- int16_t* q_noise) {
- int16_t lmagn[HALF_ANAL_BLOCKL], counter, countDiv;
- int16_t countProd, delta, zeros, frac;
- int16_t log2, tabind, logval, tmp16, tmp16no1, tmp16no2;
- const int16_t log2_const = 22713;
- const int16_t width_factor = 21845;
-
- size_t i, s, offset;
-
- tabind = inst->stages - inst->normData;
- assert(tabind < 9);
- assert(tabind > -9);
- if (tabind < 0) {
- logval = -WebRtcNsx_kLogTable[-tabind];
- } else {
- logval = WebRtcNsx_kLogTable[tabind];
- }
-
- int16x8_t logval_16x8 = vdupq_n_s16(logval);
-
- // lmagn(i)=log(magn(i))=log(2)*log2(magn(i))
- // magn is in Q(-stages), and the real lmagn values are:
- // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages)
- // lmagn in Q8
- for (i = 0; i < inst->magnLen; i++) {
- if (magn[i]) {
- zeros = WebRtcSpl_NormU32((uint32_t)magn[i]);
- frac = (int16_t)((((uint32_t)magn[i] << zeros)
- & 0x7FFFFFFF) >> 23);
- assert(frac < 256);
- // log2(magn(i))
- log2 = (int16_t)(((31 - zeros) << 8)
- + WebRtcNsx_kLogTableFrac[frac]);
- // log2(magn(i))*log(2)
- lmagn[i] = (int16_t)((log2 * log2_const) >> 15);
- // + log(2^stages)
- lmagn[i] += logval;
- } else {
- lmagn[i] = logval;
- }
- }
-
- int16x4_t Q3_16x4 = vdup_n_s16(3);
- int16x8_t WIDTHQ8_16x8 = vdupq_n_s16(WIDTH_Q8);
- int16x8_t WIDTHFACTOR_16x8 = vdupq_n_s16(width_factor);
-
- int16_t factor = FACTOR_Q7;
- if (inst->blockIndex < END_STARTUP_LONG)
- factor = FACTOR_Q7_STARTUP;
-
- // Loop over simultaneous estimates
- for (s = 0; s < SIMULT; s++) {
- offset = s * inst->magnLen;
-
- // Get counter values from state
- counter = inst->noiseEstCounter[s];
- assert(counter < 201);
- countDiv = WebRtcNsx_kCounterDiv[counter];
- countProd = (int16_t)(counter * countDiv);
-
- // quant_est(...)
- int16_t deltaBuff[8];
- int16x4_t tmp16x4_0;
- int16x4_t tmp16x4_1;
- int16x4_t countDiv_16x4 = vdup_n_s16(countDiv);
- int16x8_t countProd_16x8 = vdupq_n_s16(countProd);
- int16x8_t tmp16x8_0 = vdupq_n_s16(countDiv);
- int16x8_t prod16x8 = vqrdmulhq_s16(WIDTHFACTOR_16x8, tmp16x8_0);
- int16x8_t tmp16x8_1;
- int16x8_t tmp16x8_2;
- int16x8_t tmp16x8_3;
- uint16x8_t tmp16x8_4;
- int32x4_t tmp32x4;
-
- for (i = 0; i + 7 < inst->magnLen; i += 8) {
- // Compute delta.
- // Smaller step size during startup. This prevents from using
- // unrealistic values causing overflow.
- tmp16x8_0 = vdupq_n_s16(factor);
- vst1q_s16(deltaBuff, tmp16x8_0);
-
- int j;
- for (j = 0; j < 8; j++) {
- if (inst->noiseEstDensity[offset + i + j] > 512) {
- // Get values for deltaBuff by shifting intead of dividing.
- int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i + j]);
- deltaBuff[j] = (int16_t)(FACTOR_Q16 >> (14 - factor));
- }
- }
-
- // Update log quantile estimate
-
- // tmp16 = (int16_t)((delta * countDiv) >> 14);
- tmp32x4 = vmull_s16(vld1_s16(&deltaBuff[0]), countDiv_16x4);
- tmp16x4_1 = vshrn_n_s32(tmp32x4, 14);
- tmp32x4 = vmull_s16(vld1_s16(&deltaBuff[4]), countDiv_16x4);
- tmp16x4_0 = vshrn_n_s32(tmp32x4, 14);
- tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // Keep for several lines.
-
- // prepare for the "if" branch
- // tmp16 += 2;
- // tmp16_1 = (Word16)(tmp16>>2);
- tmp16x8_1 = vrshrq_n_s16(tmp16x8_0, 2);
-
- // inst->noiseEstLogQuantile[offset+i] + tmp16_1;
- tmp16x8_2 = vld1q_s16(&inst->noiseEstLogQuantile[offset + i]); // Keep
- tmp16x8_1 = vaddq_s16(tmp16x8_2, tmp16x8_1); // Keep for several lines
-
- // Prepare for the "else" branch
- // tmp16 += 1;
- // tmp16_1 = (Word16)(tmp16>>1);
- tmp16x8_0 = vrshrq_n_s16(tmp16x8_0, 1);
-
- // tmp16_2 = (int16_t)((tmp16_1 * 3) >> 1);
- tmp32x4 = vmull_s16(vget_low_s16(tmp16x8_0), Q3_16x4);
- tmp16x4_1 = vshrn_n_s32(tmp32x4, 1);
-
- // tmp16_2 = (int16_t)((tmp16_1 * 3) >> 1);
- tmp32x4 = vmull_s16(vget_high_s16(tmp16x8_0), Q3_16x4);
- tmp16x4_0 = vshrn_n_s32(tmp32x4, 1);
-
- // inst->noiseEstLogQuantile[offset + i] - tmp16_2;
- tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // keep
- tmp16x8_0 = vsubq_s16(tmp16x8_2, tmp16x8_0);
-
- // logval is the smallest fixed point representation we can have. Values
- // below that will correspond to values in the interval [0, 1], which
- // can't possibly occur.
- tmp16x8_0 = vmaxq_s16(tmp16x8_0, logval_16x8);
-
- // Do the if-else branches:
- tmp16x8_3 = vld1q_s16(&lmagn[i]); // keep for several lines
- tmp16x8_4 = vcgtq_s16(tmp16x8_3, tmp16x8_2);
- tmp16x8_2 = vbslq_s16(tmp16x8_4, tmp16x8_1, tmp16x8_0);
- vst1q_s16(&inst->noiseEstLogQuantile[offset + i], tmp16x8_2);
-
- // Update density estimate
- // tmp16_1 + tmp16_2
- tmp16x8_1 = vld1q_s16(&inst->noiseEstDensity[offset + i]);
- tmp16x8_0 = vqrdmulhq_s16(tmp16x8_1, countProd_16x8);
- tmp16x8_0 = vaddq_s16(tmp16x8_0, prod16x8);
-
- // lmagn[i] - inst->noiseEstLogQuantile[offset + i]
- tmp16x8_3 = vsubq_s16(tmp16x8_3, tmp16x8_2);
- tmp16x8_3 = vabsq_s16(tmp16x8_3);
- tmp16x8_4 = vcgtq_s16(WIDTHQ8_16x8, tmp16x8_3);
- tmp16x8_1 = vbslq_s16(tmp16x8_4, tmp16x8_0, tmp16x8_1);
- vst1q_s16(&inst->noiseEstDensity[offset + i], tmp16x8_1);
- } // End loop over magnitude spectrum
-
- // Last iteration over magnitude spectrum:
- // compute delta
- if (inst->noiseEstDensity[offset + i] > 512) {
- // Get values for deltaBuff by shifting intead of dividing.
- int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i]);
- delta = (int16_t)(FACTOR_Q16 >> (14 - factor));
- } else {
- delta = FACTOR_Q7;
- if (inst->blockIndex < END_STARTUP_LONG) {
- // Smaller step size during startup. This prevents from using
- // unrealistic values causing overflow.
- delta = FACTOR_Q7_STARTUP;
- }
- }
- // update log quantile estimate
- tmp16 = (int16_t)((delta * countDiv) >> 14);
- if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) {
- // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2
- // CounterDiv=1/(inst->counter[s]+1) in Q15
- tmp16 += 2;
- inst->noiseEstLogQuantile[offset + i] += tmp16 / 4;
- } else {
- tmp16 += 1;
- // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2
- // TODO(bjornv): investigate why we need to truncate twice.
- tmp16no2 = (int16_t)((tmp16 / 2) * 3 / 2);
- inst->noiseEstLogQuantile[offset + i] -= tmp16no2;
- if (inst->noiseEstLogQuantile[offset + i] < logval) {
- // logval is the smallest fixed point representation we can have.
- // Values below that will correspond to values in the interval
- // [0, 1], which can't possibly occur.
- inst->noiseEstLogQuantile[offset + i] = logval;
- }
- }
-
- // update density estimate
- if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i])
- < WIDTH_Q8) {
- tmp16no1 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- inst->noiseEstDensity[offset + i], countProd, 15);
- tmp16no2 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
- width_factor, countDiv, 15);
- inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2;
- }
-
-
- if (counter >= END_STARTUP_LONG) {
- inst->noiseEstCounter[s] = 0;
- if (inst->blockIndex >= END_STARTUP_LONG) {
- UpdateNoiseEstimateNeon(inst, offset);
- }
- }
- inst->noiseEstCounter[s]++;
-
- } // end loop over simultaneous estimates
-
- // Sequentially update the noise during startup
- if (inst->blockIndex < END_STARTUP_LONG) {
- UpdateNoiseEstimateNeon(inst, offset);
- }
-
- for (i = 0; i < inst->magnLen; i++) {
- noise[i] = (uint32_t)(inst->noiseEstQuantile[i]); // Q(qNoise)
- }
- (*q_noise) = (int16_t)inst->qNoise;
-}
-
-// Filter the data in the frequency domain, and create spectrum.
-void WebRtcNsx_PrepareSpectrumNeon(NoiseSuppressionFixedC* inst,
- int16_t* freq_buf) {
- assert(inst->magnLen % 8 == 1);
- assert(inst->anaLen2 % 16 == 0);
-
- // (1) Filtering.
-
- // Fixed point C code for the next block is as follows:
- // for (i = 0; i < inst->magnLen; i++) {
- // inst->real[i] = (int16_t)((inst->real[i] *
- // (int16_t)(inst->noiseSupFilter[i])) >> 14); // Q(normData-stages)
- // inst->imag[i] = (int16_t)((inst->imag[i] *
- // (int16_t)(inst->noiseSupFilter[i])) >> 14); // Q(normData-stages)
- // }
-
- int16_t* preal = &inst->real[0];
- int16_t* pimag = &inst->imag[0];
- int16_t* pns_filter = (int16_t*)&inst->noiseSupFilter[0];
- int16_t* pimag_end = pimag + inst->magnLen - 4;
-
- while (pimag < pimag_end) {
- int16x8_t real = vld1q_s16(preal);
- int16x8_t imag = vld1q_s16(pimag);
- int16x8_t ns_filter = vld1q_s16(pns_filter);
-
- int32x4_t tmp_r_0 = vmull_s16(vget_low_s16(real), vget_low_s16(ns_filter));
- int32x4_t tmp_i_0 = vmull_s16(vget_low_s16(imag), vget_low_s16(ns_filter));
- int32x4_t tmp_r_1 = vmull_s16(vget_high_s16(real),
- vget_high_s16(ns_filter));
- int32x4_t tmp_i_1 = vmull_s16(vget_high_s16(imag),
- vget_high_s16(ns_filter));
-
- int16x4_t result_r_0 = vshrn_n_s32(tmp_r_0, 14);
- int16x4_t result_i_0 = vshrn_n_s32(tmp_i_0, 14);
- int16x4_t result_r_1 = vshrn_n_s32(tmp_r_1, 14);
- int16x4_t result_i_1 = vshrn_n_s32(tmp_i_1, 14);
-
- vst1q_s16(preal, vcombine_s16(result_r_0, result_r_1));
- vst1q_s16(pimag, vcombine_s16(result_i_0, result_i_1));
- preal += 8;
- pimag += 8;
- pns_filter += 8;
- }
-
- // Filter the last element
- *preal = (int16_t)((*preal * *pns_filter) >> 14);
- *pimag = (int16_t)((*pimag * *pns_filter) >> 14);
-
- // (2) Create spectrum.
-
- // Fixed point C code for the rest of the function is as follows:
- // freq_buf[0] = inst->real[0];
- // freq_buf[1] = -inst->imag[0];
- // for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
- // freq_buf[j] = inst->real[i];
- // freq_buf[j + 1] = -inst->imag[i];
- // }
- // freq_buf[inst->anaLen] = inst->real[inst->anaLen2];
- // freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2];
-
- preal = &inst->real[0];
- pimag = &inst->imag[0];
- pimag_end = pimag + inst->anaLen2;
- int16_t * freq_buf_start = freq_buf;
- while (pimag < pimag_end) {
- // loop unroll
- int16x8x2_t real_imag_0;
- int16x8x2_t real_imag_1;
- real_imag_0.val[1] = vld1q_s16(pimag);
- real_imag_0.val[0] = vld1q_s16(preal);
- preal += 8;
- pimag += 8;
- real_imag_1.val[1] = vld1q_s16(pimag);
- real_imag_1.val[0] = vld1q_s16(preal);
- preal += 8;
- pimag += 8;
-
- real_imag_0.val[1] = vnegq_s16(real_imag_0.val[1]);
- real_imag_1.val[1] = vnegq_s16(real_imag_1.val[1]);
- vst2q_s16(freq_buf_start, real_imag_0);
- freq_buf_start += 16;
- vst2q_s16(freq_buf_start, real_imag_1);
- freq_buf_start += 16;
- }
- freq_buf[inst->anaLen] = inst->real[inst->anaLen2];
- freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2];
-}
-
-// For the noise supress process, synthesis, read out fully processed segment,
-// and update synthesis buffer.
-void WebRtcNsx_SynthesisUpdateNeon(NoiseSuppressionFixedC* inst,
- int16_t* out_frame,
- int16_t gain_factor) {
- assert(inst->anaLen % 16 == 0);
- assert(inst->blockLen10ms % 16 == 0);
-
- int16_t* preal_start = inst->real;
- const int16_t* pwindow = inst->window;
- int16_t* preal_end = preal_start + inst->anaLen;
- int16_t* psynthesis_buffer = inst->synthesisBuffer;
-
- while (preal_start < preal_end) {
- // Loop unroll.
- int16x8_t window_0 = vld1q_s16(pwindow);
- int16x8_t real_0 = vld1q_s16(preal_start);
- int16x8_t synthesis_buffer_0 = vld1q_s16(psynthesis_buffer);
-
- int16x8_t window_1 = vld1q_s16(pwindow + 8);
- int16x8_t real_1 = vld1q_s16(preal_start + 8);
- int16x8_t synthesis_buffer_1 = vld1q_s16(psynthesis_buffer + 8);
-
- int32x4_t tmp32a_0_low = vmull_s16(vget_low_s16(real_0),
- vget_low_s16(window_0));
- int32x4_t tmp32a_0_high = vmull_s16(vget_high_s16(real_0),
- vget_high_s16(window_0));
-
- int32x4_t tmp32a_1_low = vmull_s16(vget_low_s16(real_1),
- vget_low_s16(window_1));
- int32x4_t tmp32a_1_high = vmull_s16(vget_high_s16(real_1),
- vget_high_s16(window_1));
-
- int16x4_t tmp16a_0_low = vqrshrn_n_s32(tmp32a_0_low, 14);
- int16x4_t tmp16a_0_high = vqrshrn_n_s32(tmp32a_0_high, 14);
-
- int16x4_t tmp16a_1_low = vqrshrn_n_s32(tmp32a_1_low, 14);
- int16x4_t tmp16a_1_high = vqrshrn_n_s32(tmp32a_1_high, 14);
-
- int32x4_t tmp32b_0_low = vmull_n_s16(tmp16a_0_low, gain_factor);
- int32x4_t tmp32b_0_high = vmull_n_s16(tmp16a_0_high, gain_factor);
-
- int32x4_t tmp32b_1_low = vmull_n_s16(tmp16a_1_low, gain_factor);
- int32x4_t tmp32b_1_high = vmull_n_s16(tmp16a_1_high, gain_factor);
-
- int16x4_t tmp16b_0_low = vqrshrn_n_s32(tmp32b_0_low, 13);
- int16x4_t tmp16b_0_high = vqrshrn_n_s32(tmp32b_0_high, 13);
-
- int16x4_t tmp16b_1_low = vqrshrn_n_s32(tmp32b_1_low, 13);
- int16x4_t tmp16b_1_high = vqrshrn_n_s32(tmp32b_1_high, 13);
-
- synthesis_buffer_0 = vqaddq_s16(vcombine_s16(tmp16b_0_low, tmp16b_0_high),
- synthesis_buffer_0);
- synthesis_buffer_1 = vqaddq_s16(vcombine_s16(tmp16b_1_low, tmp16b_1_high),
- synthesis_buffer_1);
- vst1q_s16(psynthesis_buffer, synthesis_buffer_0);
- vst1q_s16(psynthesis_buffer + 8, synthesis_buffer_1);
-
- pwindow += 16;
- preal_start += 16;
- psynthesis_buffer += 16;
- }
-
- // Read out fully processed segment.
- int16_t * p_start = inst->synthesisBuffer;
- int16_t * p_end = inst->synthesisBuffer + inst->blockLen10ms;
- int16_t * p_frame = out_frame;
- while (p_start < p_end) {
- int16x8_t frame_0 = vld1q_s16(p_start);
- vst1q_s16(p_frame, frame_0);
- p_start += 8;
- p_frame += 8;
- }
-
- // Update synthesis buffer.
- int16_t* p_start_src = inst->synthesisBuffer + inst->blockLen10ms;
- int16_t* p_end_src = inst->synthesisBuffer + inst->anaLen;
- int16_t* p_start_dst = inst->synthesisBuffer;
- while (p_start_src < p_end_src) {
- int16x8_t frame = vld1q_s16(p_start_src);
- vst1q_s16(p_start_dst, frame);
- p_start_src += 8;
- p_start_dst += 8;
- }
-
- p_start = inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms;
- p_end = p_start + inst->blockLen10ms;
- int16x8_t zero = vdupq_n_s16(0);
- for (;p_start < p_end; p_start += 8) {
- vst1q_s16(p_start, zero);
- }
-}
-
-// Update analysis buffer for lower band, and window data before FFT.
-void WebRtcNsx_AnalysisUpdateNeon(NoiseSuppressionFixedC* inst,
- int16_t* out,
- int16_t* new_speech) {
- assert(inst->blockLen10ms % 16 == 0);
- assert(inst->anaLen % 16 == 0);
-
- // For lower band update analysis buffer.
- // memcpy(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms,
- // (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->analysisBuffer));
- int16_t* p_start_src = inst->analysisBuffer + inst->blockLen10ms;
- int16_t* p_end_src = inst->analysisBuffer + inst->anaLen;
- int16_t* p_start_dst = inst->analysisBuffer;
- while (p_start_src < p_end_src) {
- int16x8_t frame = vld1q_s16(p_start_src);
- vst1q_s16(p_start_dst, frame);
-
- p_start_src += 8;
- p_start_dst += 8;
- }
-
- // memcpy(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms,
- // new_speech, inst->blockLen10ms * sizeof(*inst->analysisBuffer));
- p_start_src = new_speech;
- p_end_src = new_speech + inst->blockLen10ms;
- p_start_dst = inst->analysisBuffer + inst->anaLen - inst->blockLen10ms;
- while (p_start_src < p_end_src) {
- int16x8_t frame = vld1q_s16(p_start_src);
- vst1q_s16(p_start_dst, frame);
-
- p_start_src += 8;
- p_start_dst += 8;
- }
-
- // Window data before FFT.
- int16_t* p_start_window = (int16_t*) inst->window;
- int16_t* p_start_buffer = inst->analysisBuffer;
- int16_t* p_start_out = out;
- const int16_t* p_end_out = out + inst->anaLen;
-
- // Load the first element to reduce pipeline bubble.
- int16x8_t window = vld1q_s16(p_start_window);
- int16x8_t buffer = vld1q_s16(p_start_buffer);
- p_start_window += 8;
- p_start_buffer += 8;
-
- while (p_start_out < p_end_out) {
- // Unroll loop.
- int32x4_t tmp32_low = vmull_s16(vget_low_s16(window), vget_low_s16(buffer));
- int32x4_t tmp32_high = vmull_s16(vget_high_s16(window),
- vget_high_s16(buffer));
- window = vld1q_s16(p_start_window);
- buffer = vld1q_s16(p_start_buffer);
-
- int16x4_t result_low = vrshrn_n_s32(tmp32_low, 14);
- int16x4_t result_high = vrshrn_n_s32(tmp32_high, 14);
- vst1q_s16(p_start_out, vcombine_s16(result_low, result_high));
-
- p_start_buffer += 8;
- p_start_window += 8;
- p_start_out += 8;
- }
-}
diff --git a/webrtc/modules/audio_processing/ns/nsx_defines.h b/webrtc/modules/audio_processing/ns/nsx_defines.h
deleted file mode 100644
index 862dc3c..0000000
--- a/webrtc/modules/audio_processing/ns/nsx_defines.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_
-
-#define ANAL_BLOCKL_MAX 256 /* Max analysis block length */
-#define HALF_ANAL_BLOCKL 129 /* Half max analysis block length + 1 */
-#define NUM_HIGH_BANDS_MAX 2 /* Max number of high bands */
-#define SIMULT 3
-#define END_STARTUP_LONG 200
-#define END_STARTUP_SHORT 50
-#define FACTOR_Q16 2621440 /* 40 in Q16 */
-#define FACTOR_Q7 5120 /* 40 in Q7 */
-#define FACTOR_Q7_STARTUP 1024 /* 8 in Q7 */
-#define WIDTH_Q8 3 /* 0.01 in Q8 (or 25 ) */
-
-/* PARAMETERS FOR NEW METHOD */
-#define DD_PR_SNR_Q11 2007 /* ~= Q11(0.98) DD update of prior SNR */
-#define ONE_MINUS_DD_PR_SNR_Q11 41 /* DD update of prior SNR */
-#define SPECT_FLAT_TAVG_Q14 4915 /* (0.30) tavg parameter for spectral flatness measure */
-#define SPECT_DIFF_TAVG_Q8 77 /* (0.30) tavg parameter for spectral flatness measure */
-#define PRIOR_UPDATE_Q14 1638 /* Q14(0.1) Update parameter of prior model */
-#define NOISE_UPDATE_Q8 26 /* 26 ~= Q8(0.1) Update parameter for noise */
-
-/* Probability threshold for noise state in speech/noise likelihood. */
-#define ONE_MINUS_PROB_RANGE_Q8 205 /* 205 ~= Q8(0.8) */
-#define HIST_PAR_EST 1000 /* Histogram size for estimation of parameters */
-
-/* FEATURE EXTRACTION CONFIG */
-/* Bin size of histogram */
-#define BIN_SIZE_LRT 10
-/* Scale parameters: multiply dominant peaks of the histograms by scale factor to obtain. */
-/* Thresholds for prior model */
-#define FACTOR_1_LRT_DIFF 6 /* For LRT and spectral difference (5 times bigger) */
-/* For spectral_flatness: used when noise is flatter than speech (10 times bigger). */
-#define FACTOR_2_FLAT_Q10 922
-/* Peak limit for spectral flatness (varies between 0 and 1) */
-#define THRES_PEAK_FLAT 24 /* * 2 * BIN_SIZE_FLAT_FX */
-/* Limit on spacing of two highest peaks in histogram: spacing determined by bin size. */
-#define LIM_PEAK_SPACE_FLAT_DIFF 4 /* * 2 * BIN_SIZE_DIFF_FX */
-/* Limit on relevance of second peak */
-#define LIM_PEAK_WEIGHT_FLAT_DIFF 2
-#define THRES_FLUCT_LRT 10240 /* = 20 * inst->modelUpdate; fluctuation limit of LRT feat. */
-/* Limit on the max and min values for the feature thresholds */
-#define MAX_FLAT_Q10 38912 /* * 2 * BIN_SIZE_FLAT_FX */
-#define MIN_FLAT_Q10 4096 /* * 2 * BIN_SIZE_FLAT_FX */
-#define MAX_DIFF 100 /* * 2 * BIN_SIZE_DIFF_FX */
-#define MIN_DIFF 16 /* * 2 * BIN_SIZE_DIFF_FX */
-/* Criteria of weight of histogram peak to accept/reject feature */
-#define THRES_WEIGHT_FLAT_DIFF 154 /*(int)(0.3*(inst->modelUpdate)) for flatness and difference */
-
-#define STAT_UPDATES 9 /* Update every 512 = 1 << 9 block */
-#define ONE_MINUS_GAMMA_PAUSE_Q8 13 /* ~= Q8(0.05) Update for conservative noise estimate */
-#define GAMMA_NOISE_TRANS_AND_SPEECH_Q8 3 /* ~= Q8(0.01) Update for transition and noise region */
-
-#endif /* WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_ */
diff --git a/webrtc/modules/audio_processing/ns/prior_signal_model.cc b/webrtc/modules/audio_processing/ns/prior_signal_model.cc
new file mode 100644
index 0000000..f25a1e2
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/prior_signal_model.cc
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/prior_signal_model.h"
+
+namespace webrtc {
+
+PriorSignalModel::PriorSignalModel(float lrt_initial_value)
+ : lrt(lrt_initial_value) {}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/prior_signal_model.h b/webrtc/modules/audio_processing/ns/prior_signal_model.h
new file mode 100644
index 0000000..dcfa7ea
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/prior_signal_model.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_
+#define MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_
+
+namespace webrtc {
+
+// Struct for storing the prior signal model parameters.
+struct PriorSignalModel {
+ explicit PriorSignalModel(float lrt_initial_value);
+ PriorSignalModel(const PriorSignalModel&) = delete;
+ PriorSignalModel& operator=(const PriorSignalModel&) = delete;
+
+ float lrt;
+ float flatness_threshold = .5f;
+ float template_diff_threshold = .5f;
+ float lrt_weighting = 1.f;
+ float flatness_weighting = 0.f;
+ float difference_weighting = 0.f;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_
diff --git a/webrtc/modules/audio_processing/ns/prior_signal_model_estimator.cc b/webrtc/modules/audio_processing/ns/prior_signal_model_estimator.cc
new file mode 100644
index 0000000..c814658
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/prior_signal_model_estimator.cc
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/prior_signal_model_estimator.h"
+
+#include <math.h>
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Identifies the first of the two largest peaks in the histogram.
+void FindFirstOfTwoLargestPeaks(
+ float bin_size,
+ rtc::ArrayView<const int, kHistogramSize> spectral_flatness,
+ float* peak_position,
+ int* peak_weight) {
+ RTC_DCHECK(peak_position);
+ RTC_DCHECK(peak_weight);
+
+ int peak_value = 0;
+ int secondary_peak_value = 0;
+ *peak_position = 0.f;
+ float secondary_peak_position = 0.f;
+ *peak_weight = 0;
+ int secondary_peak_weight = 0;
+
+ // Identify the two largest peaks.
+ for (int i = 0; i < kHistogramSize; ++i) {
+ const float bin_mid = (i + 0.5f) * bin_size;
+ if (spectral_flatness[i] > peak_value) {
+ // Found new "first" peak candidate.
+ secondary_peak_value = peak_value;
+ secondary_peak_weight = *peak_weight;
+ secondary_peak_position = *peak_position;
+
+ peak_value = spectral_flatness[i];
+ *peak_weight = spectral_flatness[i];
+ *peak_position = bin_mid;
+ } else if (spectral_flatness[i] > secondary_peak_value) {
+ // Found new "second" peak candidate.
+ secondary_peak_value = spectral_flatness[i];
+ secondary_peak_weight = spectral_flatness[i];
+ secondary_peak_position = bin_mid;
+ }
+ }
+
+ // Merge the peaks if they are close.
+ if ((fabs(secondary_peak_position - *peak_position) < 2 * bin_size) &&
+ (secondary_peak_weight > 0.5f * (*peak_weight))) {
+ *peak_weight += secondary_peak_weight;
+ *peak_position = 0.5f * (*peak_position + secondary_peak_position);
+ }
+}
+
+void UpdateLrt(rtc::ArrayView<const int, kHistogramSize> lrt_histogram,
+ float* prior_model_lrt,
+ bool* low_lrt_fluctuations) {
+ RTC_DCHECK(prior_model_lrt);
+ RTC_DCHECK(low_lrt_fluctuations);
+
+ float average = 0.f;
+ float average_compl = 0.f;
+ float average_squared = 0.f;
+ int count = 0;
+
+ for (int i = 0; i < 10; ++i) {
+ float bin_mid = (i + 0.5f) * kBinSizeLrt;
+ average += lrt_histogram[i] * bin_mid;
+ count += lrt_histogram[i];
+ }
+ if (count > 0) {
+ average = average / count;
+ }
+
+ for (int i = 0; i < kHistogramSize; ++i) {
+ float bin_mid = (i + 0.5f) * kBinSizeLrt;
+ average_squared += lrt_histogram[i] * bin_mid * bin_mid;
+ average_compl += lrt_histogram[i] * bin_mid;
+ }
+ constexpr float kOneFeatureUpdateWindowSize = 1.f / kFeatureUpdateWindowSize;
+ average_squared = average_squared * kOneFeatureUpdateWindowSize;
+ average_compl = average_compl * kOneFeatureUpdateWindowSize;
+
+ // Fluctuation limit of LRT feature.
+ *low_lrt_fluctuations = average_squared - average * average_compl < 0.05f;
+
+ // Get threshold for LRT feature.
+ constexpr float kMaxLrt = 1.f;
+ constexpr float kMinLrt = .2f;
+ if (*low_lrt_fluctuations) {
+ // Very low fluctuation, so likely noise.
+ *prior_model_lrt = kMaxLrt;
+ } else {
+ *prior_model_lrt = std::min(kMaxLrt, std::max(kMinLrt, 1.2f * average));
+ }
+}
+
+} // namespace
+
+PriorSignalModelEstimator::PriorSignalModelEstimator(float lrt_initial_value)
+ : prior_model_(lrt_initial_value) {}
+
+// Extract thresholds for feature parameters and computes the threshold/weights.
+void PriorSignalModelEstimator::Update(const Histograms& histograms) {
+ bool low_lrt_fluctuations;
+ UpdateLrt(histograms.get_lrt(), &prior_model_.lrt, &low_lrt_fluctuations);
+
+ // For spectral flatness and spectral difference: compute the main peaks of
+ // the histograms.
+ float spectral_flatness_peak_position;
+ int spectral_flatness_peak_weight;
+ FindFirstOfTwoLargestPeaks(
+ kBinSizeSpecFlat, histograms.get_spectral_flatness(),
+ &spectral_flatness_peak_position, &spectral_flatness_peak_weight);
+
+ float spectral_diff_peak_position = 0.f;
+ int spectral_diff_peak_weight = 0;
+ FindFirstOfTwoLargestPeaks(kBinSizeSpecDiff, histograms.get_spectral_diff(),
+ &spectral_diff_peak_position,
+ &spectral_diff_peak_weight);
+
+ // Reject if weight of peaks is not large enough, or peak value too small.
+ // Peak limit for spectral flatness (varies between 0 and 1).
+ const int use_spec_flat = spectral_flatness_peak_weight < 0.3f * 500 ||
+ spectral_flatness_peak_position < 0.6f
+ ? 0
+ : 1;
+
+ // Reject if weight of peaks is not large enough or if fluctuation of the LRT
+ // feature are very low, indicating a noise state.
+ const int use_spec_diff =
+ spectral_diff_peak_weight < 0.3f * 500 || low_lrt_fluctuations ? 0 : 1;
+
+ // Update the model.
+ prior_model_.template_diff_threshold = 1.2f * spectral_diff_peak_position;
+ prior_model_.template_diff_threshold =
+ std::min(1.f, std::max(0.16f, prior_model_.template_diff_threshold));
+
+ float one_by_feature_sum = 1.f / (1.f + use_spec_flat + use_spec_diff);
+ prior_model_.lrt_weighting = one_by_feature_sum;
+
+ if (use_spec_flat == 1) {
+ prior_model_.flatness_threshold = 0.9f * spectral_flatness_peak_position;
+ prior_model_.flatness_threshold =
+ std::min(.95f, std::max(0.1f, prior_model_.flatness_threshold));
+ prior_model_.flatness_weighting = one_by_feature_sum;
+ } else {
+ prior_model_.flatness_weighting = 0.f;
+ }
+
+ if (use_spec_diff == 1) {
+ prior_model_.difference_weighting = one_by_feature_sum;
+ } else {
+ prior_model_.difference_weighting = 0.f;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/prior_signal_model_estimator.h b/webrtc/modules/audio_processing/ns/prior_signal_model_estimator.h
new file mode 100644
index 0000000..d178323
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/prior_signal_model_estimator.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_
+
+#include "modules/audio_processing/ns/histograms.h"
+#include "modules/audio_processing/ns/prior_signal_model.h"
+
+namespace webrtc {
+
+// Estimator of the prior signal model parameters.
+class PriorSignalModelEstimator {
+ public:
+ explicit PriorSignalModelEstimator(float lrt_initial_value);
+ PriorSignalModelEstimator(const PriorSignalModelEstimator&) = delete;
+ PriorSignalModelEstimator& operator=(const PriorSignalModelEstimator&) =
+ delete;
+
+ // Updates the model estimate.
+ void Update(const Histograms& h);
+
+ // Returns the estimated model.
+ const PriorSignalModel& get_prior_model() const { return prior_model_; }
+
+ private:
+ PriorSignalModel prior_model_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/ns/quantile_noise_estimator.cc b/webrtc/modules/audio_processing/ns/quantile_noise_estimator.cc
new file mode 100644
index 0000000..bab494f
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/quantile_noise_estimator.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/quantile_noise_estimator.h"
+
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+
+namespace webrtc {
+
+QuantileNoiseEstimator::QuantileNoiseEstimator() {
+ quantile_.fill(0.f);
+ density_.fill(0.3f);
+ log_quantile_.fill(8.f);
+
+ constexpr float kOneBySimult = 1.f / kSimult;
+ for (size_t i = 0; i < kSimult; ++i) {
+ counter_[i] = floor(kLongStartupPhaseBlocks * (i + 1.f) * kOneBySimult);
+ }
+}
+
+void QuantileNoiseEstimator::Estimate(
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ rtc::ArrayView<float, kFftSizeBy2Plus1> noise_spectrum) {
+ std::array<float, kFftSizeBy2Plus1> log_spectrum;
+ LogApproximation(signal_spectrum, log_spectrum);
+
+ int quantile_index_to_return = -1;
+ // Loop over simultaneous estimates.
+ for (int s = 0, k = 0; s < kSimult;
+ ++s, k += static_cast<int>(kFftSizeBy2Plus1)) {
+ const float one_by_counter_plus_1 = 1.f / (counter_[s] + 1.f);
+ for (int i = 0, j = k; i < static_cast<int>(kFftSizeBy2Plus1); ++i, ++j) {
+ // Update log quantile estimate.
+ const float delta = density_[j] > 1.f ? 40.f / density_[j] : 40.f;
+
+ const float multiplier = delta * one_by_counter_plus_1;
+ if (log_spectrum[i] > log_quantile_[j]) {
+ log_quantile_[j] += 0.25f * multiplier;
+ } else {
+ log_quantile_[j] -= 0.75f * multiplier;
+ }
+
+ // Update density estimate.
+ constexpr float kWidth = 0.01f;
+ constexpr float kOneByWidthPlus2 = 1.f / (2.f * kWidth);
+ if (fabs(log_spectrum[i] - log_quantile_[j]) < kWidth) {
+ density_[j] = (counter_[s] * density_[j] + kOneByWidthPlus2) *
+ one_by_counter_plus_1;
+ }
+ }
+
+ if (counter_[s] >= kLongStartupPhaseBlocks) {
+ counter_[s] = 0;
+ if (num_updates_ >= kLongStartupPhaseBlocks) {
+ quantile_index_to_return = k;
+ }
+ }
+
+ ++counter_[s];
+ }
+
+ // Sequentially update the noise during startup.
+ if (num_updates_ < kLongStartupPhaseBlocks) {
+ // Use the last "s" to get noise during startup that differ from zero.
+ quantile_index_to_return = kFftSizeBy2Plus1 * (kSimult - 1);
+ ++num_updates_;
+ }
+
+ if (quantile_index_to_return >= 0) {
+ ExpApproximation(
+ rtc::ArrayView<const float>(&log_quantile_[quantile_index_to_return],
+ kFftSizeBy2Plus1),
+ quantile_);
+ }
+
+ std::copy(quantile_.begin(), quantile_.end(), noise_spectrum.begin());
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/quantile_noise_estimator.h b/webrtc/modules/audio_processing/ns/quantile_noise_estimator.h
new file mode 100644
index 0000000..67d1512
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/quantile_noise_estimator.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_
+
+#include <math.h>
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+
+namespace webrtc {
+
+constexpr int kSimult = 3;
+
+// For quantile noise estimation.
+class QuantileNoiseEstimator {
+ public:
+ QuantileNoiseEstimator();
+ QuantileNoiseEstimator(const QuantileNoiseEstimator&) = delete;
+ QuantileNoiseEstimator& operator=(const QuantileNoiseEstimator&) = delete;
+
+ // Estimate noise.
+ void Estimate(rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ rtc::ArrayView<float, kFftSizeBy2Plus1> noise_spectrum);
+
+ private:
+ std::array<float, kSimult * kFftSizeBy2Plus1> density_;
+ std::array<float, kSimult * kFftSizeBy2Plus1> log_quantile_;
+ std::array<float, kFftSizeBy2Plus1> quantile_;
+ std::array<int, kSimult> counter_;
+ int num_updates_ = 1;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/ns/signal_model.cc b/webrtc/modules/audio_processing/ns/signal_model.cc
new file mode 100644
index 0000000..364bfd0
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/signal_model.cc
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/signal_model.h"
+
+namespace webrtc {
+
+SignalModel::SignalModel() {
+ constexpr float kSfFeatureThr = 0.5f;
+
+ lrt = kLtrFeatureThr;
+ spectral_flatness = kSfFeatureThr;
+ spectral_diff = kSfFeatureThr;
+ avg_log_lrt.fill(kLtrFeatureThr);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/signal_model.h b/webrtc/modules/audio_processing/ns/signal_model.h
new file mode 100644
index 0000000..6614d38
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/signal_model.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_
+#define MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_
+
+#include <array>
+
+#include "modules/audio_processing/ns/ns_common.h"
+
+namespace webrtc {
+
+struct SignalModel {
+ SignalModel();
+ SignalModel(const SignalModel&) = delete;
+ SignalModel& operator=(const SignalModel&) = delete;
+
+ float lrt;
+ float spectral_diff;
+ float spectral_flatness;
+ // Log LRT factor with time-smoothing.
+ std::array<float, kFftSizeBy2Plus1> avg_log_lrt;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_
diff --git a/webrtc/modules/audio_processing/ns/signal_model_estimator.cc b/webrtc/modules/audio_processing/ns/signal_model_estimator.cc
new file mode 100644
index 0000000..67dd3bb
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/signal_model_estimator.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/signal_model_estimator.h"
+
+#include "modules/audio_processing/ns/fast_math.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr float kOneByFftSizeBy2Plus1 = 1.f / kFftSizeBy2Plus1;
+
+// Computes the difference measure between input spectrum and a template/learned
+// noise spectrum.
+float ComputeSpectralDiff(
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> conservative_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ float signal_spectral_sum,
+ float diff_normalization) {
+ // spectral_diff = var(signal_spectrum) - cov(signal_spectrum, magnAvgPause)^2
+ // / var(magnAvgPause)
+
+ // Compute average quantities.
+ float noise_average = 0.f;
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ // Conservative smooth noise spectrum from pause frames.
+ noise_average += conservative_noise_spectrum[i];
+ }
+ noise_average = noise_average * kOneByFftSizeBy2Plus1;
+ float signal_average = signal_spectral_sum * kOneByFftSizeBy2Plus1;
+
+ // Compute variance and covariance quantities.
+ float covariance = 0.f;
+ float noise_variance = 0.f;
+ float signal_variance = 0.f;
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ float signal_diff = signal_spectrum[i] - signal_average;
+ float noise_diff = conservative_noise_spectrum[i] - noise_average;
+ covariance += signal_diff * noise_diff;
+ noise_variance += noise_diff * noise_diff;
+ signal_variance += signal_diff * signal_diff;
+ }
+ covariance *= kOneByFftSizeBy2Plus1;
+ noise_variance *= kOneByFftSizeBy2Plus1;
+ signal_variance *= kOneByFftSizeBy2Plus1;
+
+ // Update of average magnitude spectrum.
+ float spectral_diff =
+ signal_variance - (covariance * covariance) / (noise_variance + 0.0001f);
+ // Normalize.
+ return spectral_diff / (diff_normalization + 0.0001f);
+}
+
+// Updates the spectral flatness based on the input spectrum.
+void UpdateSpectralFlatness(
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ float signal_spectral_sum,
+ float* spectral_flatness) {
+ RTC_DCHECK(spectral_flatness);
+
+ // Compute log of ratio of the geometric to arithmetic mean (handle the log(0)
+ // separately).
+ constexpr float kAveraging = 0.3f;
+ float avg_spect_flatness_num = 0.f;
+ for (size_t i = 1; i < kFftSizeBy2Plus1; ++i) {
+ if (signal_spectrum[i] == 0.f) {
+ *spectral_flatness -= kAveraging * (*spectral_flatness);
+ return;
+ }
+ }
+
+ for (size_t i = 1; i < kFftSizeBy2Plus1; ++i) {
+ avg_spect_flatness_num += LogApproximation(signal_spectrum[i]);
+ }
+
+ float avg_spect_flatness_denom = signal_spectral_sum - signal_spectrum[0];
+
+ avg_spect_flatness_denom = avg_spect_flatness_denom * kOneByFftSizeBy2Plus1;
+ avg_spect_flatness_num = avg_spect_flatness_num * kOneByFftSizeBy2Plus1;
+
+ float spectral_tmp =
+ ExpApproximation(avg_spect_flatness_num) / avg_spect_flatness_denom;
+
+ // Time-avg update of spectral flatness feature.
+ *spectral_flatness += kAveraging * (spectral_tmp - *spectral_flatness);
+}
+
+// Updates the log LRT measures.
+void UpdateSpectralLrt(rtc::ArrayView<const float, kFftSizeBy2Plus1> prior_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> post_snr,
+ rtc::ArrayView<float, kFftSizeBy2Plus1> avg_log_lrt,
+ float* lrt) {
+ RTC_DCHECK(lrt);
+
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ float tmp1 = 1.f + 2.f * prior_snr[i];
+ float tmp2 = 2.f * prior_snr[i] / (tmp1 + 0.0001f);
+ float bessel_tmp = (post_snr[i] + 1.f) * tmp2;
+ avg_log_lrt[i] +=
+ .5f * (bessel_tmp - LogApproximation(tmp1) - avg_log_lrt[i]);
+ }
+
+ float log_lrt_time_avg_k_sum = 0.f;
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ log_lrt_time_avg_k_sum += avg_log_lrt[i];
+ }
+ *lrt = log_lrt_time_avg_k_sum * kOneByFftSizeBy2Plus1;
+}
+
+} // namespace
+
+SignalModelEstimator::SignalModelEstimator()
+ : prior_model_estimator_(kLtrFeatureThr) {}
+
+void SignalModelEstimator::AdjustNormalization(int32_t num_analyzed_frames,
+ float signal_energy) {
+ diff_normalization_ *= num_analyzed_frames;
+ diff_normalization_ += signal_energy;
+ diff_normalization_ /= (num_analyzed_frames + 1);
+}
+
+// Update the noise features.
+void SignalModelEstimator::Update(
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> prior_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> post_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> conservative_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ float signal_spectral_sum,
+ float signal_energy) {
+ // Compute spectral flatness on input spectrum.
+ UpdateSpectralFlatness(signal_spectrum, signal_spectral_sum,
+ &features_.spectral_flatness);
+
+ // Compute difference of input spectrum with learned/estimated noise spectrum.
+ float spectral_diff =
+ ComputeSpectralDiff(conservative_noise_spectrum, signal_spectrum,
+ signal_spectral_sum, diff_normalization_);
+ // Compute time-avg update of difference feature.
+ features_.spectral_diff += 0.3f * (spectral_diff - features_.spectral_diff);
+
+ signal_energy_sum_ += signal_energy;
+
+ // Compute histograms for parameter decisions (thresholds and weights for
+ // features). Parameters are extracted periodically.
+ if (--histogram_analysis_counter_ > 0) {
+ histograms_.Update(features_);
+ } else {
+ // Compute model parameters.
+ prior_model_estimator_.Update(histograms_);
+
+ // Clear histograms for next update.
+ histograms_.Clear();
+
+ histogram_analysis_counter_ = kFeatureUpdateWindowSize;
+
+ // Update every window:
+ // Compute normalization for the spectral difference for next estimation.
+ signal_energy_sum_ = signal_energy_sum_ / kFeatureUpdateWindowSize;
+ diff_normalization_ = 0.5f * (signal_energy_sum_ + diff_normalization_);
+ signal_energy_sum_ = 0.f;
+ }
+
+ // Compute the LRT.
+ UpdateSpectralLrt(prior_snr, post_snr, features_.avg_log_lrt, &features_.lrt);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/signal_model_estimator.h b/webrtc/modules/audio_processing/ns/signal_model_estimator.h
new file mode 100644
index 0000000..58ce00a
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/signal_model_estimator.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/histograms.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/prior_signal_model.h"
+#include "modules/audio_processing/ns/prior_signal_model_estimator.h"
+#include "modules/audio_processing/ns/signal_model.h"
+
+namespace webrtc {
+
+class SignalModelEstimator {
+ public:
+ SignalModelEstimator();
+ SignalModelEstimator(const SignalModelEstimator&) = delete;
+ SignalModelEstimator& operator=(const SignalModelEstimator&) = delete;
+
+ // Compute signal normalization during the initial startup phase.
+ void AdjustNormalization(int32_t num_analyzed_frames, float signal_energy);
+
+ void Update(
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> prior_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> post_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> conservative_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ float signal_spectral_sum,
+ float signal_energy);
+
+ const PriorSignalModel& get_prior_model() const {
+ return prior_model_estimator_.get_prior_model();
+ }
+ const SignalModel& get_model() { return features_; }
+
+ private:
+ float diff_normalization_ = 0.f;
+ float signal_energy_sum_ = 0.f;
+ Histograms histograms_;
+ int histogram_analysis_counter_ = 500;
+ PriorSignalModelEstimator prior_model_estimator_;
+ SignalModel features_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/ns/speech_probability_estimator.cc b/webrtc/modules/audio_processing/ns/speech_probability_estimator.cc
new file mode 100644
index 0000000..fce9bc8
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/speech_probability_estimator.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/speech_probability_estimator.h"
+
+#include <math.h>
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+SpeechProbabilityEstimator::SpeechProbabilityEstimator() {
+ speech_probability_.fill(0.f);
+}
+
+void SpeechProbabilityEstimator::Update(
+ int32_t num_analyzed_frames,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> prior_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> post_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> conservative_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ float signal_spectral_sum,
+ float signal_energy) {
+ // Update models.
+ if (num_analyzed_frames < kLongStartupPhaseBlocks) {
+ signal_model_estimator_.AdjustNormalization(num_analyzed_frames,
+ signal_energy);
+ }
+ signal_model_estimator_.Update(prior_snr, post_snr,
+ conservative_noise_spectrum, signal_spectrum,
+ signal_spectral_sum, signal_energy);
+
+ const SignalModel& model = signal_model_estimator_.get_model();
+ const PriorSignalModel& prior_model =
+ signal_model_estimator_.get_prior_model();
+
+ // Width parameter in sigmoid map for prior model.
+ constexpr float kWidthPrior0 = 4.f;
+ // Width for pause region: lower range, so increase width in tanh map.
+ constexpr float kWidthPrior1 = 2.f * kWidthPrior0;
+
+ // Average LRT feature: use larger width in tanh map for pause regions.
+ float width_prior = model.lrt < prior_model.lrt ? kWidthPrior1 : kWidthPrior0;
+
+ // Compute indicator function: sigmoid map.
+ float indicator0 =
+ 0.5f * (tanh(width_prior * (model.lrt - prior_model.lrt)) + 1.f);
+
+ // Spectral flatness feature: use larger width in tanh map for pause regions.
+ width_prior = model.spectral_flatness > prior_model.flatness_threshold
+ ? kWidthPrior1
+ : kWidthPrior0;
+
+ // Compute indicator function: sigmoid map.
+ float indicator1 =
+ 0.5f * (tanh(1.f * width_prior *
+ (prior_model.flatness_threshold - model.spectral_flatness)) +
+ 1.f);
+
+ // For template spectrum-difference : use larger width in tanh map for pause
+ // regions.
+ width_prior = model.spectral_diff < prior_model.template_diff_threshold
+ ? kWidthPrior1
+ : kWidthPrior0;
+
+ // Compute indicator function: sigmoid map.
+ float indicator2 =
+ 0.5f * (tanh(width_prior * (model.spectral_diff -
+ prior_model.template_diff_threshold)) +
+ 1.f);
+
+ // Combine the indicator function with the feature weights.
+ float ind_prior = prior_model.lrt_weighting * indicator0 +
+ prior_model.flatness_weighting * indicator1 +
+ prior_model.difference_weighting * indicator2;
+
+ // Compute the prior probability.
+ prior_speech_prob_ += 0.1f * (ind_prior - prior_speech_prob_);
+
+ // Make sure probabilities are within range: keep floor to 0.01.
+ prior_speech_prob_ = std::max(std::min(prior_speech_prob_, 1.f), 0.01f);
+
+ // Final speech probability: combine prior model with LR factor:.
+ float gain_prior =
+ (1.f - prior_speech_prob_) / (prior_speech_prob_ + 0.0001f);
+
+ std::array<float, kFftSizeBy2Plus1> inv_lrt;
+ ExpApproximationSignFlip(model.avg_log_lrt, inv_lrt);
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ speech_probability_[i] = 1.f / (1.f + gain_prior * inv_lrt[i]);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/speech_probability_estimator.h b/webrtc/modules/audio_processing/ns/speech_probability_estimator.h
new file mode 100644
index 0000000..259c3b6
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/speech_probability_estimator.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/signal_model_estimator.h"
+
+namespace webrtc {
+
+// Class for estimating the probability of speech.
+class SpeechProbabilityEstimator {
+ public:
+ SpeechProbabilityEstimator();
+ SpeechProbabilityEstimator(const SpeechProbabilityEstimator&) = delete;
+ SpeechProbabilityEstimator& operator=(const SpeechProbabilityEstimator&) =
+ delete;
+
+ // Compute speech probability.
+ void Update(
+ int32_t num_analyzed_frames,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> prior_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> post_snr,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> conservative_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+ float signal_spectral_sum,
+ float signal_energy);
+
+ float get_prior_probability() const { return prior_speech_prob_; }
+ rtc::ArrayView<const float> get_probability() { return speech_probability_; }
+
+ private:
+ SignalModelEstimator signal_model_estimator_;
+ float prior_speech_prob_ = .5f;
+ std::array<float, kFftSizeBy2Plus1> speech_probability_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/ns/suppression_params.cc b/webrtc/modules/audio_processing/ns/suppression_params.cc
new file mode 100644
index 0000000..9a6bd5a
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/suppression_params.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/suppression_params.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+SuppressionParams::SuppressionParams(
+ NsConfig::SuppressionLevel suppression_level) {
+ switch (suppression_level) {
+ case NsConfig::SuppressionLevel::k6dB:
+ over_subtraction_factor = 1.f;
+ // 6 dB attenuation.
+ minimum_attenuating_gain = 0.5f;
+ use_attenuation_adjustment = false;
+ break;
+ case NsConfig::SuppressionLevel::k12dB:
+ over_subtraction_factor = 1.f;
+ // 12 dB attenuation.
+ minimum_attenuating_gain = 0.25f;
+ use_attenuation_adjustment = true;
+ break;
+ case NsConfig::SuppressionLevel::k18dB:
+ over_subtraction_factor = 1.1f;
+ // 18 dB attenuation.
+ minimum_attenuating_gain = 0.125f;
+ use_attenuation_adjustment = true;
+ break;
+ case NsConfig::SuppressionLevel::k21dB:
+ over_subtraction_factor = 1.25f;
+ // 20.9 dB attenuation.
+ minimum_attenuating_gain = 0.09f;
+ use_attenuation_adjustment = true;
+ break;
+ default:
+ RTC_NOTREACHED();
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/suppression_params.h b/webrtc/modules/audio_processing/ns/suppression_params.h
new file mode 100644
index 0000000..ad11977
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/suppression_params.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_
+#define MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_
+
+#include "modules/audio_processing/ns/ns_config.h"
+
+namespace webrtc {
+
+struct SuppressionParams {
+ explicit SuppressionParams(NsConfig::SuppressionLevel suppression_level);
+ SuppressionParams(const SuppressionParams&) = delete;
+ SuppressionParams& operator=(const SuppressionParams&) = delete;
+
+ float over_subtraction_factor;
+ float minimum_attenuating_gain;
+ bool use_attenuation_adjustment;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_
diff --git a/webrtc/modules/audio_processing/ns/wiener_filter.cc b/webrtc/modules/audio_processing/ns/wiener_filter.cc
new file mode 100644
index 0000000..e14b797
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/wiener_filter.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/ns/wiener_filter.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+WienerFilter::WienerFilter(const SuppressionParams& suppression_params)
+ : suppression_params_(suppression_params) {
+ filter_.fill(1.f);
+ initial_spectral_estimate_.fill(0.f);
+ spectrum_prev_process_.fill(0.f);
+}
+
+void WienerFilter::Update(
+ int32_t num_analyzed_frames,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> prev_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> parametric_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum) {
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ // Previous estimate based on previous frame with gain filter.
+ float prev_tsa = spectrum_prev_process_[i] /
+ (prev_noise_spectrum[i] + 0.0001f) * filter_[i];
+
+ // Current estimate.
+ float current_tsa;
+ if (signal_spectrum[i] > noise_spectrum[i]) {
+ current_tsa = signal_spectrum[i] / (noise_spectrum[i] + 0.0001f) - 1.f;
+ } else {
+ current_tsa = 0.f;
+ }
+
+ // Directed decision estimate is sum of two terms: current estimate and
+ // previous estimate.
+ float snr_prior = 0.98f * prev_tsa + (1.f - 0.98f) * current_tsa;
+ filter_[i] =
+ snr_prior / (suppression_params_.over_subtraction_factor + snr_prior);
+ filter_[i] = std::max(std::min(filter_[i], 1.f),
+ suppression_params_.minimum_attenuating_gain);
+ }
+
+ if (num_analyzed_frames < kShortStartupPhaseBlocks) {
+ for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+ initial_spectral_estimate_[i] += signal_spectrum[i];
+ float filter_initial = initial_spectral_estimate_[i] -
+ suppression_params_.over_subtraction_factor *
+ parametric_noise_spectrum[i];
+ filter_initial /= initial_spectral_estimate_[i] + 0.0001f;
+
+ filter_initial = std::max(std::min(filter_initial, 1.f),
+ suppression_params_.minimum_attenuating_gain);
+
+ // Weight the two suppression filters.
+ constexpr float kOnyByShortStartupPhaseBlocks =
+ 1.f / kShortStartupPhaseBlocks;
+ filter_initial *= kShortStartupPhaseBlocks - num_analyzed_frames;
+ filter_[i] *= num_analyzed_frames;
+ filter_[i] += filter_initial;
+ filter_[i] *= kOnyByShortStartupPhaseBlocks;
+ }
+ }
+
+ std::copy(signal_spectrum.begin(), signal_spectrum.end(),
+ spectrum_prev_process_.begin());
+}
+
+float WienerFilter::ComputeOverallScalingFactor(
+ int32_t num_analyzed_frames,
+ float prior_speech_probability,
+ float energy_before_filtering,
+ float energy_after_filtering) const {
+ if (!suppression_params_.use_attenuation_adjustment ||
+ num_analyzed_frames <= kLongStartupPhaseBlocks) {
+ return 1.f;
+ }
+
+ float gain = SqrtFastApproximation(energy_after_filtering /
+ (energy_before_filtering + 1.f));
+
+ // Scaling for new version. Threshold in final energy gain factor calculation.
+ constexpr float kBLim = 0.5f;
+ float scale_factor1 = 1.f;
+ if (gain > kBLim) {
+ scale_factor1 = 1.f + 1.3f * (gain - kBLim);
+ if (gain * scale_factor1 > 1.f) {
+ scale_factor1 = 1.f / gain;
+ }
+ }
+
+ float scale_factor2 = 1.f;
+ if (gain < kBLim) {
+ // Do not reduce scale too much for pause regions: attenuation here should
+ // be controlled by flooring.
+ gain = std::max(gain, suppression_params_.minimum_attenuating_gain);
+ scale_factor2 = 1.f - 0.3f * (kBLim - gain);
+ }
+
+ // Combine both scales with speech/noise prob: note prior
+ // (prior_speech_probability) is not frequency dependent.
+ return prior_speech_probability * scale_factor1 +
+ (1.f - prior_speech_probability) * scale_factor2;
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/ns/wiener_filter.h b/webrtc/modules/audio_processing/ns/wiener_filter.h
new file mode 100644
index 0000000..b55c5dc
--- /dev/null
+++ b/webrtc/modules/audio_processing/ns/wiener_filter.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/suppression_params.h"
+
+namespace webrtc {
+
+// Estimates a Wiener-filter based frequency domain noise reduction filter.
+class WienerFilter {
+ public:
+ explicit WienerFilter(const SuppressionParams& suppression_params);
+ WienerFilter(const WienerFilter&) = delete;
+ WienerFilter& operator=(const WienerFilter&) = delete;
+
+ // Updates the filter estimate.
+ void Update(
+ int32_t num_analyzed_frames,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> prev_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> parametric_noise_spectrum,
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum);
+
+ // Compute an overall gain scaling factor.
+ float ComputeOverallScalingFactor(int32_t num_analyzed_frames,
+ float prior_speech_probability,
+ float energy_before_filtering,
+ float energy_after_filtering) const;
+
+ // Returns the filter.
+ rtc::ArrayView<const float, kFftSizeBy2Plus1> get_filter() const {
+ return filter_;
+ }
+
+ private:
+ const SuppressionParams& suppression_params_;
+ std::array<float, kFftSizeBy2Plus1> spectrum_prev_process_;
+ std::array<float, kFftSizeBy2Plus1> initial_spectral_estimate_;
+ std::array<float, kFftSizeBy2Plus1> filter_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_
diff --git a/webrtc/modules/audio_processing/ns/windows_private.h b/webrtc/modules/audio_processing/ns/windows_private.h
deleted file mode 100644
index 44c2e84..0000000
--- a/webrtc/modules/audio_processing/ns/windows_private.h
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * 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 WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_
-
-// Hanning window for 4ms 16kHz
-static const float kHanning64w128[128] = {
- 0.00000000000000f, 0.02454122852291f, 0.04906767432742f,
- 0.07356456359967f, 0.09801714032956f, 0.12241067519922f,
- 0.14673047445536f, 0.17096188876030f, 0.19509032201613f,
- 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
- 0.29028467725446f, 0.31368174039889f, 0.33688985339222f,
- 0.35989503653499f, 0.38268343236509f, 0.40524131400499f,
- 0.42755509343028f, 0.44961132965461f, 0.47139673682600f,
- 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
- 0.55557023301960f, 0.57580819141785f, 0.59569930449243f,
- 0.61523159058063f, 0.63439328416365f, 0.65317284295378f,
- 0.67155895484702f, 0.68954054473707f, 0.70710678118655f,
- 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
- 0.77301045336274f, 0.78834642762661f, 0.80320753148064f,
- 0.81758481315158f, 0.83146961230255f, 0.84485356524971f,
- 0.85772861000027f, 0.87008699110871f, 0.88192126434835f,
- 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
- 0.92387953251129f, 0.93299279883474f, 0.94154406518302f,
- 0.94952818059304f, 0.95694033573221f, 0.96377606579544f,
- 0.97003125319454f, 0.97570213003853f, 0.98078528040323f,
- 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
- 0.99518472667220f, 0.99729045667869f, 0.99879545620517f,
- 0.99969881869620f, 1.00000000000000f,
- 0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
- 0.99518472667220f, 0.99247953459871f, 0.98917650996478f,
- 0.98527764238894f, 0.98078528040323f, 0.97570213003853f,
- 0.97003125319454f, 0.96377606579544f, 0.95694033573221f,
- 0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
- 0.92387953251129f, 0.91420975570353f, 0.90398929312344f,
- 0.89322430119552f, 0.88192126434835f, 0.87008699110871f,
- 0.85772861000027f, 0.84485356524971f, 0.83146961230255f,
- 0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
- 0.77301045336274f, 0.75720884650648f, 0.74095112535496f,
- 0.72424708295147f, 0.70710678118655f, 0.68954054473707f,
- 0.67155895484702f, 0.65317284295378f, 0.63439328416365f,
- 0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
- 0.55557023301960f, 0.53499761988710f, 0.51410274419322f,
- 0.49289819222978f, 0.47139673682600f, 0.44961132965461f,
- 0.42755509343028f, 0.40524131400499f, 0.38268343236509f,
- 0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
- 0.29028467725446f, 0.26671275747490f, 0.24298017990326f,
- 0.21910124015687f, 0.19509032201613f, 0.17096188876030f,
- 0.14673047445536f, 0.12241067519922f, 0.09801714032956f,
- 0.07356456359967f, 0.04906767432742f, 0.02454122852291f
-};
-
-
-
-// hybrib Hanning & flat window
-static const float kBlocks80w128[128] = {
- (float)0.00000000, (float)0.03271908, (float)0.06540313, (float)0.09801714, (float)0.13052619,
- (float)0.16289547, (float)0.19509032, (float)0.22707626, (float)0.25881905, (float)0.29028468,
- (float)0.32143947, (float)0.35225005, (float)0.38268343, (float)0.41270703, (float)0.44228869,
- (float)0.47139674, (float)0.50000000, (float)0.52806785, (float)0.55557023, (float)0.58247770,
- (float)0.60876143, (float)0.63439328, (float)0.65934582, (float)0.68359230, (float)0.70710678,
- (float)0.72986407, (float)0.75183981, (float)0.77301045, (float)0.79335334, (float)0.81284668,
- (float)0.83146961, (float)0.84920218, (float)0.86602540, (float)0.88192126, (float)0.89687274,
- (float)0.91086382, (float)0.92387953, (float)0.93590593, (float)0.94693013, (float)0.95694034,
- (float)0.96592583, (float)0.97387698, (float)0.98078528, (float)0.98664333, (float)0.99144486,
- (float)0.99518473, (float)0.99785892, (float)0.99946459, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)0.99946459, (float)0.99785892, (float)0.99518473, (float)0.99144486,
- (float)0.98664333, (float)0.98078528, (float)0.97387698, (float)0.96592583, (float)0.95694034,
- (float)0.94693013, (float)0.93590593, (float)0.92387953, (float)0.91086382, (float)0.89687274,
- (float)0.88192126, (float)0.86602540, (float)0.84920218, (float)0.83146961, (float)0.81284668,
- (float)0.79335334, (float)0.77301045, (float)0.75183981, (float)0.72986407, (float)0.70710678,
- (float)0.68359230, (float)0.65934582, (float)0.63439328, (float)0.60876143, (float)0.58247770,
- (float)0.55557023, (float)0.52806785, (float)0.50000000, (float)0.47139674, (float)0.44228869,
- (float)0.41270703, (float)0.38268343, (float)0.35225005, (float)0.32143947, (float)0.29028468,
- (float)0.25881905, (float)0.22707626, (float)0.19509032, (float)0.16289547, (float)0.13052619,
- (float)0.09801714, (float)0.06540313, (float)0.03271908
-};
-
-// hybrib Hanning & flat window
-static const float kBlocks160w256[256] = {
- (float)0.00000000, (float)0.01636173, (float)0.03271908, (float)0.04906767, (float)0.06540313,
- (float)0.08172107, (float)0.09801714, (float)0.11428696, (float)0.13052619, (float)0.14673047,
- (float)0.16289547, (float)0.17901686, (float)0.19509032, (float)0.21111155, (float)0.22707626,
- (float)0.24298018, (float)0.25881905, (float)0.27458862, (float)0.29028468, (float)0.30590302,
- (float)0.32143947, (float)0.33688985, (float)0.35225005, (float)0.36751594, (float)0.38268343,
- (float)0.39774847, (float)0.41270703, (float)0.42755509, (float)0.44228869, (float)0.45690388,
- (float)0.47139674, (float)0.48576339, (float)0.50000000, (float)0.51410274, (float)0.52806785,
- (float)0.54189158, (float)0.55557023, (float)0.56910015, (float)0.58247770, (float)0.59569930,
- (float)0.60876143, (float)0.62166057, (float)0.63439328, (float)0.64695615, (float)0.65934582,
- (float)0.67155895, (float)0.68359230, (float)0.69544264, (float)0.70710678, (float)0.71858162,
- (float)0.72986407, (float)0.74095113, (float)0.75183981, (float)0.76252720, (float)0.77301045,
- (float)0.78328675, (float)0.79335334, (float)0.80320753, (float)0.81284668, (float)0.82226822,
- (float)0.83146961, (float)0.84044840, (float)0.84920218, (float)0.85772861, (float)0.86602540,
- (float)0.87409034, (float)0.88192126, (float)0.88951608, (float)0.89687274, (float)0.90398929,
- (float)0.91086382, (float)0.91749450, (float)0.92387953, (float)0.93001722, (float)0.93590593,
- (float)0.94154407, (float)0.94693013, (float)0.95206268, (float)0.95694034, (float)0.96156180,
- (float)0.96592583, (float)0.97003125, (float)0.97387698, (float)0.97746197, (float)0.98078528,
- (float)0.98384601, (float)0.98664333, (float)0.98917651, (float)0.99144486, (float)0.99344778,
- (float)0.99518473, (float)0.99665524, (float)0.99785892, (float)0.99879546, (float)0.99946459,
- (float)0.99986614, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)0.99986614, (float)0.99946459, (float)0.99879546, (float)0.99785892,
- (float)0.99665524, (float)0.99518473, (float)0.99344778, (float)0.99144486, (float)0.98917651,
- (float)0.98664333, (float)0.98384601, (float)0.98078528, (float)0.97746197, (float)0.97387698,
- (float)0.97003125, (float)0.96592583, (float)0.96156180, (float)0.95694034, (float)0.95206268,
- (float)0.94693013, (float)0.94154407, (float)0.93590593, (float)0.93001722, (float)0.92387953,
- (float)0.91749450, (float)0.91086382, (float)0.90398929, (float)0.89687274, (float)0.88951608,
- (float)0.88192126, (float)0.87409034, (float)0.86602540, (float)0.85772861, (float)0.84920218,
- (float)0.84044840, (float)0.83146961, (float)0.82226822, (float)0.81284668, (float)0.80320753,
- (float)0.79335334, (float)0.78328675, (float)0.77301045, (float)0.76252720, (float)0.75183981,
- (float)0.74095113, (float)0.72986407, (float)0.71858162, (float)0.70710678, (float)0.69544264,
- (float)0.68359230, (float)0.67155895, (float)0.65934582, (float)0.64695615, (float)0.63439328,
- (float)0.62166057, (float)0.60876143, (float)0.59569930, (float)0.58247770, (float)0.56910015,
- (float)0.55557023, (float)0.54189158, (float)0.52806785, (float)0.51410274, (float)0.50000000,
- (float)0.48576339, (float)0.47139674, (float)0.45690388, (float)0.44228869, (float)0.42755509,
- (float)0.41270703, (float)0.39774847, (float)0.38268343, (float)0.36751594, (float)0.35225005,
- (float)0.33688985, (float)0.32143947, (float)0.30590302, (float)0.29028468, (float)0.27458862,
- (float)0.25881905, (float)0.24298018, (float)0.22707626, (float)0.21111155, (float)0.19509032,
- (float)0.17901686, (float)0.16289547, (float)0.14673047, (float)0.13052619, (float)0.11428696,
- (float)0.09801714, (float)0.08172107, (float)0.06540313, (float)0.04906767, (float)0.03271908,
- (float)0.01636173
-};
-
-// hybrib Hanning & flat window: for 20ms
-static const float kBlocks320w512[512] = {
- (float)0.00000000, (float)0.00818114, (float)0.01636173, (float)0.02454123, (float)0.03271908,
- (float)0.04089475, (float)0.04906767, (float)0.05723732, (float)0.06540313, (float)0.07356456,
- (float)0.08172107, (float)0.08987211, (float)0.09801714, (float)0.10615561, (float)0.11428696,
- (float)0.12241068, (float)0.13052619, (float)0.13863297, (float)0.14673047, (float)0.15481816,
- (float)0.16289547, (float)0.17096189, (float)0.17901686, (float)0.18705985, (float)0.19509032,
- (float)0.20310773, (float)0.21111155, (float)0.21910124, (float)0.22707626, (float)0.23503609,
- (float)0.24298018, (float)0.25090801, (float)0.25881905, (float)0.26671276, (float)0.27458862,
- (float)0.28244610, (float)0.29028468, (float)0.29810383, (float)0.30590302, (float)0.31368174,
- (float)0.32143947, (float)0.32917568, (float)0.33688985, (float)0.34458148, (float)0.35225005,
- (float)0.35989504, (float)0.36751594, (float)0.37511224, (float)0.38268343, (float)0.39022901,
- (float)0.39774847, (float)0.40524131, (float)0.41270703, (float)0.42014512, (float)0.42755509,
- (float)0.43493645, (float)0.44228869, (float)0.44961133, (float)0.45690388, (float)0.46416584,
- (float)0.47139674, (float)0.47859608, (float)0.48576339, (float)0.49289819, (float)0.50000000,
- (float)0.50706834, (float)0.51410274, (float)0.52110274, (float)0.52806785, (float)0.53499762,
- (float)0.54189158, (float)0.54874927, (float)0.55557023, (float)0.56235401, (float)0.56910015,
- (float)0.57580819, (float)0.58247770, (float)0.58910822, (float)0.59569930, (float)0.60225052,
- (float)0.60876143, (float)0.61523159, (float)0.62166057, (float)0.62804795, (float)0.63439328,
- (float)0.64069616, (float)0.64695615, (float)0.65317284, (float)0.65934582, (float)0.66547466,
- (float)0.67155895, (float)0.67759830, (float)0.68359230, (float)0.68954054, (float)0.69544264,
- (float)0.70129818, (float)0.70710678, (float)0.71286806, (float)0.71858162, (float)0.72424708,
- (float)0.72986407, (float)0.73543221, (float)0.74095113, (float)0.74642045, (float)0.75183981,
- (float)0.75720885, (float)0.76252720, (float)0.76779452, (float)0.77301045, (float)0.77817464,
- (float)0.78328675, (float)0.78834643, (float)0.79335334, (float)0.79830715, (float)0.80320753,
- (float)0.80805415, (float)0.81284668, (float)0.81758481, (float)0.82226822, (float)0.82689659,
- (float)0.83146961, (float)0.83598698, (float)0.84044840, (float)0.84485357, (float)0.84920218,
- (float)0.85349396, (float)0.85772861, (float)0.86190585, (float)0.86602540, (float)0.87008699,
- (float)0.87409034, (float)0.87803519, (float)0.88192126, (float)0.88574831, (float)0.88951608,
- (float)0.89322430, (float)0.89687274, (float)0.90046115, (float)0.90398929, (float)0.90745693,
- (float)0.91086382, (float)0.91420976, (float)0.91749450, (float)0.92071783, (float)0.92387953,
- (float)0.92697940, (float)0.93001722, (float)0.93299280, (float)0.93590593, (float)0.93875641,
- (float)0.94154407, (float)0.94426870, (float)0.94693013, (float)0.94952818, (float)0.95206268,
- (float)0.95453345, (float)0.95694034, (float)0.95928317, (float)0.96156180, (float)0.96377607,
- (float)0.96592583, (float)0.96801094, (float)0.97003125, (float)0.97198664, (float)0.97387698,
- (float)0.97570213, (float)0.97746197, (float)0.97915640, (float)0.98078528, (float)0.98234852,
- (float)0.98384601, (float)0.98527764, (float)0.98664333, (float)0.98794298, (float)0.98917651,
- (float)0.99034383, (float)0.99144486, (float)0.99247953, (float)0.99344778, (float)0.99434953,
- (float)0.99518473, (float)0.99595331, (float)0.99665524, (float)0.99729046, (float)0.99785892,
- (float)0.99836060, (float)0.99879546, (float)0.99916346, (float)0.99946459, (float)0.99969882,
- (float)0.99986614, (float)0.99996653, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
- (float)1.00000000, (float)0.99996653, (float)0.99986614, (float)0.99969882, (float)0.99946459,
- (float)0.99916346, (float)0.99879546, (float)0.99836060, (float)0.99785892, (float)0.99729046,
- (float)0.99665524, (float)0.99595331, (float)0.99518473, (float)0.99434953, (float)0.99344778,
- (float)0.99247953, (float)0.99144486, (float)0.99034383, (float)0.98917651, (float)0.98794298,
- (float)0.98664333, (float)0.98527764, (float)0.98384601, (float)0.98234852, (float)0.98078528,
- (float)0.97915640, (float)0.97746197, (float)0.97570213, (float)0.97387698, (float)0.97198664,
- (float)0.97003125, (float)0.96801094, (float)0.96592583, (float)0.96377607, (float)0.96156180,
- (float)0.95928317, (float)0.95694034, (float)0.95453345, (float)0.95206268, (float)0.94952818,
- (float)0.94693013, (float)0.94426870, (float)0.94154407, (float)0.93875641, (float)0.93590593,
- (float)0.93299280, (float)0.93001722, (float)0.92697940, (float)0.92387953, (float)0.92071783,
- (float)0.91749450, (float)0.91420976, (float)0.91086382, (float)0.90745693, (float)0.90398929,
- (float)0.90046115, (float)0.89687274, (float)0.89322430, (float)0.88951608, (float)0.88574831,
- (float)0.88192126, (float)0.87803519, (float)0.87409034, (float)0.87008699, (float)0.86602540,
- (float)0.86190585, (float)0.85772861, (float)0.85349396, (float)0.84920218, (float)0.84485357,
- (float)0.84044840, (float)0.83598698, (float)0.83146961, (float)0.82689659, (float)0.82226822,
- (float)0.81758481, (float)0.81284668, (float)0.80805415, (float)0.80320753, (float)0.79830715,
- (float)0.79335334, (float)0.78834643, (float)0.78328675, (float)0.77817464, (float)0.77301045,
- (float)0.76779452, (float)0.76252720, (float)0.75720885, (float)0.75183981, (float)0.74642045,
- (float)0.74095113, (float)0.73543221, (float)0.72986407, (float)0.72424708, (float)0.71858162,
- (float)0.71286806, (float)0.70710678, (float)0.70129818, (float)0.69544264, (float)0.68954054,
- (float)0.68359230, (float)0.67759830, (float)0.67155895, (float)0.66547466, (float)0.65934582,
- (float)0.65317284, (float)0.64695615, (float)0.64069616, (float)0.63439328, (float)0.62804795,
- (float)0.62166057, (float)0.61523159, (float)0.60876143, (float)0.60225052, (float)0.59569930,
- (float)0.58910822, (float)0.58247770, (float)0.57580819, (float)0.56910015, (float)0.56235401,
- (float)0.55557023, (float)0.54874927, (float)0.54189158, (float)0.53499762, (float)0.52806785,
- (float)0.52110274, (float)0.51410274, (float)0.50706834, (float)0.50000000, (float)0.49289819,
- (float)0.48576339, (float)0.47859608, (float)0.47139674, (float)0.46416584, (float)0.45690388,
- (float)0.44961133, (float)0.44228869, (float)0.43493645, (float)0.42755509, (float)0.42014512,
- (float)0.41270703, (float)0.40524131, (float)0.39774847, (float)0.39022901, (float)0.38268343,
- (float)0.37511224, (float)0.36751594, (float)0.35989504, (float)0.35225005, (float)0.34458148,
- (float)0.33688985, (float)0.32917568, (float)0.32143947, (float)0.31368174, (float)0.30590302,
- (float)0.29810383, (float)0.29028468, (float)0.28244610, (float)0.27458862, (float)0.26671276,
- (float)0.25881905, (float)0.25090801, (float)0.24298018, (float)0.23503609, (float)0.22707626,
- (float)0.21910124, (float)0.21111155, (float)0.20310773, (float)0.19509032, (float)0.18705985,
- (float)0.17901686, (float)0.17096189, (float)0.16289547, (float)0.15481816, (float)0.14673047,
- (float)0.13863297, (float)0.13052619, (float)0.12241068, (float)0.11428696, (float)0.10615561,
- (float)0.09801714, (float)0.08987211, (float)0.08172107, (float)0.07356456, (float)0.06540313,
- (float)0.05723732, (float)0.04906767, (float)0.04089475, (float)0.03271908, (float)0.02454123,
- (float)0.01636173, (float)0.00818114
-};
-
-
-// Hanning window: for 15ms at 16kHz with symmetric zeros
-static const float kBlocks240w512[512] = {
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00654494, (float)0.01308960, (float)0.01963369,
- (float)0.02617695, (float)0.03271908, (float)0.03925982, (float)0.04579887, (float)0.05233596,
- (float)0.05887080, (float)0.06540313, (float)0.07193266, (float)0.07845910, (float)0.08498218,
- (float)0.09150162, (float)0.09801714, (float)0.10452846, (float)0.11103531, (float)0.11753740,
- (float)0.12403446, (float)0.13052620, (float)0.13701233, (float)0.14349262, (float)0.14996676,
- (float)0.15643448, (float)0.16289547, (float)0.16934951, (float)0.17579629, (float)0.18223552,
- (float)0.18866697, (float)0.19509032, (float)0.20150533, (float)0.20791170, (float)0.21430916,
- (float)0.22069745, (float)0.22707628, (float)0.23344538, (float)0.23980446, (float)0.24615330,
- (float)0.25249159, (float)0.25881904, (float)0.26513544, (float)0.27144045, (float)0.27773386,
- (float)0.28401536, (float)0.29028466, (float)0.29654160, (float)0.30278578, (float)0.30901700,
- (float)0.31523499, (float)0.32143945, (float)0.32763019, (float)0.33380687, (float)0.33996925,
- (float)0.34611708, (float)0.35225007, (float)0.35836795, (float)0.36447051, (float)0.37055743,
- (float)0.37662852, (float)0.38268346, (float)0.38872197, (float)0.39474389, (float)0.40074885,
- (float)0.40673664, (float)0.41270703, (float)0.41865975, (float)0.42459452, (float)0.43051112,
- (float)0.43640924, (float)0.44228873, (float)0.44814920, (float)0.45399052, (float)0.45981237,
- (float)0.46561453, (float)0.47139674, (float)0.47715878, (float)0.48290035, (float)0.48862126,
- (float)0.49432120, (float)0.50000000, (float)0.50565743, (float)0.51129311, (float)0.51690692,
- (float)0.52249855, (float)0.52806789, (float)0.53361452, (float)0.53913832, (float)0.54463905,
- (float)0.55011642, (float)0.55557024, (float)0.56100029, (float)0.56640625, (float)0.57178795,
- (float)0.57714522, (float)0.58247769, (float)0.58778524, (float)0.59306765, (float)0.59832460,
- (float)0.60355598, (float)0.60876143, (float)0.61394083, (float)0.61909395, (float)0.62422055,
- (float)0.62932038, (float)0.63439333, (float)0.63943899, (float)0.64445734, (float)0.64944810,
- (float)0.65441096, (float)0.65934587, (float)0.66425246, (float)0.66913062, (float)0.67398012,
- (float)0.67880076, (float)0.68359232, (float)0.68835455, (float)0.69308740, (float)0.69779050,
- (float)0.70246369, (float)0.70710677, (float)0.71171963, (float)0.71630198, (float)0.72085363,
- (float)0.72537440, (float)0.72986406, (float)0.73432255, (float)0.73874950, (float)0.74314487,
- (float)0.74750835, (float)0.75183982, (float)0.75613910, (float)0.76040596, (float)0.76464027,
- (float)0.76884186, (float)0.77301043, (float)0.77714598, (float)0.78124821, (float)0.78531694,
- (float)0.78935206, (float)0.79335338, (float)0.79732066, (float)0.80125386, (float)0.80515265,
- (float)0.80901700, (float)0.81284672, (float)0.81664157, (float)0.82040149, (float)0.82412618,
- (float)0.82781565, (float)0.83146966, (float)0.83508795, (float)0.83867061, (float)0.84221727,
- (float)0.84572780, (float)0.84920216, (float)0.85264021, (float)0.85604161, (float)0.85940641,
- (float)0.86273444, (float)0.86602545, (float)0.86927933, (float)0.87249607, (float)0.87567532,
- (float)0.87881714, (float)0.88192129, (float)0.88498765, (float)0.88801610, (float)0.89100653,
- (float)0.89395881, (float)0.89687276, (float)0.89974827, (float)0.90258533, (float)0.90538365,
- (float)0.90814316, (float)0.91086388, (float)0.91354549, (float)0.91618794, (float)0.91879123,
- (float)0.92135513, (float)0.92387950, (float)0.92636442, (float)0.92880958, (float)0.93121493,
- (float)0.93358046, (float)0.93590593, (float)0.93819135, (float)0.94043654, (float)0.94264150,
- (float)0.94480604, (float)0.94693011, (float)0.94901365, (float)0.95105654, (float)0.95305866,
- (float)0.95501995, (float)0.95694035, (float)0.95881975, (float)0.96065807, (float)0.96245527,
- (float)0.96421117, (float)0.96592581, (float)0.96759909, (float)0.96923089, (float)0.97082120,
- (float)0.97236991, (float)0.97387701, (float)0.97534233, (float)0.97676587, (float)0.97814763,
- (float)0.97948742, (float)0.98078531, (float)0.98204112, (float)0.98325491, (float)0.98442656,
- (float)0.98555607, (float)0.98664331, (float)0.98768836, (float)0.98869103, (float)0.98965138,
- (float)0.99056935, (float)0.99144489, (float)0.99227792, (float)0.99306846, (float)0.99381649,
- (float)0.99452192, (float)0.99518472, (float)0.99580491, (float)0.99638247, (float)0.99691731,
- (float)0.99740952, (float)0.99785894, (float)0.99826562, (float)0.99862951, (float)0.99895066,
- (float)0.99922901, (float)0.99946457, (float)0.99965733, (float)0.99980724, (float)0.99991435,
- (float)0.99997860, (float)1.00000000, (float)0.99997860, (float)0.99991435, (float)0.99980724,
- (float)0.99965733, (float)0.99946457, (float)0.99922901, (float)0.99895066, (float)0.99862951,
- (float)0.99826562, (float)0.99785894, (float)0.99740946, (float)0.99691731, (float)0.99638247,
- (float)0.99580491, (float)0.99518472, (float)0.99452192, (float)0.99381644, (float)0.99306846,
- (float)0.99227792, (float)0.99144489, (float)0.99056935, (float)0.98965138, (float)0.98869103,
- (float)0.98768836, (float)0.98664331, (float)0.98555607, (float)0.98442656, (float)0.98325491,
- (float)0.98204112, (float)0.98078525, (float)0.97948742, (float)0.97814757, (float)0.97676587,
- (float)0.97534227, (float)0.97387695, (float)0.97236991, (float)0.97082120, (float)0.96923089,
- (float)0.96759909, (float)0.96592581, (float)0.96421117, (float)0.96245521, (float)0.96065807,
- (float)0.95881969, (float)0.95694029, (float)0.95501995, (float)0.95305860, (float)0.95105648,
- (float)0.94901365, (float)0.94693011, (float)0.94480604, (float)0.94264150, (float)0.94043654,
- (float)0.93819129, (float)0.93590593, (float)0.93358046, (float)0.93121493, (float)0.92880952,
- (float)0.92636436, (float)0.92387950, (float)0.92135507, (float)0.91879123, (float)0.91618794,
- (float)0.91354543, (float)0.91086382, (float)0.90814310, (float)0.90538365, (float)0.90258527,
- (float)0.89974827, (float)0.89687276, (float)0.89395875, (float)0.89100647, (float)0.88801610,
- (float)0.88498759, (float)0.88192123, (float)0.87881714, (float)0.87567532, (float)0.87249595,
- (float)0.86927933, (float)0.86602539, (float)0.86273432, (float)0.85940641, (float)0.85604161,
- (float)0.85264009, (float)0.84920216, (float)0.84572780, (float)0.84221715, (float)0.83867055,
- (float)0.83508795, (float)0.83146954, (float)0.82781565, (float)0.82412612, (float)0.82040137,
- (float)0.81664157, (float)0.81284660, (float)0.80901700, (float)0.80515265, (float)0.80125374,
- (float)0.79732066, (float)0.79335332, (float)0.78935200, (float)0.78531694, (float)0.78124815,
- (float)0.77714586, (float)0.77301049, (float)0.76884180, (float)0.76464021, (float)0.76040596,
- (float)0.75613904, (float)0.75183970, (float)0.74750835, (float)0.74314481, (float)0.73874938,
- (float)0.73432249, (float)0.72986400, (float)0.72537428, (float)0.72085363, (float)0.71630186,
- (float)0.71171951, (float)0.70710677, (float)0.70246363, (float)0.69779032, (float)0.69308734,
- (float)0.68835449, (float)0.68359220, (float)0.67880070, (float)0.67398006, (float)0.66913044,
- (float)0.66425240, (float)0.65934575, (float)0.65441096, (float)0.64944804, (float)0.64445722,
- (float)0.63943905, (float)0.63439327, (float)0.62932026, (float)0.62422055, (float)0.61909389,
- (float)0.61394072, (float)0.60876143, (float)0.60355592, (float)0.59832448, (float)0.59306765,
- (float)0.58778518, (float)0.58247757, (float)0.57714522, (float)0.57178789, (float)0.56640613,
- (float)0.56100023, (float)0.55557019, (float)0.55011630, (float)0.54463905, (float)0.53913826,
- (float)0.53361434, (float)0.52806783, (float)0.52249849, (float)0.51690674, (float)0.51129305,
- (float)0.50565726, (float)0.50000006, (float)0.49432117, (float)0.48862115, (float)0.48290038,
- (float)0.47715873, (float)0.47139663, (float)0.46561456, (float)0.45981231, (float)0.45399037,
- (float)0.44814920, (float)0.44228864, (float)0.43640912, (float)0.43051112, (float)0.42459446,
- (float)0.41865960, (float)0.41270703, (float)0.40673658, (float)0.40074870, (float)0.39474386,
- (float)0.38872188, (float)0.38268328, (float)0.37662849, (float)0.37055734, (float)0.36447033,
- (float)0.35836792, (float)0.35224995, (float)0.34611690, (float)0.33996922, (float)0.33380675,
- (float)0.32763001, (float)0.32143945, (float)0.31523487, (float)0.30901679, (float)0.30278572,
- (float)0.29654145, (float)0.29028472, (float)0.28401530, (float)0.27773371, (float)0.27144048,
- (float)0.26513538, (float)0.25881892, (float)0.25249159, (float)0.24615324, (float)0.23980433,
- (float)0.23344538, (float)0.22707619, (float)0.22069728, (float)0.21430916, (float)0.20791161,
- (float)0.20150517, (float)0.19509031, (float)0.18866688, (float)0.18223536, (float)0.17579627,
- (float)0.16934940, (float)0.16289529, (float)0.15643445, (float)0.14996666, (float)0.14349243,
- (float)0.13701232, (float)0.13052608, (float)0.12403426, (float)0.11753736, (float)0.11103519,
- (float)0.10452849, (float)0.09801710, (float)0.09150149, (float)0.08498220, (float)0.07845904,
- (float)0.07193252, (float)0.06540315, (float)0.05887074, (float)0.05233581, (float)0.04579888,
- (float)0.03925974, (float)0.03271893, (float)0.02617695, (float)0.01963361, (float)0.01308943,
- (float)0.00654493, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000
-};
-
-
-// Hanning window: for 30ms with 1024 fft with symmetric zeros at 16kHz
-static const float kBlocks480w1024[1024] = {
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00327249, (float)0.00654494,
- (float)0.00981732, (float)0.01308960, (float)0.01636173, (float)0.01963369, (float)0.02290544,
- (float)0.02617695, (float)0.02944817, (float)0.03271908, (float)0.03598964, (float)0.03925982,
- (float)0.04252957, (float)0.04579887, (float)0.04906768, (float)0.05233596, (float)0.05560368,
- (float)0.05887080, (float)0.06213730, (float)0.06540313, (float)0.06866825, (float)0.07193266,
- (float)0.07519628, (float)0.07845910, (float)0.08172107, (float)0.08498218, (float)0.08824237,
- (float)0.09150162, (float)0.09475989, (float)0.09801714, (float)0.10127335, (float)0.10452846,
- (float)0.10778246, (float)0.11103531, (float)0.11428697, (float)0.11753740, (float)0.12078657,
- (float)0.12403446, (float)0.12728101, (float)0.13052620, (float)0.13376999, (float)0.13701233,
- (float)0.14025325, (float)0.14349262, (float)0.14673047, (float)0.14996676, (float)0.15320145,
- (float)0.15643448, (float)0.15966582, (float)0.16289547, (float)0.16612339, (float)0.16934951,
- (float)0.17257382, (float)0.17579629, (float)0.17901687, (float)0.18223552, (float)0.18545224,
- (float)0.18866697, (float)0.19187967, (float)0.19509032, (float)0.19829889, (float)0.20150533,
- (float)0.20470962, (float)0.20791170, (float)0.21111156, (float)0.21430916, (float)0.21750447,
- (float)0.22069745, (float)0.22388805, (float)0.22707628, (float)0.23026206, (float)0.23344538,
- (float)0.23662618, (float)0.23980446, (float)0.24298020, (float)0.24615330, (float)0.24932377,
- (float)0.25249159, (float)0.25565669, (float)0.25881904, (float)0.26197866, (float)0.26513544,
- (float)0.26828939, (float)0.27144045, (float)0.27458861, (float)0.27773386, (float)0.28087610,
- (float)0.28401536, (float)0.28715158, (float)0.29028466, (float)0.29341471, (float)0.29654160,
- (float)0.29966527, (float)0.30278578, (float)0.30590302, (float)0.30901700, (float)0.31212768,
- (float)0.31523499, (float)0.31833893, (float)0.32143945, (float)0.32453656, (float)0.32763019,
- (float)0.33072028, (float)0.33380687, (float)0.33688986, (float)0.33996925, (float)0.34304500,
- (float)0.34611708, (float)0.34918544, (float)0.35225007, (float)0.35531089, (float)0.35836795,
- (float)0.36142117, (float)0.36447051, (float)0.36751595, (float)0.37055743, (float)0.37359497,
- (float)0.37662852, (float)0.37965801, (float)0.38268346, (float)0.38570479, (float)0.38872197,
- (float)0.39173502, (float)0.39474389, (float)0.39774847, (float)0.40074885, (float)0.40374491,
- (float)0.40673664, (float)0.40972406, (float)0.41270703, (float)0.41568562, (float)0.41865975,
- (float)0.42162940, (float)0.42459452, (float)0.42755508, (float)0.43051112, (float)0.43346250,
- (float)0.43640924, (float)0.43935132, (float)0.44228873, (float)0.44522133, (float)0.44814920,
- (float)0.45107228, (float)0.45399052, (float)0.45690390, (float)0.45981237, (float)0.46271592,
- (float)0.46561453, (float)0.46850815, (float)0.47139674, (float)0.47428030, (float)0.47715878,
- (float)0.48003215, (float)0.48290035, (float)0.48576337, (float)0.48862126, (float)0.49147385,
- (float)0.49432120, (float)0.49716330, (float)0.50000000, (float)0.50283140, (float)0.50565743,
- (float)0.50847799, (float)0.51129311, (float)0.51410276, (float)0.51690692, (float)0.51970553,
- (float)0.52249855, (float)0.52528602, (float)0.52806789, (float)0.53084403, (float)0.53361452,
- (float)0.53637928, (float)0.53913832, (float)0.54189163, (float)0.54463905, (float)0.54738063,
- (float)0.55011642, (float)0.55284631, (float)0.55557024, (float)0.55828828, (float)0.56100029,
- (float)0.56370628, (float)0.56640625, (float)0.56910014, (float)0.57178795, (float)0.57446963,
- (float)0.57714522, (float)0.57981455, (float)0.58247769, (float)0.58513463, (float)0.58778524,
- (float)0.59042960, (float)0.59306765, (float)0.59569931, (float)0.59832460, (float)0.60094351,
- (float)0.60355598, (float)0.60616195, (float)0.60876143, (float)0.61135441, (float)0.61394083,
- (float)0.61652070, (float)0.61909395, (float)0.62166059, (float)0.62422055, (float)0.62677383,
- (float)0.62932038, (float)0.63186020, (float)0.63439333, (float)0.63691956, (float)0.63943899,
- (float)0.64195162, (float)0.64445734, (float)0.64695615, (float)0.64944810, (float)0.65193301,
- (float)0.65441096, (float)0.65688187, (float)0.65934587, (float)0.66180271, (float)0.66425246,
- (float)0.66669512, (float)0.66913062, (float)0.67155898, (float)0.67398012, (float)0.67639405,
- (float)0.67880076, (float)0.68120021, (float)0.68359232, (float)0.68597710, (float)0.68835455,
- (float)0.69072467, (float)0.69308740, (float)0.69544262, (float)0.69779050, (float)0.70013082,
- (float)0.70246369, (float)0.70478904, (float)0.70710677, (float)0.70941699, (float)0.71171963,
- (float)0.71401459, (float)0.71630198, (float)0.71858168, (float)0.72085363, (float)0.72311789,
- (float)0.72537440, (float)0.72762316, (float)0.72986406, (float)0.73209721, (float)0.73432255,
- (float)0.73653996, (float)0.73874950, (float)0.74095118, (float)0.74314487, (float)0.74533057,
- (float)0.74750835, (float)0.74967808, (float)0.75183982, (float)0.75399351, (float)0.75613910,
- (float)0.75827658, (float)0.76040596, (float)0.76252723, (float)0.76464027, (float)0.76674515,
- (float)0.76884186, (float)0.77093029, (float)0.77301043, (float)0.77508241, (float)0.77714598,
- (float)0.77920127, (float)0.78124821, (float)0.78328675, (float)0.78531694, (float)0.78733873,
- (float)0.78935206, (float)0.79135692, (float)0.79335338, (float)0.79534125, (float)0.79732066,
- (float)0.79929149, (float)0.80125386, (float)0.80320752, (float)0.80515265, (float)0.80708915,
- (float)0.80901700, (float)0.81093621, (float)0.81284672, (float)0.81474853, (float)0.81664157,
- (float)0.81852591, (float)0.82040149, (float)0.82226825, (float)0.82412618, (float)0.82597536,
- (float)0.82781565, (float)0.82964706, (float)0.83146966, (float)0.83328325, (float)0.83508795,
- (float)0.83688378, (float)0.83867061, (float)0.84044838, (float)0.84221727, (float)0.84397703,
- (float)0.84572780, (float)0.84746957, (float)0.84920216, (float)0.85092574, (float)0.85264021,
- (float)0.85434544, (float)0.85604161, (float)0.85772866, (float)0.85940641, (float)0.86107504,
- (float)0.86273444, (float)0.86438453, (float)0.86602545, (float)0.86765707, (float)0.86927933,
- (float)0.87089235, (float)0.87249607, (float)0.87409031, (float)0.87567532, (float)0.87725097,
- (float)0.87881714, (float)0.88037390, (float)0.88192129, (float)0.88345921, (float)0.88498765,
- (float)0.88650668, (float)0.88801610, (float)0.88951612, (float)0.89100653, (float)0.89248741,
- (float)0.89395881, (float)0.89542055, (float)0.89687276, (float)0.89831537, (float)0.89974827,
- (float)0.90117162, (float)0.90258533, (float)0.90398932, (float)0.90538365, (float)0.90676826,
- (float)0.90814316, (float)0.90950841, (float)0.91086388, (float)0.91220951, (float)0.91354549,
- (float)0.91487163, (float)0.91618794, (float)0.91749454, (float)0.91879123, (float)0.92007810,
- (float)0.92135513, (float)0.92262226, (float)0.92387950, (float)0.92512691, (float)0.92636442,
- (float)0.92759192, (float)0.92880958, (float)0.93001723, (float)0.93121493, (float)0.93240267,
- (float)0.93358046, (float)0.93474817, (float)0.93590593, (float)0.93705362, (float)0.93819135,
- (float)0.93931901, (float)0.94043654, (float)0.94154406, (float)0.94264150, (float)0.94372880,
- (float)0.94480604, (float)0.94587320, (float)0.94693011, (float)0.94797695, (float)0.94901365,
- (float)0.95004016, (float)0.95105654, (float)0.95206273, (float)0.95305866, (float)0.95404440,
- (float)0.95501995, (float)0.95598525, (float)0.95694035, (float)0.95788521, (float)0.95881975,
- (float)0.95974404, (float)0.96065807, (float)0.96156180, (float)0.96245527, (float)0.96333838,
- (float)0.96421117, (float)0.96507370, (float)0.96592581, (float)0.96676767, (float)0.96759909,
- (float)0.96842021, (float)0.96923089, (float)0.97003126, (float)0.97082120, (float)0.97160077,
- (float)0.97236991, (float)0.97312868, (float)0.97387701, (float)0.97461486, (float)0.97534233,
- (float)0.97605932, (float)0.97676587, (float)0.97746199, (float)0.97814763, (float)0.97882277,
- (float)0.97948742, (float)0.98014158, (float)0.98078531, (float)0.98141843, (float)0.98204112,
- (float)0.98265332, (float)0.98325491, (float)0.98384601, (float)0.98442656, (float)0.98499662,
- (float)0.98555607, (float)0.98610497, (float)0.98664331, (float)0.98717111, (float)0.98768836,
- (float)0.98819500, (float)0.98869103, (float)0.98917651, (float)0.98965138, (float)0.99011570,
- (float)0.99056935, (float)0.99101239, (float)0.99144489, (float)0.99186671, (float)0.99227792,
- (float)0.99267852, (float)0.99306846, (float)0.99344778, (float)0.99381649, (float)0.99417448,
- (float)0.99452192, (float)0.99485862, (float)0.99518472, (float)0.99550015, (float)0.99580491,
- (float)0.99609905, (float)0.99638247, (float)0.99665523, (float)0.99691731, (float)0.99716878,
- (float)0.99740952, (float)0.99763954, (float)0.99785894, (float)0.99806762, (float)0.99826562,
- (float)0.99845290, (float)0.99862951, (float)0.99879545, (float)0.99895066, (float)0.99909520,
- (float)0.99922901, (float)0.99935216, (float)0.99946457, (float)0.99956632, (float)0.99965733,
- (float)0.99973762, (float)0.99980724, (float)0.99986613, (float)0.99991435, (float)0.99995178,
- (float)0.99997860, (float)0.99999464, (float)1.00000000, (float)0.99999464, (float)0.99997860,
- (float)0.99995178, (float)0.99991435, (float)0.99986613, (float)0.99980724, (float)0.99973762,
- (float)0.99965733, (float)0.99956632, (float)0.99946457, (float)0.99935216, (float)0.99922901,
- (float)0.99909520, (float)0.99895066, (float)0.99879545, (float)0.99862951, (float)0.99845290,
- (float)0.99826562, (float)0.99806762, (float)0.99785894, (float)0.99763954, (float)0.99740946,
- (float)0.99716872, (float)0.99691731, (float)0.99665523, (float)0.99638247, (float)0.99609905,
- (float)0.99580491, (float)0.99550015, (float)0.99518472, (float)0.99485862, (float)0.99452192,
- (float)0.99417448, (float)0.99381644, (float)0.99344778, (float)0.99306846, (float)0.99267852,
- (float)0.99227792, (float)0.99186671, (float)0.99144489, (float)0.99101239, (float)0.99056935,
- (float)0.99011564, (float)0.98965138, (float)0.98917651, (float)0.98869103, (float)0.98819494,
- (float)0.98768836, (float)0.98717111, (float)0.98664331, (float)0.98610497, (float)0.98555607,
- (float)0.98499656, (float)0.98442656, (float)0.98384601, (float)0.98325491, (float)0.98265326,
- (float)0.98204112, (float)0.98141843, (float)0.98078525, (float)0.98014158, (float)0.97948742,
- (float)0.97882277, (float)0.97814757, (float)0.97746193, (float)0.97676587, (float)0.97605932,
- (float)0.97534227, (float)0.97461486, (float)0.97387695, (float)0.97312862, (float)0.97236991,
- (float)0.97160077, (float)0.97082120, (float)0.97003126, (float)0.96923089, (float)0.96842015,
- (float)0.96759909, (float)0.96676761, (float)0.96592581, (float)0.96507365, (float)0.96421117,
- (float)0.96333838, (float)0.96245521, (float)0.96156180, (float)0.96065807, (float)0.95974404,
- (float)0.95881969, (float)0.95788515, (float)0.95694029, (float)0.95598525, (float)0.95501995,
- (float)0.95404440, (float)0.95305860, (float)0.95206267, (float)0.95105648, (float)0.95004016,
- (float)0.94901365, (float)0.94797695, (float)0.94693011, (float)0.94587314, (float)0.94480604,
- (float)0.94372880, (float)0.94264150, (float)0.94154406, (float)0.94043654, (float)0.93931895,
- (float)0.93819129, (float)0.93705362, (float)0.93590593, (float)0.93474817, (float)0.93358046,
- (float)0.93240267, (float)0.93121493, (float)0.93001723, (float)0.92880952, (float)0.92759192,
- (float)0.92636436, (float)0.92512691, (float)0.92387950, (float)0.92262226, (float)0.92135507,
- (float)0.92007804, (float)0.91879123, (float)0.91749448, (float)0.91618794, (float)0.91487157,
- (float)0.91354543, (float)0.91220951, (float)0.91086382, (float)0.90950835, (float)0.90814310,
- (float)0.90676820, (float)0.90538365, (float)0.90398932, (float)0.90258527, (float)0.90117157,
- (float)0.89974827, (float)0.89831525, (float)0.89687276, (float)0.89542055, (float)0.89395875,
- (float)0.89248741, (float)0.89100647, (float)0.88951600, (float)0.88801610, (float)0.88650662,
- (float)0.88498759, (float)0.88345915, (float)0.88192123, (float)0.88037384, (float)0.87881714,
- (float)0.87725091, (float)0.87567532, (float)0.87409031, (float)0.87249595, (float)0.87089223,
- (float)0.86927933, (float)0.86765701, (float)0.86602539, (float)0.86438447, (float)0.86273432,
- (float)0.86107504, (float)0.85940641, (float)0.85772860, (float)0.85604161, (float)0.85434544,
- (float)0.85264009, (float)0.85092574, (float)0.84920216, (float)0.84746951, (float)0.84572780,
- (float)0.84397697, (float)0.84221715, (float)0.84044844, (float)0.83867055, (float)0.83688372,
- (float)0.83508795, (float)0.83328319, (float)0.83146954, (float)0.82964706, (float)0.82781565,
- (float)0.82597530, (float)0.82412612, (float)0.82226813, (float)0.82040137, (float)0.81852591,
- (float)0.81664157, (float)0.81474847, (float)0.81284660, (float)0.81093609, (float)0.80901700,
- (float)0.80708915, (float)0.80515265, (float)0.80320752, (float)0.80125374, (float)0.79929143,
- (float)0.79732066, (float)0.79534125, (float)0.79335332, (float)0.79135686, (float)0.78935200,
- (float)0.78733861, (float)0.78531694, (float)0.78328675, (float)0.78124815, (float)0.77920121,
- (float)0.77714586, (float)0.77508223, (float)0.77301049, (float)0.77093029, (float)0.76884180,
- (float)0.76674509, (float)0.76464021, (float)0.76252711, (float)0.76040596, (float)0.75827658,
- (float)0.75613904, (float)0.75399339, (float)0.75183970, (float)0.74967796, (float)0.74750835,
- (float)0.74533057, (float)0.74314481, (float)0.74095106, (float)0.73874938, (float)0.73653996,
- (float)0.73432249, (float)0.73209721, (float)0.72986400, (float)0.72762305, (float)0.72537428,
- (float)0.72311789, (float)0.72085363, (float)0.71858162, (float)0.71630186, (float)0.71401453,
- (float)0.71171951, (float)0.70941705, (float)0.70710677, (float)0.70478898, (float)0.70246363,
- (float)0.70013070, (float)0.69779032, (float)0.69544268, (float)0.69308734, (float)0.69072461,
- (float)0.68835449, (float)0.68597704, (float)0.68359220, (float)0.68120021, (float)0.67880070,
- (float)0.67639399, (float)0.67398006, (float)0.67155886, (float)0.66913044, (float)0.66669512,
- (float)0.66425240, (float)0.66180259, (float)0.65934575, (float)0.65688181, (float)0.65441096,
- (float)0.65193301, (float)0.64944804, (float)0.64695609, (float)0.64445722, (float)0.64195150,
- (float)0.63943905, (float)0.63691956, (float)0.63439327, (float)0.63186014, (float)0.62932026,
- (float)0.62677372, (float)0.62422055, (float)0.62166059, (float)0.61909389, (float)0.61652064,
- (float)0.61394072, (float)0.61135429, (float)0.60876143, (float)0.60616189, (float)0.60355592,
- (float)0.60094339, (float)0.59832448, (float)0.59569913, (float)0.59306765, (float)0.59042960,
- (float)0.58778518, (float)0.58513451, (float)0.58247757, (float)0.57981461, (float)0.57714522,
- (float)0.57446963, (float)0.57178789, (float)0.56910002, (float)0.56640613, (float)0.56370628,
- (float)0.56100023, (float)0.55828822, (float)0.55557019, (float)0.55284619, (float)0.55011630,
- (float)0.54738069, (float)0.54463905, (float)0.54189152, (float)0.53913826, (float)0.53637916,
- (float)0.53361434, (float)0.53084403, (float)0.52806783, (float)0.52528596, (float)0.52249849,
- (float)0.51970541, (float)0.51690674, (float)0.51410276, (float)0.51129305, (float)0.50847787,
- (float)0.50565726, (float)0.50283122, (float)0.50000006, (float)0.49716327, (float)0.49432117,
- (float)0.49147379, (float)0.48862115, (float)0.48576325, (float)0.48290038, (float)0.48003212,
- (float)0.47715873, (float)0.47428021, (float)0.47139663, (float)0.46850798, (float)0.46561456,
- (float)0.46271589, (float)0.45981231, (float)0.45690379, (float)0.45399037, (float)0.45107210,
- (float)0.44814920, (float)0.44522130, (float)0.44228864, (float)0.43935123, (float)0.43640912,
- (float)0.43346232, (float)0.43051112, (float)0.42755505, (float)0.42459446, (float)0.42162928,
- (float)0.41865960, (float)0.41568545, (float)0.41270703, (float)0.40972400, (float)0.40673658,
- (float)0.40374479, (float)0.40074870, (float)0.39774850, (float)0.39474386, (float)0.39173496,
- (float)0.38872188, (float)0.38570464, (float)0.38268328, (float)0.37965804, (float)0.37662849,
- (float)0.37359491, (float)0.37055734, (float)0.36751580, (float)0.36447033, (float)0.36142117,
- (float)0.35836792, (float)0.35531086, (float)0.35224995, (float)0.34918529, (float)0.34611690,
- (float)0.34304500, (float)0.33996922, (float)0.33688980, (float)0.33380675, (float)0.33072016,
- (float)0.32763001, (float)0.32453656, (float)0.32143945, (float)0.31833887, (float)0.31523487,
- (float)0.31212750, (float)0.30901679, (float)0.30590302, (float)0.30278572, (float)0.29966521,
- (float)0.29654145, (float)0.29341453, (float)0.29028472, (float)0.28715155, (float)0.28401530,
- (float)0.28087601, (float)0.27773371, (float)0.27458847, (float)0.27144048, (float)0.26828936,
- (float)0.26513538, (float)0.26197854, (float)0.25881892, (float)0.25565651, (float)0.25249159,
- (float)0.24932374, (float)0.24615324, (float)0.24298008, (float)0.23980433, (float)0.23662600,
- (float)0.23344538, (float)0.23026201, (float)0.22707619, (float)0.22388794, (float)0.22069728,
- (float)0.21750426, (float)0.21430916, (float)0.21111152, (float)0.20791161, (float)0.20470949,
- (float)0.20150517, (float)0.19829892, (float)0.19509031, (float)0.19187963, (float)0.18866688,
- (float)0.18545210, (float)0.18223536, (float)0.17901689, (float)0.17579627, (float)0.17257376,
- (float)0.16934940, (float)0.16612324, (float)0.16289529, (float)0.15966584, (float)0.15643445,
- (float)0.15320137, (float)0.14996666, (float)0.14673033, (float)0.14349243, (float)0.14025325,
- (float)0.13701232, (float)0.13376991, (float)0.13052608, (float)0.12728085, (float)0.12403426,
- (float)0.12078657, (float)0.11753736, (float)0.11428688, (float)0.11103519, (float)0.10778230,
- (float)0.10452849, (float)0.10127334, (float)0.09801710, (float)0.09475980, (float)0.09150149,
- (float)0.08824220, (float)0.08498220, (float)0.08172106, (float)0.07845904, (float)0.07519618,
- (float)0.07193252, (float)0.06866808, (float)0.06540315, (float)0.06213728, (float)0.05887074,
- (float)0.05560357, (float)0.05233581, (float)0.04906749, (float)0.04579888, (float)0.04252954,
- (float)0.03925974, (float)0.03598953, (float)0.03271893, (float)0.02944798, (float)0.02617695,
- (float)0.02290541, (float)0.01963361, (float)0.01636161, (float)0.01308943, (float)0.00981712,
- (float)0.00654493, (float)0.00327244, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
- (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000
-};
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_
diff --git a/webrtc/modules/audio_processing/optionally_built_submodule_creators.cc b/webrtc/modules/audio_processing/optionally_built_submodule_creators.cc
new file mode 100644
index 0000000..62a1632
--- /dev/null
+++ b/webrtc/modules/audio_processing/optionally_built_submodule_creators.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/optionally_built_submodule_creators.h"
+
+#include <memory>
+
+#include "modules/audio_processing/transient/transient_suppressor_impl.h"
+
+namespace webrtc {
+
+std::unique_ptr<TransientSuppressor> CreateTransientSuppressor(
+ const ApmSubmoduleCreationOverrides& overrides) {
+#ifdef WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR
+ return nullptr;
+#else
+ if (overrides.transient_suppression) {
+ return nullptr;
+ }
+ return std::make_unique<TransientSuppressorImpl>();
+#endif
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/optionally_built_submodule_creators.h b/webrtc/modules/audio_processing/optionally_built_submodule_creators.h
new file mode 100644
index 0000000..c96e66f
--- /dev/null
+++ b/webrtc/modules/audio_processing/optionally_built_submodule_creators.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_OPTIONALLY_BUILT_SUBMODULE_CREATORS_H_
+#define MODULES_AUDIO_PROCESSING_OPTIONALLY_BUILT_SUBMODULE_CREATORS_H_
+
+#include <memory>
+
+#include "modules/audio_processing/transient/transient_suppressor.h"
+
+namespace webrtc {
+
+// These overrides are only to be used for testing purposes.
+// Each flag emulates a preprocessor macro to exclude a submodule of APM from
+// the build, e.g. WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR. If the corresponding
+// flag |transient_suppression| is enabled, then the creators will return
+// nullptr instead of a submodule instance, as if the macro had been defined.
+struct ApmSubmoduleCreationOverrides {
+ bool transient_suppression = false;
+};
+
+// Creates a transient suppressor.
+// Will instead return nullptr if one of the following is true:
+// * WEBRTC_EXCLUDE_TRANSIENT_SUPPRESSOR is defined
+// * The corresponding override in |overrides| is enabled.
+std::unique_ptr<TransientSuppressor> CreateTransientSuppressor(
+ const ApmSubmoduleCreationOverrides& overrides);
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_OPTIONALLY_BUILT_SUBMODULE_CREATORS_H_
diff --git a/webrtc/modules/audio_processing/processing_component.cc b/webrtc/modules/audio_processing/processing_component.cc
deleted file mode 100644
index 9e16d7c..0000000
--- a/webrtc/modules/audio_processing/processing_component.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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 "webrtc/modules/audio_processing/processing_component.h"
-
-#include <assert.h>
-
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-
-namespace webrtc {
-
-ProcessingComponent::ProcessingComponent()
- : initialized_(false),
- enabled_(false),
- num_handles_(0) {}
-
-ProcessingComponent::~ProcessingComponent() {
- assert(initialized_ == false);
-}
-
-int ProcessingComponent::Destroy() {
- while (!handles_.empty()) {
- DestroyHandle(handles_.back());
- handles_.pop_back();
- }
- initialized_ = false;
-
- return AudioProcessing::kNoError;
-}
-
-int ProcessingComponent::EnableComponent(bool enable) {
- if (enable && !enabled_) {
- enabled_ = enable; // Must be set before Initialize() is called.
-
- int err = Initialize();
- if (err != AudioProcessing::kNoError) {
- enabled_ = false;
- return err;
- }
- } else {
- enabled_ = enable;
- }
-
- return AudioProcessing::kNoError;
-}
-
-bool ProcessingComponent::is_component_enabled() const {
- return enabled_;
-}
-
-void* ProcessingComponent::handle(int index) const {
- assert(index < num_handles_);
- return handles_[index];
-}
-
-int ProcessingComponent::num_handles() const {
- return num_handles_;
-}
-
-int ProcessingComponent::Initialize() {
- if (!enabled_) {
- return AudioProcessing::kNoError;
- }
-
- num_handles_ = num_handles_required();
- if (num_handles_ > static_cast<int>(handles_.size())) {
- handles_.resize(num_handles_, NULL);
- }
-
- assert(static_cast<int>(handles_.size()) >= num_handles_);
- for (int i = 0; i < num_handles_; i++) {
- if (handles_[i] == NULL) {
- handles_[i] = CreateHandle();
- if (handles_[i] == NULL) {
- return AudioProcessing::kCreationFailedError;
- }
- }
-
- int err = InitializeHandle(handles_[i]);
- if (err != AudioProcessing::kNoError) {
- return GetHandleError(handles_[i]);
- }
- }
-
- initialized_ = true;
- return Configure();
-}
-
-int ProcessingComponent::Configure() {
- if (!initialized_) {
- return AudioProcessing::kNoError;
- }
-
- assert(static_cast<int>(handles_.size()) >= num_handles_);
- for (int i = 0; i < num_handles_; i++) {
- int err = ConfigureHandle(handles_[i]);
- if (err != AudioProcessing::kNoError) {
- return GetHandleError(handles_[i]);
- }
- }
-
- return AudioProcessing::kNoError;
-}
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/processing_component.h b/webrtc/modules/audio_processing/processing_component.h
deleted file mode 100644
index 8ee3ac6..0000000
--- a/webrtc/modules/audio_processing/processing_component.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_PROCESSING_COMPONENT_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_PROCESSING_COMPONENT_H_
-
-#include <vector>
-
-#include "webrtc/common.h"
-
-namespace webrtc {
-
-class ProcessingComponent {
- public:
- ProcessingComponent();
- virtual ~ProcessingComponent();
-
- virtual int Initialize();
- virtual void SetExtraOptions(const Config& config) {}
- virtual int Destroy();
-
- bool is_component_enabled() const;
-
- protected:
- virtual int Configure();
- int EnableComponent(bool enable);
- void* handle(int index) const;
- int num_handles() const;
-
- private:
- virtual void* CreateHandle() const = 0;
- virtual int InitializeHandle(void* handle) const = 0;
- virtual int ConfigureHandle(void* handle) const = 0;
- virtual void DestroyHandle(void* handle) const = 0;
- virtual int num_handles_required() const = 0;
- virtual int GetHandleError(void* handle) const = 0;
-
- std::vector<void*> handles_;
- bool initialized_;
- bool enabled_;
- int num_handles_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_PROCESSING_COMPONENT_H__
diff --git a/webrtc/modules/audio_processing/render_queue_item_verifier.h b/webrtc/modules/audio_processing/render_queue_item_verifier.h
new file mode 100644
index 0000000..b8aff4a
--- /dev/null
+++ b/webrtc/modules/audio_processing/render_queue_item_verifier.h
@@ -0,0 +1,36 @@
+/*
+ * 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_AUDIO_PROCESSING_RENDER_QUEUE_ITEM_VERIFIER_H_
+#define MODULES_AUDIO_PROCESSING_RENDER_QUEUE_ITEM_VERIFIER_H_
+
+#include <vector>
+
+namespace webrtc {
+
+// Functor to use when supplying a verifier function for the queue item
+// verifcation.
+template <typename T>
+class RenderQueueItemVerifier {
+ public:
+ explicit RenderQueueItemVerifier(size_t minimum_capacity)
+ : minimum_capacity_(minimum_capacity) {}
+
+ bool operator()(const std::vector<T>& v) const {
+ return v.capacity() >= minimum_capacity_;
+ }
+
+ private:
+ size_t minimum_capacity_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_RENDER_QUEUE_ITEM_VERIFIER_H__
diff --git a/webrtc/modules/audio_processing/residual_echo_detector.cc b/webrtc/modules/audio_processing/residual_echo_detector.cc
new file mode 100644
index 0000000..6188883
--- /dev/null
+++ b/webrtc/modules/audio_processing/residual_echo_detector.cc
@@ -0,0 +1,215 @@
+/*
+ * 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/audio_processing/residual_echo_detector.h"
+
+#include <algorithm>
+#include <numeric>
+
+#include "absl/types/optional.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/logging/apm_data_dumper.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace {
+
+float Power(rtc::ArrayView<const float> input) {
+ if (input.empty()) {
+ return 0.f;
+ }
+ return std::inner_product(input.begin(), input.end(), input.begin(), 0.f) /
+ input.size();
+}
+
+constexpr size_t kLookbackFrames = 650;
+// TODO(ivoc): Verify the size of this buffer.
+constexpr size_t kRenderBufferSize = 30;
+constexpr float kAlpha = 0.001f;
+// 10 seconds of data, updated every 10 ms.
+constexpr size_t kAggregationBufferSize = 10 * 100;
+
+} // namespace
+
+namespace webrtc {
+
+int ResidualEchoDetector::instance_count_ = 0;
+
+ResidualEchoDetector::ResidualEchoDetector()
+ : data_dumper_(
+ new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ render_buffer_(kRenderBufferSize),
+ render_power_(kLookbackFrames),
+ render_power_mean_(kLookbackFrames),
+ render_power_std_dev_(kLookbackFrames),
+ covariances_(kLookbackFrames),
+ recent_likelihood_max_(kAggregationBufferSize) {}
+
+ResidualEchoDetector::~ResidualEchoDetector() = default;
+
+void ResidualEchoDetector::AnalyzeRenderAudio(
+ rtc::ArrayView<const float> render_audio) {
+ // Dump debug data assuming 48 kHz sample rate (if this assumption is not
+ // valid the dumped audio will need to be converted offline accordingly).
+ data_dumper_->DumpWav("ed_render", render_audio.size(), render_audio.data(),
+ 48000, 1);
+
+ if (render_buffer_.Size() == 0) {
+ frames_since_zero_buffer_size_ = 0;
+ } else if (frames_since_zero_buffer_size_ >= kRenderBufferSize) {
+ // This can happen in a few cases: at the start of a call, due to a glitch
+ // or due to clock drift. The excess capture value will be ignored.
+ // TODO(ivoc): Include how often this happens in APM stats.
+ render_buffer_.Pop();
+ frames_since_zero_buffer_size_ = 0;
+ }
+ ++frames_since_zero_buffer_size_;
+ float power = Power(render_audio);
+ render_buffer_.Push(power);
+}
+
+void ResidualEchoDetector::AnalyzeCaptureAudio(
+ rtc::ArrayView<const float> capture_audio) {
+ // Dump debug data assuming 48 kHz sample rate (if this assumption is not
+ // valid the dumped audio will need to be converted offline accordingly).
+ data_dumper_->DumpWav("ed_capture", capture_audio.size(),
+ capture_audio.data(), 48000, 1);
+
+ if (first_process_call_) {
+ // On the first process call (so the start of a call), we must flush the
+ // render buffer, otherwise the render data will be delayed.
+ render_buffer_.Clear();
+ first_process_call_ = false;
+ }
+
+ // Get the next render value.
+ const absl::optional<float> buffered_render_power = render_buffer_.Pop();
+ if (!buffered_render_power) {
+ // This can happen in a few cases: at the start of a call, due to a glitch
+ // or due to clock drift. The excess capture value will be ignored.
+ // TODO(ivoc): Include how often this happens in APM stats.
+ return;
+ }
+ // Update the render statistics, and store the statistics in circular buffers.
+ render_statistics_.Update(*buffered_render_power);
+ RTC_DCHECK_LT(next_insertion_index_, kLookbackFrames);
+ render_power_[next_insertion_index_] = *buffered_render_power;
+ render_power_mean_[next_insertion_index_] = render_statistics_.mean();
+ render_power_std_dev_[next_insertion_index_] =
+ render_statistics_.std_deviation();
+
+ // Get the next capture value, update capture statistics and add the relevant
+ // values to the buffers.
+ const float capture_power = Power(capture_audio);
+ capture_statistics_.Update(capture_power);
+ const float capture_mean = capture_statistics_.mean();
+ const float capture_std_deviation = capture_statistics_.std_deviation();
+
+ // Update the covariance values and determine the new echo likelihood.
+ echo_likelihood_ = 0.f;
+ size_t read_index = next_insertion_index_;
+
+ int best_delay = -1;
+ for (size_t delay = 0; delay < covariances_.size(); ++delay) {
+ RTC_DCHECK_LT(read_index, render_power_.size());
+ covariances_[delay].Update(capture_power, capture_mean,
+ capture_std_deviation, render_power_[read_index],
+ render_power_mean_[read_index],
+ render_power_std_dev_[read_index]);
+ read_index = read_index > 0 ? read_index - 1 : kLookbackFrames - 1;
+
+ if (covariances_[delay].normalized_cross_correlation() > echo_likelihood_) {
+ echo_likelihood_ = covariances_[delay].normalized_cross_correlation();
+ best_delay = static_cast<int>(delay);
+ }
+ }
+ // This is a temporary log message to help find the underlying cause for echo
+ // likelihoods > 1.0.
+ // TODO(ivoc): Remove once the issue is resolved.
+ if (echo_likelihood_ > 1.1f) {
+ // Make sure we don't spam the log.
+ if (log_counter_ < 5 && best_delay != -1) {
+ size_t read_index = kLookbackFrames + next_insertion_index_ - best_delay;
+ if (read_index >= kLookbackFrames) {
+ read_index -= kLookbackFrames;
+ }
+ RTC_DCHECK_LT(read_index, render_power_.size());
+ RTC_LOG_F(LS_ERROR) << "Echo detector internal state: {"
+ "Echo likelihood: "
+ << echo_likelihood_ << ", Best Delay: " << best_delay
+ << ", Covariance: "
+ << covariances_[best_delay].covariance()
+ << ", Last capture power: " << capture_power
+ << ", Capture mean: " << capture_mean
+ << ", Capture_standard deviation: "
+ << capture_std_deviation << ", Last render power: "
+ << render_power_[read_index]
+ << ", Render mean: " << render_power_mean_[read_index]
+ << ", Render standard deviation: "
+ << render_power_std_dev_[read_index]
+ << ", Reliability: " << reliability_ << "}";
+ log_counter_++;
+ }
+ }
+ RTC_DCHECK_LT(echo_likelihood_, 1.1f);
+
+ reliability_ = (1.0f - kAlpha) * reliability_ + kAlpha * 1.0f;
+ echo_likelihood_ *= reliability_;
+ // This is a temporary fix to prevent echo likelihood values > 1.0.
+ // TODO(ivoc): Find the root cause of this issue and fix it.
+ echo_likelihood_ = std::min(echo_likelihood_, 1.0f);
+ int echo_percentage = static_cast<int>(echo_likelihood_ * 100);
+ RTC_HISTOGRAM_COUNTS("WebRTC.Audio.ResidualEchoDetector.EchoLikelihood",
+ echo_percentage, 0, 100, 100 /* number of bins */);
+
+ // Update the buffer of recent likelihood values.
+ recent_likelihood_max_.Update(echo_likelihood_);
+
+ // Update the next insertion index.
+ next_insertion_index_ = next_insertion_index_ < (kLookbackFrames - 1)
+ ? next_insertion_index_ + 1
+ : 0;
+}
+
+void ResidualEchoDetector::Initialize(int /*capture_sample_rate_hz*/,
+ int /*num_capture_channels*/,
+ int /*render_sample_rate_hz*/,
+ int /*num_render_channels*/) {
+ render_buffer_.Clear();
+ std::fill(render_power_.begin(), render_power_.end(), 0.f);
+ std::fill(render_power_mean_.begin(), render_power_mean_.end(), 0.f);
+ std::fill(render_power_std_dev_.begin(), render_power_std_dev_.end(), 0.f);
+ render_statistics_.Clear();
+ capture_statistics_.Clear();
+ recent_likelihood_max_.Clear();
+ for (auto& cov : covariances_) {
+ cov.Clear();
+ }
+ echo_likelihood_ = 0.f;
+ next_insertion_index_ = 0;
+ reliability_ = 0.f;
+}
+
+void EchoDetector::PackRenderAudioBuffer(AudioBuffer* audio,
+ std::vector<float>* packed_buffer) {
+ packed_buffer->clear();
+ packed_buffer->insert(packed_buffer->end(), audio->channels()[0],
+ audio->channels()[0] + audio->num_frames());
+}
+
+EchoDetector::Metrics ResidualEchoDetector::GetMetrics() const {
+ EchoDetector::Metrics metrics;
+ metrics.echo_likelihood = echo_likelihood_;
+ metrics.echo_likelihood_recent_max = recent_likelihood_max_.max();
+ return metrics;
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/residual_echo_detector.h b/webrtc/modules/audio_processing/residual_echo_detector.h
new file mode 100644
index 0000000..5d18ecb
--- /dev/null
+++ b/webrtc/modules/audio_processing/residual_echo_detector.h
@@ -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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_RESIDUAL_ECHO_DETECTOR_H_
+#define MODULES_AUDIO_PROCESSING_RESIDUAL_ECHO_DETECTOR_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/echo_detector/circular_buffer.h"
+#include "modules/audio_processing/echo_detector/mean_variance_estimator.h"
+#include "modules/audio_processing/echo_detector/moving_max.h"
+#include "modules/audio_processing/echo_detector/normalized_covariance_estimator.h"
+#include "modules/audio_processing/include/audio_processing.h"
+
+namespace webrtc {
+
+class ApmDataDumper;
+class AudioBuffer;
+
+class ResidualEchoDetector : public EchoDetector {
+ public:
+ ResidualEchoDetector();
+ ~ResidualEchoDetector() override;
+
+ // This function should be called while holding the render lock.
+ void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) override;
+
+ // This function should be called while holding the capture lock.
+ void AnalyzeCaptureAudio(rtc::ArrayView<const float> capture_audio) override;
+
+ // This function should be called while holding the capture lock.
+ void Initialize(int capture_sample_rate_hz,
+ int num_capture_channels,
+ int render_sample_rate_hz,
+ int num_render_channels) override;
+
+ // This function is for testing purposes only.
+ void SetReliabilityForTest(float value) { reliability_ = value; }
+
+ // This function should be called while holding the capture lock.
+ EchoDetector::Metrics GetMetrics() const override;
+
+ private:
+ static int instance_count_;
+ std::unique_ptr<ApmDataDumper> data_dumper_;
+ // Keep track if the |Process| function has been previously called.
+ bool first_process_call_ = true;
+ // Buffer for storing the power of incoming farend buffers. This is needed for
+ // cases where calls to BufferFarend and Process are jittery.
+ CircularBuffer render_buffer_;
+ // Count how long ago it was that the size of |render_buffer_| was zero. This
+ // value is also reset to zero when clock drift is detected and a value from
+ // the renderbuffer is discarded, even though the buffer is not actually zero
+ // at that point. This is done to avoid repeatedly removing elements in this
+ // situation.
+ size_t frames_since_zero_buffer_size_ = 0;
+
+ // Circular buffers containing delayed versions of the power, mean and
+ // standard deviation, for calculating the delayed covariance values.
+ std::vector<float> render_power_;
+ std::vector<float> render_power_mean_;
+ std::vector<float> render_power_std_dev_;
+ // Covariance estimates for different delay values.
+ std::vector<NormalizedCovarianceEstimator> covariances_;
+ // Index where next element should be inserted in all of the above circular
+ // buffers.
+ size_t next_insertion_index_ = 0;
+
+ MeanVarianceEstimator render_statistics_;
+ MeanVarianceEstimator capture_statistics_;
+ // Current echo likelihood.
+ float echo_likelihood_ = 0.f;
+ // Reliability of the current likelihood.
+ float reliability_ = 0.f;
+ MovingMax recent_likelihood_max_;
+
+ int log_counter_ = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_RESIDUAL_ECHO_DETECTOR_H_
diff --git a/webrtc/modules/audio_processing/rms_level.cc b/webrtc/modules/audio_processing/rms_level.cc
index 70c4422..6992a15 100644
--- a/webrtc/modules/audio_processing/rms_level.cc
+++ b/webrtc/modules/audio_processing/rms_level.cc
@@ -8,54 +8,121 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/rms_level.h"
+#include "modules/audio_processing/rms_level.h"
-#include <assert.h>
-#include <math.h>
+#include <algorithm>
+#include <cmath>
+#include <numeric>
+
+#include "rtc_base/checks.h"
namespace webrtc {
+namespace {
+static constexpr float kMaxSquaredLevel = 32768 * 32768;
+// kMinLevel is the level corresponding to kMinLevelDb, that is 10^(-127/10).
+static constexpr float kMinLevel = 1.995262314968883e-13f;
-static const float kMaxSquaredLevel = 32768 * 32768;
+// Calculates the normalized RMS value from a mean square value. The input
+// should be the sum of squared samples divided by the number of samples. The
+// value will be normalized to full range before computing the RMS, wich is
+// returned as a negated dBfs. That is, 0 is full amplitude while 127 is very
+// faint.
+int ComputeRms(float mean_square) {
+ if (mean_square <= kMinLevel * kMaxSquaredLevel) {
+ // Very faint; simply return the minimum value.
+ return RmsLevel::kMinLevelDb;
+ }
+ // Normalize by the max level.
+ const float mean_square_norm = mean_square / kMaxSquaredLevel;
+ RTC_DCHECK_GT(mean_square_norm, kMinLevel);
+ // 20log_10(x^0.5) = 10log_10(x)
+ const float rms = 10.f * std::log10(mean_square_norm);
+ RTC_DCHECK_LE(rms, 0.f);
+ RTC_DCHECK_GT(rms, -RmsLevel::kMinLevelDb);
+ // Return the negated value.
+ return static_cast<int>(-rms + 0.5f);
+}
+} // namespace
-RMSLevel::RMSLevel()
- : sum_square_(0),
- sample_count_(0) {}
+RmsLevel::RmsLevel() {
+ Reset();
+}
-RMSLevel::~RMSLevel() {}
+RmsLevel::~RmsLevel() = default;
-void RMSLevel::Reset() {
- sum_square_ = 0;
+void RmsLevel::Reset() {
+ sum_square_ = 0.f;
sample_count_ = 0;
+ max_sum_square_ = 0.f;
+ block_size_ = absl::nullopt;
}
-void RMSLevel::Process(const int16_t* data, size_t length) {
- for (size_t i = 0; i < length; ++i) {
- sum_square_ += data[i] * data[i];
+void RmsLevel::Analyze(rtc::ArrayView<const int16_t> data) {
+ if (data.empty()) {
+ return;
}
- sample_count_ += length;
-}
-void RMSLevel::ProcessMuted(size_t length) {
- sample_count_ += length;
+ CheckBlockSize(data.size());
+
+ const float sum_square =
+ std::accumulate(data.begin(), data.end(), 0.f,
+ [](float a, int16_t b) { return a + b * b; });
+ RTC_DCHECK_GE(sum_square, 0.f);
+ sum_square_ += sum_square;
+ sample_count_ += data.size();
+
+ max_sum_square_ = std::max(max_sum_square_, sum_square);
}
-int RMSLevel::RMS() {
- if (sample_count_ == 0 || sum_square_ == 0) {
- Reset();
- return kMinLevel;
+void RmsLevel::Analyze(rtc::ArrayView<const float> data) {
+ if (data.empty()) {
+ return;
}
- // Normalize by the max level.
- float rms = sum_square_ / (sample_count_ * kMaxSquaredLevel);
- // 20log_10(x^0.5) = 10log_10(x)
- rms = 10 * log10(rms);
- assert(rms <= 0);
- if (rms < -kMinLevel)
- rms = -kMinLevel;
+ CheckBlockSize(data.size());
- rms = -rms;
+ float sum_square = 0.f;
+
+ for (float data_k : data) {
+ int16_t tmp =
+ static_cast<int16_t>(std::min(std::max(data_k, -32768.f), 32767.f));
+ sum_square += tmp * tmp;
+ }
+ RTC_DCHECK_GE(sum_square, 0.f);
+ sum_square_ += sum_square;
+ sample_count_ += data.size();
+
+ max_sum_square_ = std::max(max_sum_square_, sum_square);
+}
+
+void RmsLevel::AnalyzeMuted(size_t length) {
+ CheckBlockSize(length);
+ sample_count_ += length;
+}
+
+int RmsLevel::Average() {
+ int rms = (sample_count_ == 0) ? RmsLevel::kMinLevelDb
+ : ComputeRms(sum_square_ / sample_count_);
+ Reset();
+ return rms;
+}
+
+RmsLevel::Levels RmsLevel::AverageAndPeak() {
+ // Note that block_size_ should by design always be non-empty when
+ // sample_count_ != 0. Also, the * operator of absl::optional enforces this
+ // with a DCHECK.
+ Levels levels = (sample_count_ == 0)
+ ? Levels{RmsLevel::kMinLevelDb, RmsLevel::kMinLevelDb}
+ : Levels{ComputeRms(sum_square_ / sample_count_),
+ ComputeRms(max_sum_square_ / *block_size_)};
Reset();
- return static_cast<int>(rms + 0.5);
+ return levels;
}
+void RmsLevel::CheckBlockSize(size_t block_size) {
+ if (block_size_ != block_size) {
+ Reset();
+ block_size_ = block_size;
+ }
+}
} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/rms_level.h b/webrtc/modules/audio_processing/rms_level.h
index 12fa212..e1a6d56 100644
--- a/webrtc/modules/audio_processing/rms_level.h
+++ b/webrtc/modules/audio_processing/rms_level.h
@@ -8,12 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
+#ifndef MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
+#define MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
-#include <cstddef>
+#include <stddef.h>
+#include <stdint.h>
-#include "webrtc/typedefs.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
namespace webrtc {
@@ -23,37 +25,53 @@ namespace webrtc {
// with the intent that it can provide the RTP audio level indication.
//
// The expected approach is to provide constant-sized chunks of audio to
-// Process(). When enough chunks have been accumulated to form a packet, call
-// RMS() to get the audio level indicator for the RTP header.
-class RMSLevel {
+// Analyze(). When enough chunks have been accumulated to form a packet, call
+// Average() to get the audio level indicator for the RTP header.
+class RmsLevel {
public:
- static const int kMinLevel = 127;
+ struct Levels {
+ int average;
+ int peak;
+ };
- RMSLevel();
- ~RMSLevel();
+ enum : int { kMinLevelDb = 127 };
+
+ RmsLevel();
+ ~RmsLevel();
// Can be called to reset internal states, but is not required during normal
// operation.
void Reset();
- // Pass each chunk of audio to Process() to accumulate the level.
- void Process(const int16_t* data, size_t length);
+ // Pass each chunk of audio to Analyze() to accumulate the level.
+ void Analyze(rtc::ArrayView<const int16_t> data);
+ void Analyze(rtc::ArrayView<const float> data);
// If all samples with the given |length| have a magnitude of zero, this is
// a shortcut to avoid some computation.
- void ProcessMuted(size_t length);
+ void AnalyzeMuted(size_t length);
+
+ // Computes the RMS level over all data passed to Analyze() since the last
+ // call to Average(). The returned value is positive but should be interpreted
+ // as negative as per the RFC. It is constrained to [0, 127]. Resets the
+ // internal state to start a new measurement period.
+ int Average();
- // Computes the RMS level over all data passed to Process() since the last
- // call to RMS(). The returned value is positive but should be interpreted as
- // negative as per the RFC. It is constrained to [0, 127].
- int RMS();
+ // Like Average() above, but also returns the RMS peak value. Resets the
+ // internal state to start a new measurement period.
+ Levels AverageAndPeak();
private:
+ // Compares |block_size| with |block_size_|. If they are different, calls
+ // Reset() and stores the new size.
+ void CheckBlockSize(size_t block_size);
+
float sum_square_;
size_t sample_count_;
+ float max_sum_square_;
+ absl::optional<size_t> block_size_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
-
+#endif // MODULES_AUDIO_PROCESSING_RMS_LEVEL_H_
diff --git a/webrtc/modules/audio_processing/splitting_filter.cc b/webrtc/modules/audio_processing/splitting_filter.cc
index 60427e2..d47090b 100644
--- a/webrtc/modules/audio_processing/splitting_filter.cc
+++ b/webrtc/modules/audio_processing/splitting_filter.cc
@@ -8,30 +8,36 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/splitting_filter.h"
+#include "modules/audio_processing/splitting_filter.h"
-#include "webrtc/base/checks.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/common_audio/channel_buffer.h"
+#include <array>
+
+#include "api/array_view.h"
+#include "common_audio/channel_buffer.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "rtc_base/checks.h"
namespace webrtc {
+namespace {
+
+constexpr size_t kSamplesPerBand = 160;
+constexpr size_t kTwoBandFilterSamplesPerFrame = 320;
+
+} // namespace
-SplittingFilter::SplittingFilter(int num_channels,
+SplittingFilter::SplittingFilter(size_t num_channels,
size_t num_bands,
size_t num_frames)
- : num_bands_(num_bands) {
+ : num_bands_(num_bands),
+ two_bands_states_(num_bands_ == 2 ? num_channels : 0),
+ three_band_filter_banks_(num_bands_ == 3 ? num_channels : 0) {
RTC_CHECK(num_bands_ == 2 || num_bands_ == 3);
- if (num_bands_ == 2) {
- two_bands_states_.resize(num_channels);
- } else if (num_bands_ == 3) {
- for (int i = 0; i < num_channels; ++i) {
- three_band_filter_banks_.push_back(new ThreeBandFilterBank(num_frames));
- }
- }
}
-void SplittingFilter::Analysis(const IFChannelBuffer* data,
- IFChannelBuffer* bands) {
+SplittingFilter::~SplittingFilter() = default;
+
+void SplittingFilter::Analysis(const ChannelBuffer<float>* data,
+ ChannelBuffer<float>* bands) {
RTC_DCHECK_EQ(num_bands_, bands->num_bands());
RTC_DCHECK_EQ(data->num_channels(), bands->num_channels());
RTC_DCHECK_EQ(data->num_frames(),
@@ -43,8 +49,8 @@ void SplittingFilter::Analysis(const IFChannelBuffer* data,
}
}
-void SplittingFilter::Synthesis(const IFChannelBuffer* bands,
- IFChannelBuffer* data) {
+void SplittingFilter::Synthesis(const ChannelBuffer<float>* bands,
+ ChannelBuffer<float>* data) {
RTC_DCHECK_EQ(num_bands_, bands->num_bands());
RTC_DCHECK_EQ(data->num_channels(), bands->num_channels());
RTC_DCHECK_EQ(data->num_frames(),
@@ -56,53 +62,82 @@ void SplittingFilter::Synthesis(const IFChannelBuffer* bands,
}
}
-void SplittingFilter::TwoBandsAnalysis(const IFChannelBuffer* data,
- IFChannelBuffer* bands) {
- RTC_DCHECK_EQ(static_cast<int>(two_bands_states_.size()),
- data->num_channels());
+void SplittingFilter::TwoBandsAnalysis(const ChannelBuffer<float>* data,
+ ChannelBuffer<float>* bands) {
+ RTC_DCHECK_EQ(two_bands_states_.size(), data->num_channels());
+ RTC_DCHECK_EQ(data->num_frames(), kTwoBandFilterSamplesPerFrame);
+
for (size_t i = 0; i < two_bands_states_.size(); ++i) {
- WebRtcSpl_AnalysisQMF(data->ibuf_const()->channels()[i],
- data->num_frames(),
- bands->ibuf()->channels(0)[i],
- bands->ibuf()->channels(1)[i],
+ std::array<std::array<int16_t, kSamplesPerBand>, 2> bands16;
+ std::array<int16_t, kTwoBandFilterSamplesPerFrame> full_band16;
+ FloatS16ToS16(data->channels(0)[i], full_band16.size(), full_band16.data());
+ WebRtcSpl_AnalysisQMF(full_band16.data(), data->num_frames(),
+ bands16[0].data(), bands16[1].data(),
two_bands_states_[i].analysis_state1,
two_bands_states_[i].analysis_state2);
+ S16ToFloatS16(bands16[0].data(), bands16[0].size(), bands->channels(0)[i]);
+ S16ToFloatS16(bands16[1].data(), bands16[1].size(), bands->channels(1)[i]);
}
}
-void SplittingFilter::TwoBandsSynthesis(const IFChannelBuffer* bands,
- IFChannelBuffer* data) {
- RTC_DCHECK_EQ(static_cast<int>(two_bands_states_.size()),
- data->num_channels());
- for (size_t i = 0; i < two_bands_states_.size(); ++i) {
- WebRtcSpl_SynthesisQMF(bands->ibuf_const()->channels(0)[i],
- bands->ibuf_const()->channels(1)[i],
- bands->num_frames_per_band(),
- data->ibuf()->channels()[i],
+void SplittingFilter::TwoBandsSynthesis(const ChannelBuffer<float>* bands,
+ ChannelBuffer<float>* data) {
+ RTC_DCHECK_LE(data->num_channels(), two_bands_states_.size());
+ RTC_DCHECK_EQ(data->num_frames(), kTwoBandFilterSamplesPerFrame);
+ for (size_t i = 0; i < data->num_channels(); ++i) {
+ std::array<std::array<int16_t, kSamplesPerBand>, 2> bands16;
+ std::array<int16_t, kTwoBandFilterSamplesPerFrame> full_band16;
+ FloatS16ToS16(bands->channels(0)[i], bands16[0].size(), bands16[0].data());
+ FloatS16ToS16(bands->channels(1)[i], bands16[1].size(), bands16[1].data());
+ WebRtcSpl_SynthesisQMF(bands16[0].data(), bands16[1].data(),
+ bands->num_frames_per_band(), full_band16.data(),
two_bands_states_[i].synthesis_state1,
two_bands_states_[i].synthesis_state2);
+ S16ToFloatS16(full_band16.data(), full_band16.size(), data->channels(0)[i]);
}
}
-void SplittingFilter::ThreeBandsAnalysis(const IFChannelBuffer* data,
- IFChannelBuffer* bands) {
- RTC_DCHECK_EQ(static_cast<int>(three_band_filter_banks_.size()),
- data->num_channels());
+void SplittingFilter::ThreeBandsAnalysis(const ChannelBuffer<float>* data,
+ ChannelBuffer<float>* bands) {
+ RTC_DCHECK_EQ(three_band_filter_banks_.size(), data->num_channels());
+ RTC_DCHECK_LE(data->num_channels(), three_band_filter_banks_.size());
+ RTC_DCHECK_LE(data->num_channels(), bands->num_channels());
+ RTC_DCHECK_EQ(data->num_frames(), ThreeBandFilterBank::kFullBandSize);
+ RTC_DCHECK_EQ(bands->num_frames(), ThreeBandFilterBank::kFullBandSize);
+ RTC_DCHECK_EQ(bands->num_bands(), ThreeBandFilterBank::kNumBands);
+ RTC_DCHECK_EQ(bands->num_frames_per_band(),
+ ThreeBandFilterBank::kSplitBandSize);
+
for (size_t i = 0; i < three_band_filter_banks_.size(); ++i) {
- three_band_filter_banks_[i]->Analysis(data->fbuf_const()->channels()[i],
- data->num_frames(),
- bands->fbuf()->bands(i));
+ three_band_filter_banks_[i].Analysis(
+ rtc::ArrayView<const float, ThreeBandFilterBank::kFullBandSize>(
+ data->channels_view()[i].data(),
+ ThreeBandFilterBank::kFullBandSize),
+ rtc::ArrayView<const rtc::ArrayView<float>,
+ ThreeBandFilterBank::kNumBands>(
+ bands->bands_view(i).data(), ThreeBandFilterBank::kNumBands));
}
}
-void SplittingFilter::ThreeBandsSynthesis(const IFChannelBuffer* bands,
- IFChannelBuffer* data) {
- RTC_DCHECK_EQ(static_cast<int>(three_band_filter_banks_.size()),
- data->num_channels());
- for (size_t i = 0; i < three_band_filter_banks_.size(); ++i) {
- three_band_filter_banks_[i]->Synthesis(bands->fbuf_const()->bands(i),
- bands->num_frames_per_band(),
- data->fbuf()->channels()[i]);
+void SplittingFilter::ThreeBandsSynthesis(const ChannelBuffer<float>* bands,
+ ChannelBuffer<float>* data) {
+ RTC_DCHECK_LE(data->num_channels(), three_band_filter_banks_.size());
+ RTC_DCHECK_LE(data->num_channels(), bands->num_channels());
+ RTC_DCHECK_LE(data->num_channels(), three_band_filter_banks_.size());
+ RTC_DCHECK_EQ(data->num_frames(), ThreeBandFilterBank::kFullBandSize);
+ RTC_DCHECK_EQ(bands->num_frames(), ThreeBandFilterBank::kFullBandSize);
+ RTC_DCHECK_EQ(bands->num_bands(), ThreeBandFilterBank::kNumBands);
+ RTC_DCHECK_EQ(bands->num_frames_per_band(),
+ ThreeBandFilterBank::kSplitBandSize);
+
+ for (size_t i = 0; i < data->num_channels(); ++i) {
+ three_band_filter_banks_[i].Synthesis(
+ rtc::ArrayView<const rtc::ArrayView<float>,
+ ThreeBandFilterBank::kNumBands>(
+ bands->bands_view(i).data(), ThreeBandFilterBank::kNumBands),
+ rtc::ArrayView<float, ThreeBandFilterBank::kFullBandSize>(
+ data->channels_view()[i].data(),
+ ThreeBandFilterBank::kFullBandSize));
}
}
diff --git a/webrtc/modules/audio_processing/splitting_filter.h b/webrtc/modules/audio_processing/splitting_filter.h
index 4698d3f..e578dd0 100644
--- a/webrtc/modules/audio_processing/splitting_filter.h
+++ b/webrtc/modules/audio_processing/splitting_filter.h
@@ -8,19 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_
+#ifndef MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_
#include <cstring>
+#include <memory>
#include <vector>
-#include "webrtc/modules/audio_processing/three_band_filter_bank.h"
-#include "webrtc/system_wrappers/include/scoped_vector.h"
+#include "common_audio/channel_buffer.h"
+#include "modules/audio_processing/three_band_filter_bank.h"
namespace webrtc {
-class IFChannelBuffer;
-
struct TwoBandsStates {
TwoBandsStates() {
memset(analysis_state1, 0, sizeof(analysis_state1));
@@ -41,28 +40,33 @@ struct TwoBandsStates {
//
// For each block, Analysis() is called to split into bands and then Synthesis()
// to merge these bands again. The input and output signals are contained in
-// IFChannelBuffers and for the different bands an array of IFChannelBuffers is
+// ChannelBuffers and for the different bands an array of ChannelBuffers is
// used.
class SplittingFilter {
public:
- SplittingFilter(int num_channels, size_t num_bands, size_t num_frames);
+ SplittingFilter(size_t num_channels, size_t num_bands, size_t num_frames);
+ ~SplittingFilter();
- void Analysis(const IFChannelBuffer* data, IFChannelBuffer* bands);
- void Synthesis(const IFChannelBuffer* bands, IFChannelBuffer* data);
+ void Analysis(const ChannelBuffer<float>* data, ChannelBuffer<float>* bands);
+ void Synthesis(const ChannelBuffer<float>* bands, ChannelBuffer<float>* data);
private:
// Two-band analysis and synthesis work for 640 samples or less.
- void TwoBandsAnalysis(const IFChannelBuffer* data, IFChannelBuffer* bands);
- void TwoBandsSynthesis(const IFChannelBuffer* bands, IFChannelBuffer* data);
- void ThreeBandsAnalysis(const IFChannelBuffer* data, IFChannelBuffer* bands);
- void ThreeBandsSynthesis(const IFChannelBuffer* bands, IFChannelBuffer* data);
+ void TwoBandsAnalysis(const ChannelBuffer<float>* data,
+ ChannelBuffer<float>* bands);
+ void TwoBandsSynthesis(const ChannelBuffer<float>* bands,
+ ChannelBuffer<float>* data);
+ void ThreeBandsAnalysis(const ChannelBuffer<float>* data,
+ ChannelBuffer<float>* bands);
+ void ThreeBandsSynthesis(const ChannelBuffer<float>* bands,
+ ChannelBuffer<float>* data);
void InitBuffers();
const size_t num_bands_;
std::vector<TwoBandsStates> two_bands_states_;
- ScopedVector<ThreeBandFilterBank> three_band_filter_banks_;
+ std::vector<ThreeBandFilterBank> three_band_filter_banks_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_
+#endif // MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_
diff --git a/webrtc/modules/audio_processing/three_band_filter_bank.cc b/webrtc/modules/audio_processing/three_band_filter_bank.cc
index 91e58df..2a7d272 100644
--- a/webrtc/modules/audio_processing/three_band_filter_bank.cc
+++ b/webrtc/modules/audio_processing/three_band_filter_bank.cc
@@ -30,37 +30,33 @@
//
// A similar logic can be applied to the synthesis stage.
-// MSVC++ requires this to be set before any other includes to get M_PI.
-#define _USE_MATH_DEFINES
+#include "modules/audio_processing/three_band_filter_bank.h"
-#include "webrtc/modules/audio_processing/three_band_filter_bank.h"
+#include <array>
-#include <cmath>
-
-#include "webrtc/base/checks.h"
+#include "rtc_base/checks.h"
namespace webrtc {
namespace {
-const size_t kNumBands = 3;
-const size_t kSparsity = 4;
-
-// Factors to take into account when choosing |kNumCoeffs|:
-// 1. Higher |kNumCoeffs|, means faster transition, which ensures less
+// Factors to take into account when choosing |kFilterSize|:
+// 1. Higher |kFilterSize|, means faster transition, which ensures less
// aliasing. This is especially important when there is non-linear
// processing between the splitting and merging.
// 2. The delay that this filter bank introduces is
-// |kNumBands| * |kSparsity| * |kNumCoeffs| / 2, so it increases linearly
-// with |kNumCoeffs|.
-// 3. The computation complexity also increases linearly with |kNumCoeffs|.
-const size_t kNumCoeffs = 4;
+// |kNumBands| * |kSparsity| * |kFilterSize| / 2, so it increases linearly
+// with |kFilterSize|.
+// 3. The computation complexity also increases linearly with |kFilterSize|.
-// The Matlab code to generate these |kLowpassCoeffs| is:
+// The Matlab code to generate these |kFilterCoeffs| is:
//
-// N = kNumBands * kSparsity * kNumCoeffs - 1;
+// N = kNumBands * kSparsity * kFilterSize - 1;
// h = fir1(N, 1 / (2 * kNumBands), kaiser(N + 1, 3.5));
-// reshape(h, kNumBands * kSparsity, kNumCoeffs);
+// reshape(h, kNumBands * kSparsity, kFilterSize);
//
+// The code below uses the values of kFilterSize, kNumBands and kSparsity
+// specified in the header.
+
// Because the total bandwidth of the lower and higher band is double the middle
// one (because of the spectrum parity), the low-pass prototype is half the
// bandwidth of 1 / (2 * |kNumBands|) and is then shifted with cosine modulation
@@ -68,39 +64,84 @@ const size_t kNumCoeffs = 4;
// A Kaiser window is used because of its flexibility and the alpha is set to
// 3.5, since that sets a stop band attenuation of 40dB ensuring a fast
// transition.
-const float kLowpassCoeffs[kNumBands * kSparsity][kNumCoeffs] =
- {{-0.00047749f, -0.00496888f, +0.16547118f, +0.00425496f},
- {-0.00173287f, -0.01585778f, +0.14989004f, +0.00994113f},
- {-0.00304815f, -0.02536082f, +0.12154542f, +0.01157993f},
- {-0.00383509f, -0.02982767f, +0.08543175f, +0.00983212f},
- {-0.00346946f, -0.02587886f, +0.04760441f, +0.00607594f},
- {-0.00154717f, -0.01136076f, +0.01387458f, +0.00186353f},
- {+0.00186353f, +0.01387458f, -0.01136076f, -0.00154717f},
- {+0.00607594f, +0.04760441f, -0.02587886f, -0.00346946f},
- {+0.00983212f, +0.08543175f, -0.02982767f, -0.00383509f},
- {+0.01157993f, +0.12154542f, -0.02536082f, -0.00304815f},
- {+0.00994113f, +0.14989004f, -0.01585778f, -0.00173287f},
- {+0.00425496f, +0.16547118f, -0.00496888f, -0.00047749f}};
-
-// Downsamples |in| into |out|, taking one every |kNumbands| starting from
-// |offset|. |split_length| is the |out| length. |in| has to be at least
-// |kNumBands| * |split_length| long.
-void Downsample(const float* in,
- size_t split_length,
- size_t offset,
- float* out) {
- for (size_t i = 0; i < split_length; ++i) {
- out[i] = in[kNumBands * i + offset];
+
+constexpr int kSubSampling = ThreeBandFilterBank::kNumBands;
+constexpr int kDctSize = ThreeBandFilterBank::kNumBands;
+static_assert(ThreeBandFilterBank::kNumBands *
+ ThreeBandFilterBank::kSplitBandSize ==
+ ThreeBandFilterBank::kFullBandSize,
+ "The full band must be split in equally sized subbands");
+
+const float
+ kFilterCoeffs[ThreeBandFilterBank::kNumNonZeroFilters][kFilterSize] = {
+ {-0.00047749f, -0.00496888f, +0.16547118f, +0.00425496f},
+ {-0.00173287f, -0.01585778f, +0.14989004f, +0.00994113f},
+ {-0.00304815f, -0.02536082f, +0.12154542f, +0.01157993f},
+ {-0.00346946f, -0.02587886f, +0.04760441f, +0.00607594f},
+ {-0.00154717f, -0.01136076f, +0.01387458f, +0.00186353f},
+ {+0.00186353f, +0.01387458f, -0.01136076f, -0.00154717f},
+ {+0.00607594f, +0.04760441f, -0.02587886f, -0.00346946f},
+ {+0.00983212f, +0.08543175f, -0.02982767f, -0.00383509f},
+ {+0.00994113f, +0.14989004f, -0.01585778f, -0.00173287f},
+ {+0.00425496f, +0.16547118f, -0.00496888f, -0.00047749f}};
+
+constexpr int kZeroFilterIndex1 = 3;
+constexpr int kZeroFilterIndex2 = 9;
+
+const float kDctModulation[ThreeBandFilterBank::kNumNonZeroFilters][kDctSize] =
+ {{2.f, 2.f, 2.f},
+ {1.73205077f, 0.f, -1.73205077f},
+ {1.f, -2.f, 1.f},
+ {-1.f, 2.f, -1.f},
+ {-1.73205077f, 0.f, 1.73205077f},
+ {-2.f, -2.f, -2.f},
+ {-1.73205077f, 0.f, 1.73205077f},
+ {-1.f, 2.f, -1.f},
+ {1.f, -2.f, 1.f},
+ {1.73205077f, 0.f, -1.73205077f}};
+
+// Filters the input signal |in| with the filter |filter| using a shift by
+// |in_shift|, taking into account the previous state.
+void FilterCore(
+ rtc::ArrayView<const float, kFilterSize> filter,
+ rtc::ArrayView<const float, ThreeBandFilterBank::kSplitBandSize> in,
+ const int in_shift,
+ rtc::ArrayView<float, ThreeBandFilterBank::kSplitBandSize> out,
+ rtc::ArrayView<float, kMemorySize> state) {
+ constexpr int kMaxInShift = (kStride - 1);
+ RTC_DCHECK_GE(in_shift, 0);
+ RTC_DCHECK_LE(in_shift, kMaxInShift);
+ std::fill(out.begin(), out.end(), 0.f);
+
+ for (int k = 0; k < in_shift; ++k) {
+ for (int i = 0, j = kMemorySize + k - in_shift; i < kFilterSize;
+ ++i, j -= kStride) {
+ out[k] += state[j] * filter[i];
+ }
}
-}
-// Upsamples |in| into |out|, scaling by |kNumBands| and accumulating it every
-// |kNumBands| starting from |offset|. |split_length| is the |in| length. |out|
-// has to be at least |kNumBands| * |split_length| long.
-void Upsample(const float* in, size_t split_length, size_t offset, float* out) {
- for (size_t i = 0; i < split_length; ++i) {
- out[kNumBands * i + offset] += kNumBands * in[i];
+ for (int k = in_shift, shift = 0; k < kFilterSize * kStride; ++k, ++shift) {
+ RTC_DCHECK_GE(shift, 0);
+ const int loop_limit = std::min(kFilterSize, 1 + (shift >> kStrideLog2));
+ for (int i = 0, j = shift; i < loop_limit; ++i, j -= kStride) {
+ out[k] += in[j] * filter[i];
+ }
+ for (int i = loop_limit, j = kMemorySize + shift - loop_limit * kStride;
+ i < kFilterSize; ++i, j -= kStride) {
+ out[k] += state[j] * filter[i];
+ }
}
+
+ for (int k = kFilterSize * kStride, shift = kFilterSize * kStride - in_shift;
+ k < ThreeBandFilterBank::kSplitBandSize; ++k, ++shift) {
+ for (int i = 0, j = shift; i < kFilterSize; ++i, j -= kStride) {
+ out[k] += in[j] * filter[i];
+ }
+ }
+
+ // Update current state.
+ std::copy(in.begin() + ThreeBandFilterBank::kSplitBandSize - kMemorySize,
+ in.end(), state.begin());
}
} // namespace
@@ -108,48 +149,72 @@ void Upsample(const float* in, size_t split_length, size_t offset, float* out) {
// Because the low-pass filter prototype has half bandwidth it is possible to
// use a DCT to shift it in both directions at the same time, to the center
// frequencies [1 / 12, 3 / 12, 5 / 12].
-ThreeBandFilterBank::ThreeBandFilterBank(size_t length)
- : in_buffer_(rtc::CheckedDivExact(length, kNumBands)),
- out_buffer_(in_buffer_.size()) {
- for (size_t i = 0; i < kSparsity; ++i) {
- for (size_t j = 0; j < kNumBands; ++j) {
- analysis_filters_.push_back(new SparseFIRFilter(
- kLowpassCoeffs[i * kNumBands + j], kNumCoeffs, kSparsity, i));
- synthesis_filters_.push_back(new SparseFIRFilter(
- kLowpassCoeffs[i * kNumBands + j], kNumCoeffs, kSparsity, i));
- }
- }
- dct_modulation_.resize(kNumBands * kSparsity);
- for (size_t i = 0; i < dct_modulation_.size(); ++i) {
- dct_modulation_[i].resize(kNumBands);
- for (size_t j = 0; j < kNumBands; ++j) {
- dct_modulation_[i][j] =
- 2.f * cos(2.f * M_PI * i * (2.f * j + 1.f) / dct_modulation_.size());
- }
+ThreeBandFilterBank::ThreeBandFilterBank() {
+ RTC_DCHECK_EQ(state_analysis_.size(), kNumNonZeroFilters);
+ RTC_DCHECK_EQ(state_synthesis_.size(), kNumNonZeroFilters);
+ for (int k = 0; k < kNumNonZeroFilters; ++k) {
+ RTC_DCHECK_EQ(state_analysis_[k].size(), kMemorySize);
+ RTC_DCHECK_EQ(state_synthesis_[k].size(), kMemorySize);
+
+ state_analysis_[k].fill(0.f);
+ state_synthesis_[k].fill(0.f);
}
}
+ThreeBandFilterBank::~ThreeBandFilterBank() = default;
+
// The analysis can be separated in these steps:
// 1. Serial to parallel downsampling by a factor of |kNumBands|.
// 2. Filtering of |kSparsity| different delayed signals with polyphase
// decomposition of the low-pass prototype filter and upsampled by a factor
// of |kSparsity|.
// 3. Modulating with cosines and accumulating to get the desired band.
-void ThreeBandFilterBank::Analysis(const float* in,
- size_t length,
- float* const* out) {
- RTC_CHECK_EQ(in_buffer_.size(), rtc::CheckedDivExact(length, kNumBands));
- for (size_t i = 0; i < kNumBands; ++i) {
- memset(out[i], 0, in_buffer_.size() * sizeof(*out[i]));
+void ThreeBandFilterBank::Analysis(
+ rtc::ArrayView<const float, kFullBandSize> in,
+ rtc::ArrayView<const rtc::ArrayView<float>, ThreeBandFilterBank::kNumBands>
+ out) {
+ // Initialize the output to zero.
+ for (int band = 0; band < ThreeBandFilterBank::kNumBands; ++band) {
+ RTC_DCHECK_EQ(out[band].size(), kSplitBandSize);
+ std::fill(out[band].begin(), out[band].end(), 0);
}
- for (size_t i = 0; i < kNumBands; ++i) {
- Downsample(in, in_buffer_.size(), kNumBands - i - 1, &in_buffer_[0]);
- for (size_t j = 0; j < kSparsity; ++j) {
- const size_t offset = i + j * kNumBands;
- analysis_filters_[offset]->Filter(&in_buffer_[0],
- in_buffer_.size(),
- &out_buffer_[0]);
- DownModulate(&out_buffer_[0], out_buffer_.size(), offset, out);
+
+ for (int downsampling_index = 0; downsampling_index < kSubSampling;
+ ++downsampling_index) {
+ // Downsample to form the filter input.
+ std::array<float, kSplitBandSize> in_subsampled;
+ for (int k = 0; k < kSplitBandSize; ++k) {
+ in_subsampled[k] =
+ in[(kSubSampling - 1) - downsampling_index + kSubSampling * k];
+ }
+
+ for (int in_shift = 0; in_shift < kStride; ++in_shift) {
+ // Choose filter, skip zero filters.
+ const int index = downsampling_index + in_shift * kSubSampling;
+ if (index == kZeroFilterIndex1 || index == kZeroFilterIndex2) {
+ continue;
+ }
+ const int filter_index =
+ index < kZeroFilterIndex1
+ ? index
+ : (index < kZeroFilterIndex2 ? index - 1 : index - 2);
+
+ rtc::ArrayView<const float, kFilterSize> filter(
+ kFilterCoeffs[filter_index]);
+ rtc::ArrayView<const float, kDctSize> dct_modulation(
+ kDctModulation[filter_index]);
+ rtc::ArrayView<float, kMemorySize> state(state_analysis_[filter_index]);
+
+ // Filter.
+ std::array<float, kSplitBandSize> out_subsampled;
+ FilterCore(filter, in_subsampled, in_shift, out_subsampled, state);
+
+ // Band and modulate the output.
+ for (int band = 0; band < ThreeBandFilterBank::kNumBands; ++band) {
+ for (int n = 0; n < kSplitBandSize; ++n) {
+ out[band][n] += dct_modulation[band] * out_subsampled[n];
+ }
+ }
}
}
}
@@ -160,51 +225,50 @@ void ThreeBandFilterBank::Analysis(const float* in,
// prototype filter upsampled by a factor of |kSparsity| and accumulating
// |kSparsity| signals with different delays.
// 3. Parallel to serial upsampling by a factor of |kNumBands|.
-void ThreeBandFilterBank::Synthesis(const float* const* in,
- size_t split_length,
- float* out) {
- RTC_CHECK_EQ(in_buffer_.size(), split_length);
- memset(out, 0, kNumBands * in_buffer_.size() * sizeof(*out));
- for (size_t i = 0; i < kNumBands; ++i) {
- for (size_t j = 0; j < kSparsity; ++j) {
- const size_t offset = i + j * kNumBands;
- UpModulate(in, in_buffer_.size(), offset, &in_buffer_[0]);
- synthesis_filters_[offset]->Filter(&in_buffer_[0],
- in_buffer_.size(),
- &out_buffer_[0]);
- Upsample(&out_buffer_[0], out_buffer_.size(), i, out);
- }
- }
-}
+void ThreeBandFilterBank::Synthesis(
+ rtc::ArrayView<const rtc::ArrayView<float>, ThreeBandFilterBank::kNumBands>
+ in,
+ rtc::ArrayView<float, kFullBandSize> out) {
+ std::fill(out.begin(), out.end(), 0);
+ for (int upsampling_index = 0; upsampling_index < kSubSampling;
+ ++upsampling_index) {
+ for (int in_shift = 0; in_shift < kStride; ++in_shift) {
+ // Choose filter, skip zero filters.
+ const int index = upsampling_index + in_shift * kSubSampling;
+ if (index == kZeroFilterIndex1 || index == kZeroFilterIndex2) {
+ continue;
+ }
+ const int filter_index =
+ index < kZeroFilterIndex1
+ ? index
+ : (index < kZeroFilterIndex2 ? index - 1 : index - 2);
+ rtc::ArrayView<const float, kFilterSize> filter(
+ kFilterCoeffs[filter_index]);
+ rtc::ArrayView<const float, kDctSize> dct_modulation(
+ kDctModulation[filter_index]);
+ rtc::ArrayView<float, kMemorySize> state(state_synthesis_[filter_index]);
-// Modulates |in| by |dct_modulation_| and accumulates it in each of the
-// |kNumBands| bands of |out|. |offset| is the index in the period of the
-// cosines used for modulation. |split_length| is the length of |in| and each
-// band of |out|.
-void ThreeBandFilterBank::DownModulate(const float* in,
- size_t split_length,
- size_t offset,
- float* const* out) {
- for (size_t i = 0; i < kNumBands; ++i) {
- for (size_t j = 0; j < split_length; ++j) {
- out[i][j] += dct_modulation_[offset][i] * in[j];
- }
- }
-}
+ // Prepare filter input by modulating the banded input.
+ std::array<float, kSplitBandSize> in_subsampled;
+ std::fill(in_subsampled.begin(), in_subsampled.end(), 0.f);
+ for (int band = 0; band < ThreeBandFilterBank::kNumBands; ++band) {
+ RTC_DCHECK_EQ(in[band].size(), kSplitBandSize);
+ for (int n = 0; n < kSplitBandSize; ++n) {
+ in_subsampled[n] += dct_modulation[band] * in[band][n];
+ }
+ }
+
+ // Filter.
+ std::array<float, kSplitBandSize> out_subsampled;
+ FilterCore(filter, in_subsampled, in_shift, out_subsampled, state);
-// Modulates each of the |kNumBands| bands of |in| by |dct_modulation_| and
-// accumulates them in |out|. |out| is cleared before starting to accumulate.
-// |offset| is the index in the period of the cosines used for modulation.
-// |split_length| is the length of each band of |in| and |out|.
-void ThreeBandFilterBank::UpModulate(const float* const* in,
- size_t split_length,
- size_t offset,
- float* out) {
- memset(out, 0, split_length * sizeof(*out));
- for (size_t i = 0; i < kNumBands; ++i) {
- for (size_t j = 0; j < split_length; ++j) {
- out[j] += dct_modulation_[offset][i] * in[i][j];
+ // Upsample.
+ constexpr float kUpsamplingScaling = kSubSampling;
+ for (int k = 0; k < kSplitBandSize; ++k) {
+ out[upsampling_index + kSubSampling * k] +=
+ kUpsamplingScaling * out_subsampled[k];
+ }
}
}
}
diff --git a/webrtc/modules/audio_processing/three_band_filter_bank.h b/webrtc/modules/audio_processing/three_band_filter_bank.h
index cb9cfbe..e6346de 100644
--- a/webrtc/modules/audio_processing/three_band_filter_bank.h
+++ b/webrtc/modules/audio_processing/three_band_filter_bank.h
@@ -8,17 +8,28 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_
+#ifndef MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_
+#define MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_
+#include <array>
#include <cstring>
+#include <memory>
#include <vector>
-#include "webrtc/common_audio/sparse_fir_filter.h"
-#include "webrtc/system_wrappers/include/scoped_vector.h"
+#include "api/array_view.h"
namespace webrtc {
+constexpr int kSparsity = 4;
+constexpr int kStrideLog2 = 2;
+constexpr int kStride = 1 << kStrideLog2;
+constexpr int kNumZeroFilters = 2;
+constexpr int kFilterSize = 4;
+constexpr int kMemorySize = kFilterSize * kStride - 1;
+static_assert(kMemorySize == 15,
+ "The memory size must be sufficient to provide memory for the "
+ "shifted filters");
+
// An implementation of a 3-band FIR filter-bank with DCT modulation, similar to
// the proposed in "Multirate Signal Processing for Communication Systems" by
// Fredric J Harris.
@@ -34,35 +45,33 @@ namespace webrtc {
// depending on the input signal after compensating for the delay.
class ThreeBandFilterBank final {
public:
- explicit ThreeBandFilterBank(size_t length);
+ static const int kNumBands = 3;
+ static const int kFullBandSize = 480;
+ static const int kSplitBandSize =
+ ThreeBandFilterBank::kFullBandSize / ThreeBandFilterBank::kNumBands;
+ static const int kNumNonZeroFilters =
+ kSparsity * ThreeBandFilterBank::kNumBands - kNumZeroFilters;
- // Splits |in| into 3 downsampled frequency bands in |out|.
- // |length| is the |in| length. Each of the 3 bands of |out| has to have a
- // length of |length| / 3.
- void Analysis(const float* in, size_t length, float* const* out);
+ ThreeBandFilterBank();
+ ~ThreeBandFilterBank();
- // Merges the 3 downsampled frequency bands in |in| into |out|.
- // |split_length| is the length of each band of |in|. |out| has to have at
- // least a length of 3 * |split_length|.
- void Synthesis(const float* const* in, size_t split_length, float* out);
+ // Splits |in| of size kFullBandSize into 3 downsampled frequency bands in
+ // |out|, each of size 160.
+ void Analysis(rtc::ArrayView<const float, kFullBandSize> in,
+ rtc::ArrayView<const rtc::ArrayView<float>, kNumBands> out);
- private:
- void DownModulate(const float* in,
- size_t split_length,
- size_t offset,
- float* const* out);
- void UpModulate(const float* const* in,
- size_t split_length,
- size_t offset,
- float* out);
+ // Merges the 3 downsampled frequency bands in |in|, each of size 160, into
+ // |out|, which is of size kFullBandSize.
+ void Synthesis(rtc::ArrayView<const rtc::ArrayView<float>, kNumBands> in,
+ rtc::ArrayView<float, kFullBandSize> out);
- std::vector<float> in_buffer_;
- std::vector<float> out_buffer_;
- ScopedVector<SparseFIRFilter> analysis_filters_;
- ScopedVector<SparseFIRFilter> synthesis_filters_;
- std::vector<std::vector<float>> dct_modulation_;
+ private:
+ std::array<std::array<float, kMemorySize>, kNumNonZeroFilters>
+ state_analysis_;
+ std::array<std::array<float, kMemorySize>, kNumNonZeroFilters>
+ state_synthesis_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_
+#endif // MODULES_AUDIO_PROCESSING_THREE_BAND_FILTER_BANK_H_
diff --git a/webrtc/modules/audio_processing/transient/BUILD.gn b/webrtc/modules/audio_processing/transient/BUILD.gn
new file mode 100644
index 0000000..13e319f
--- /dev/null
+++ b/webrtc/modules/audio_processing/transient/BUILD.gn
@@ -0,0 +1,112 @@
+# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("transient_suppressor_api") {
+ sources = [ "transient_suppressor.h" ]
+}
+
+rtc_library("transient_suppressor_impl") {
+ visibility = [
+ "..:optionally_built_submodule_creators",
+ ":transient_suppression_test",
+ ":transient_suppression_unittests",
+ ":click_annotate",
+ ]
+ sources = [
+ "common.h",
+ "daubechies_8_wavelet_coeffs.h",
+ "dyadic_decimator.h",
+ "moving_moments.cc",
+ "moving_moments.h",
+ "transient_detector.cc",
+ "transient_detector.h",
+ "transient_suppressor_impl.cc",
+ "transient_suppressor_impl.h",
+ "windows_private.h",
+ "wpd_node.cc",
+ "wpd_node.h",
+ "wpd_tree.cc",
+ "wpd_tree.h",
+ ]
+ deps = [
+ ":transient_suppressor_api",
+ "../../../common_audio:common_audio",
+ "../../../common_audio:common_audio_c",
+ "../../../common_audio:fir_filter",
+ "../../../common_audio:fir_filter_factory",
+ "../../../common_audio/third_party/ooura:fft_size_256",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gtest_prod",
+ "../../../rtc_base:logging",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_executable("click_annotate") {
+ testonly = true
+ sources = [
+ "click_annotate.cc",
+ "file_utils.cc",
+ "file_utils.h",
+ ]
+ deps = [
+ ":transient_suppressor_impl",
+ "..:audio_processing",
+ "../../../rtc_base/system:file_wrapper",
+ "../../../system_wrappers",
+ ]
+ }
+
+ rtc_executable("transient_suppression_test") {
+ testonly = true
+ sources = [
+ "file_utils.cc",
+ "file_utils.h",
+ "transient_suppression_test.cc",
+ ]
+ deps = [
+ ":transient_suppressor_impl",
+ "..:audio_processing",
+ "../../../common_audio",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../rtc_base/system:file_wrapper",
+ "../../../system_wrappers",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "../agc:level_estimation",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ ]
+ }
+
+ rtc_library("transient_suppression_unittests") {
+ testonly = true
+ sources = [
+ "dyadic_decimator_unittest.cc",
+ "file_utils.cc",
+ "file_utils.h",
+ "file_utils_unittest.cc",
+ "moving_moments_unittest.cc",
+ "transient_detector_unittest.cc",
+ "transient_suppressor_unittest.cc",
+ "wpd_node_unittest.cc",
+ "wpd_tree_unittest.cc",
+ ]
+ deps = [
+ ":transient_suppressor_impl",
+ "../../../rtc_base:stringutils",
+ "../../../rtc_base/system:file_wrapper",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+}
diff --git a/webrtc/modules/audio_processing/transient/click_annotate.cc b/webrtc/modules/audio_processing/transient/click_annotate.cc
index 38f7a8e..21641f8 100644
--- a/webrtc/modules/audio_processing/transient/click_annotate.cc
+++ b/webrtc/modules/audio_processing/transient/click_annotate.cc
@@ -11,14 +11,13 @@
#include <cfloat>
#include <cstdio>
#include <cstdlib>
+#include <memory>
#include <vector>
-#include "webrtc/modules/audio_processing/transient/transient_detector.h"
-#include "webrtc/modules/audio_processing/transient/file_utils.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/system_wrappers/include/file_wrapper.h"
+#include "modules/audio_processing/transient/file_utils.h"
+#include "modules/audio_processing/transient/transient_detector.h"
+#include "rtc_base/system/file_wrapper.h"
-using rtc::scoped_ptr;
using webrtc::FileWrapper;
using webrtc::TransientDetector;
@@ -40,16 +39,14 @@ int main(int argc, char* argv[]) {
return 0;
}
- scoped_ptr<FileWrapper> pcm_file(FileWrapper::Create());
- pcm_file->OpenFile(argv[1], true, false, false);
- if (!pcm_file->Open()) {
+ FileWrapper pcm_file = FileWrapper::OpenReadOnly(argv[1]);
+ if (!pcm_file.is_open()) {
printf("\nThe %s could not be opened.\n\n", argv[1]);
return -1;
}
- scoped_ptr<FileWrapper> dat_file(FileWrapper::Create());
- dat_file->OpenFile(argv[2], false, false, false);
- if (!dat_file->Open()) {
+ FileWrapper dat_file = FileWrapper::OpenWriteOnly(argv[2]);
+ if (!dat_file.is_open()) {
printf("\nThe %s could not be opened.\n\n", argv[2]);
return -1;
}
@@ -69,14 +66,12 @@ int main(int argc, char* argv[]) {
TransientDetector detector(sample_rate_hz);
int lost_packets = 0;
size_t audio_buffer_length = chunk_size_ms * sample_rate_hz / 1000;
- scoped_ptr<float[]> audio_buffer(new float[audio_buffer_length]);
+ std::unique_ptr<float[]> audio_buffer(new float[audio_buffer_length]);
std::vector<float> send_times;
// Read first buffer from the PCM test file.
size_t file_samples_read = ReadInt16FromFileToFloatBuffer(
- pcm_file.get(),
- audio_buffer_length,
- audio_buffer.get());
+ &pcm_file, audio_buffer_length, audio_buffer.get());
for (int time = 0; file_samples_read > 0; time += chunk_size_ms) {
// Pad the rest of the buffer with zeros.
for (size_t i = file_samples_read; i < audio_buffer_length; ++i) {
@@ -93,22 +88,20 @@ int main(int argc, char* argv[]) {
send_times.push_back(value);
// Read next buffer from the PCM test file.
- file_samples_read = ReadInt16FromFileToFloatBuffer(pcm_file.get(),
- audio_buffer_length,
- audio_buffer.get());
+ file_samples_read = ReadInt16FromFileToFloatBuffer(
+ &pcm_file, audio_buffer_length, audio_buffer.get());
}
- size_t floats_written = WriteFloatBufferToFile(dat_file.get(),
- send_times.size(),
- &send_times[0]);
+ size_t floats_written =
+ WriteFloatBufferToFile(&dat_file, send_times.size(), &send_times[0]);
if (floats_written == 0) {
printf("\nThe send times could not be written to DAT file\n\n");
return -1;
}
- pcm_file->CloseFile();
- dat_file->CloseFile();
+ pcm_file.Close();
+ dat_file.Close();
return lost_packets;
}
diff --git a/webrtc/modules/audio_processing/transient/common.h b/webrtc/modules/audio_processing/transient/common.h
index 92194e9..63c9a7b 100644
--- a/webrtc/modules/audio_processing/transient/common.h
+++ b/webrtc/modules/audio_processing/transient/common.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
namespace webrtc {
namespace ts {
@@ -22,6 +22,6 @@ enum {
kSampleRate48kHz = 48000
};
-} // namespace ts
-} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
+} // namespace ts
+} // namespace webrtc
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
diff --git a/webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h b/webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h
index b1236ac..92233bf 100644
--- a/webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h
+++ b/webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h
@@ -10,8 +10,8 @@
// This header file defines the coefficients of the FIR based approximation of
// the Meyer Wavelet
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
// Decomposition coefficients Daubechies 8.
@@ -19,45 +19,26 @@ namespace webrtc {
const int kDaubechies8CoefficientsLength = 16;
-const float kDaubechies8HighPassCoefficients[kDaubechies8CoefficientsLength]
- = {
- -5.44158422430816093862e-02f,
- 3.12871590914465924627e-01f,
- -6.75630736298012846142e-01f,
- 5.85354683654869090148e-01f,
- 1.58291052560238926228e-02f,
- -2.84015542962428091389e-01f,
- -4.72484573997972536787e-04f,
- 1.28747426620186011803e-01f,
- 1.73693010020221083600e-02f,
- -4.40882539310647192377e-02f,
- -1.39810279170155156436e-02f,
- 8.74609404701565465445e-03f,
- 4.87035299301066034600e-03f,
- -3.91740372995977108837e-04f,
- -6.75449405998556772109e-04f,
- -1.17476784002281916305e-04f
-};
+const float kDaubechies8HighPassCoefficients[kDaubechies8CoefficientsLength] = {
+ -5.44158422430816093862e-02f, 3.12871590914465924627e-01f,
+ -6.75630736298012846142e-01f, 5.85354683654869090148e-01f,
+ 1.58291052560238926228e-02f, -2.84015542962428091389e-01f,
+ -4.72484573997972536787e-04f, 1.28747426620186011803e-01f,
+ 1.73693010020221083600e-02f, -4.40882539310647192377e-02f,
+ -1.39810279170155156436e-02f, 8.74609404701565465445e-03f,
+ 4.87035299301066034600e-03f, -3.91740372995977108837e-04f,
+ -6.75449405998556772109e-04f, -1.17476784002281916305e-04f};
const float kDaubechies8LowPassCoefficients[kDaubechies8CoefficientsLength] = {
- -1.17476784002281916305e-04f,
- 6.75449405998556772109e-04f,
- -3.91740372995977108837e-04f,
- -4.87035299301066034600e-03f,
- 8.74609404701565465445e-03f,
- 1.39810279170155156436e-02f,
- -4.40882539310647192377e-02f,
- -1.73693010020221083600e-02f,
- 1.28747426620186011803e-01f,
- 4.72484573997972536787e-04f,
- -2.84015542962428091389e-01f,
- -1.58291052560238926228e-02f,
- 5.85354683654869090148e-01f,
- 6.75630736298012846142e-01f,
- 3.12871590914465924627e-01f,
- 5.44158422430816093862e-02f
-};
+ -1.17476784002281916305e-04f, 6.75449405998556772109e-04f,
+ -3.91740372995977108837e-04f, -4.87035299301066034600e-03f,
+ 8.74609404701565465445e-03f, 1.39810279170155156436e-02f,
+ -4.40882539310647192377e-02f, -1.73693010020221083600e-02f,
+ 1.28747426620186011803e-01f, 4.72484573997972536787e-04f,
+ -2.84015542962428091389e-01f, -1.58291052560238926228e-02f,
+ 5.85354683654869090148e-01f, 6.75630736298012846142e-01f,
+ 3.12871590914465924627e-01f, 5.44158422430816093862e-02f};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
diff --git a/webrtc/modules/audio_processing/transient/dyadic_decimator.h b/webrtc/modules/audio_processing/transient/dyadic_decimator.h
index c1046f2..fcb56b7 100644
--- a/webrtc/modules/audio_processing/transient/dyadic_decimator.h
+++ b/webrtc/modules/audio_processing/transient/dyadic_decimator.h
@@ -8,13 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
#include <cstdlib>
-#include "webrtc/typedefs.h"
-
// Provides a set of static methods to perform dyadic decimations.
namespace webrtc {
@@ -44,7 +42,7 @@ inline size_t GetOutLengthToDyadicDecimate(size_t in_length,
// GetOutLengthToDyadicDecimate().
// Must be previously allocated.
// Returns the number of output samples, -1 on error.
-template<typename T>
+template <typename T>
static size_t DyadicDecimate(const T* in,
size_t in_length,
bool odd_sequence,
@@ -67,4 +65,4 @@ static size_t DyadicDecimate(const T* in,
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
diff --git a/webrtc/modules/audio_processing/transient/file_utils.cc b/webrtc/modules/audio_processing/transient/file_utils.cc
index e043286..58f9932 100644
--- a/webrtc/modules/audio_processing/transient/file_utils.cc
+++ b/webrtc/modules/audio_processing/transient/file_utils.cc
@@ -8,11 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/transient/file_utils.h"
+#include "modules/audio_processing/transient/file_utils.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/system_wrappers/include/file_wrapper.h"
-#include "webrtc/typedefs.h"
+#include <memory>
+
+#include "rtc_base/system/file_wrapper.h"
namespace webrtc {
@@ -79,11 +79,11 @@ int ConvertDoubleToByteArray(double value, uint8_t out_bytes[8]) {
size_t ReadInt16BufferFromFile(FileWrapper* file,
size_t length,
int16_t* buffer) {
- if (!file || !file->Open() || !buffer || length <= 0) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
return 0;
}
- rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[2]);
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[2]);
size_t int16s_read = 0;
@@ -105,11 +105,11 @@ size_t ReadInt16BufferFromFile(FileWrapper* file,
size_t ReadInt16FromFileToFloatBuffer(FileWrapper* file,
size_t length,
float* buffer) {
- if (!file || !file->Open() || !buffer || length <= 0) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
return 0;
}
- rtc::scoped_ptr<int16_t[]> buffer16(new int16_t[length]);
+ std::unique_ptr<int16_t[]> buffer16(new int16_t[length]);
size_t int16s_read = ReadInt16BufferFromFile(file, length, buffer16.get());
@@ -123,11 +123,11 @@ size_t ReadInt16FromFileToFloatBuffer(FileWrapper* file,
size_t ReadInt16FromFileToDoubleBuffer(FileWrapper* file,
size_t length,
double* buffer) {
- if (!file || !file->Open() || !buffer || length <= 0) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
return 0;
}
- rtc::scoped_ptr<int16_t[]> buffer16(new int16_t[length]);
+ std::unique_ptr<int16_t[]> buffer16(new int16_t[length]);
size_t int16s_read = ReadInt16BufferFromFile(file, length, buffer16.get());
@@ -141,11 +141,11 @@ size_t ReadInt16FromFileToDoubleBuffer(FileWrapper* file,
size_t ReadFloatBufferFromFile(FileWrapper* file,
size_t length,
float* buffer) {
- if (!file || !file->Open() || !buffer || length <= 0) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
return 0;
}
- rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[4]);
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[4]);
size_t floats_read = 0;
@@ -164,11 +164,11 @@ size_t ReadFloatBufferFromFile(FileWrapper* file,
size_t ReadDoubleBufferFromFile(FileWrapper* file,
size_t length,
double* buffer) {
- if (!file || !file->Open() || !buffer || length <= 0) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
return 0;
}
- rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[8]);
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[8]);
size_t doubles_read = 0;
@@ -187,11 +187,11 @@ size_t ReadDoubleBufferFromFile(FileWrapper* file,
size_t WriteInt16BufferToFile(FileWrapper* file,
size_t length,
const int16_t* buffer) {
- if (!file || !file->Open() || !buffer || length <= 0) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
return 0;
}
- rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[2]);
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[2]);
size_t int16s_written = 0;
@@ -211,11 +211,11 @@ size_t WriteInt16BufferToFile(FileWrapper* file,
size_t WriteFloatBufferToFile(FileWrapper* file,
size_t length,
const float* buffer) {
- if (!file || !file->Open() || !buffer || length <= 0) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
return 0;
}
- rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[4]);
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[4]);
size_t floats_written = 0;
@@ -234,11 +234,11 @@ size_t WriteFloatBufferToFile(FileWrapper* file,
size_t WriteDoubleBufferToFile(FileWrapper* file,
size_t length,
const double* buffer) {
- if (!file || !file->Open() || !buffer || length <= 0) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
return 0;
}
- rtc::scoped_ptr<uint8_t[]> byte_array(new uint8_t[8]);
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[8]);
size_t doubles_written = 0;
diff --git a/webrtc/modules/audio_processing/transient/file_utils.h b/webrtc/modules/audio_processing/transient/file_utils.h
index cc76953..6184017 100644
--- a/webrtc/modules/audio_processing/transient/file_utils.h
+++ b/webrtc/modules/audio_processing/transient/file_utils.h
@@ -8,13 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
#include <string.h>
-#include "webrtc/system_wrappers/include/file_wrapper.h"
-#include "webrtc/typedefs.h"
+#include "rtc_base/system/file_wrapper.h"
namespace webrtc {
@@ -115,4 +114,4 @@ size_t WriteDoubleBufferToFile(FileWrapper* file,
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
diff --git a/webrtc/modules/audio_processing/transient/moving_moments.cc b/webrtc/modules/audio_processing/transient/moving_moments.cc
index aa47522..83810bf 100644
--- a/webrtc/modules/audio_processing/transient/moving_moments.cc
+++ b/webrtc/modules/audio_processing/transient/moving_moments.cc
@@ -8,21 +8,17 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/transient/moving_moments.h"
+#include "modules/audio_processing/transient/moving_moments.h"
-#include <math.h>
-#include <string.h>
+#include <algorithm>
-#include "webrtc/base/scoped_ptr.h"
+#include "rtc_base/checks.h"
namespace webrtc {
MovingMoments::MovingMoments(size_t length)
- : length_(length),
- queue_(),
- sum_(0.0),
- sum_of_squares_(0.0) {
- assert(length > 0);
+ : length_(length), queue_(), sum_(0.0), sum_of_squares_(0.0) {
+ RTC_DCHECK_GT(length, 0);
for (size_t i = 0; i < length; ++i) {
queue_.push(0.0);
}
@@ -30,9 +26,14 @@ MovingMoments::MovingMoments(size_t length)
MovingMoments::~MovingMoments() {}
-void MovingMoments::CalculateMoments(const float* in, size_t in_length,
- float* first, float* second) {
- assert(in && in_length > 0 && first && second);
+void MovingMoments::CalculateMoments(const float* in,
+ size_t in_length,
+ float* first,
+ float* second) {
+ RTC_DCHECK(in);
+ RTC_DCHECK_GT(in_length, 0);
+ RTC_DCHECK(first);
+ RTC_DCHECK(second);
for (size_t i = 0; i < in_length; ++i) {
const float old_value = queue_.front();
@@ -42,7 +43,7 @@ void MovingMoments::CalculateMoments(const float* in, size_t in_length,
sum_ += in[i] - old_value;
sum_of_squares_ += in[i] * in[i] - old_value * old_value;
first[i] = sum_ / length_;
- second[i] = sum_of_squares_ / length_;
+ second[i] = std::max(0.f, sum_of_squares_ / length_);
}
}
diff --git a/webrtc/modules/audio_processing/transient/moving_moments.h b/webrtc/modules/audio_processing/transient/moving_moments.h
index 6e3ad5b..6dc0520 100644
--- a/webrtc/modules/audio_processing/transient/moving_moments.h
+++ b/webrtc/modules/audio_processing/transient/moving_moments.h
@@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
-#include <queue>
+#include <stddef.h>
-#include "webrtc/base/scoped_ptr.h"
+#include <queue>
namespace webrtc {
@@ -33,8 +33,10 @@ class MovingMoments {
// Calculates the new values using |in|. Results will be in the out buffers.
// |first| and |second| must be allocated with at least |in_length|.
- void CalculateMoments(const float* in, size_t in_length,
- float* first, float* second);
+ void CalculateMoments(const float* in,
+ size_t in_length,
+ float* first,
+ float* second);
private:
size_t length_;
@@ -48,5 +50,4 @@ class MovingMoments {
} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
diff --git a/webrtc/modules/audio_processing/transient/transient_detector.cc b/webrtc/modules/audio_processing/transient/transient_detector.cc
index 7f021ac..f03a2ea 100644
--- a/webrtc/modules/audio_processing/transient/transient_detector.cc
+++ b/webrtc/modules/audio_processing/transient/transient_detector.cc
@@ -8,17 +8,20 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/transient/transient_detector.h"
+#include "modules/audio_processing/transient/transient_detector.h"
-#include <assert.h>
#include <float.h>
-#include <math.h>
#include <string.h>
-#include "webrtc/modules/audio_processing/transient/common.h"
-#include "webrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h"
-#include "webrtc/modules/audio_processing/transient/moving_moments.h"
-#include "webrtc/modules/audio_processing/transient/wpd_tree.h"
+#include <algorithm>
+#include <cmath>
+
+#include "modules/audio_processing/transient/common.h"
+#include "modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h"
+#include "modules/audio_processing/transient/moving_moments.h"
+#include "modules/audio_processing/transient/wpd_node.h"
+#include "modules/audio_processing/transient/wpd_tree.h"
+#include "rtc_base/checks.h"
namespace webrtc {
@@ -34,10 +37,10 @@ TransientDetector::TransientDetector(int sample_rate_hz)
chunks_at_startup_left_to_delete_(kChunksAtStartupLeftToDelete),
reference_energy_(1.f),
using_reference_(false) {
- assert(sample_rate_hz == ts::kSampleRate8kHz ||
- sample_rate_hz == ts::kSampleRate16kHz ||
- sample_rate_hz == ts::kSampleRate32kHz ||
- sample_rate_hz == ts::kSampleRate48kHz);
+ RTC_DCHECK(sample_rate_hz == ts::kSampleRate8kHz ||
+ sample_rate_hz == ts::kSampleRate16kHz ||
+ sample_rate_hz == ts::kSampleRate32kHz ||
+ sample_rate_hz == ts::kSampleRate48kHz);
int samples_per_transient = sample_rate_hz * kTransientLengthMs / 1000;
// Adjustment to avoid data loss while downsampling, making
// |samples_per_chunk_| and |samples_per_transient| always divisible by
@@ -49,8 +52,7 @@ TransientDetector::TransientDetector(int sample_rate_hz)
wpd_tree_.reset(new WPDTree(samples_per_chunk_,
kDaubechies8HighPassCoefficients,
kDaubechies8LowPassCoefficients,
- kDaubechies8CoefficientsLength,
- kLevels));
+ kDaubechies8CoefficientsLength, kLevels));
for (size_t i = 0; i < kLeaves; ++i) {
moving_moments_[i].reset(
new MovingMoments(samples_per_transient / kLeaves));
@@ -70,7 +72,8 @@ float TransientDetector::Detect(const float* data,
size_t data_length,
const float* reference_data,
size_t reference_length) {
- assert(data && data_length == samples_per_chunk_);
+ RTC_DCHECK(data);
+ RTC_DCHECK_EQ(samples_per_chunk_, data_length);
// TODO(aluebs): Check if these errors can logically happen and if not assert
// on them.
@@ -83,8 +86,7 @@ float TransientDetector::Detect(const float* data,
for (size_t i = 0; i < kLeaves; ++i) {
WPDNode* leaf = wpd_tree_->NodeAt(kLevels, i);
- moving_moments_[i]->CalculateMoments(leaf->data(),
- tree_leaves_data_length_,
+ moving_moments_[i]->CalculateMoments(leaf->data(), tree_leaves_data_length_,
first_moments_.get(),
second_moments_.get());
@@ -124,8 +126,9 @@ float TransientDetector::Detect(const float* data,
const float kVerticalScaling = 0.5f;
const float kVerticalShift = 1.f;
- result = (cos(result * horizontal_scaling + kHorizontalShift)
- + kVerticalShift) * kVerticalScaling;
+ result = (std::cos(result * horizontal_scaling + kHorizontalShift) +
+ kVerticalShift) *
+ kVerticalScaling;
result *= result;
}
@@ -158,10 +161,10 @@ float TransientDetector::ReferenceDetectionValue(const float* data,
using_reference_ = false;
return 1.f;
}
- assert(reference_energy_ != 0);
- float result = 1.f / (1.f + exp(kReferenceNonLinearity *
- (kEnergyRatioThreshold -
- reference_energy / reference_energy_)));
+ RTC_DCHECK_NE(0, reference_energy_);
+ float result = 1.f / (1.f + std::exp(kReferenceNonLinearity *
+ (kEnergyRatioThreshold -
+ reference_energy / reference_energy_)));
reference_energy_ =
kMemory * reference_energy_ + (1.f - kMemory) * reference_energy;
diff --git a/webrtc/modules/audio_processing/transient/transient_detector.h b/webrtc/modules/audio_processing/transient/transient_detector.h
index 3f96582..5ede2e8 100644
--- a/webrtc/modules/audio_processing/transient/transient_detector.h
+++ b/webrtc/modules/audio_processing/transient/transient_detector.h
@@ -8,14 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
+
+#include <stddef.h>
#include <deque>
+#include <memory>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/transient/moving_moments.h"
-#include "webrtc/modules/audio_processing/transient/wpd_tree.h"
+#include "modules/audio_processing/transient/moving_moments.h"
+#include "modules/audio_processing/transient/wpd_tree.h"
namespace webrtc {
@@ -55,14 +57,14 @@ class TransientDetector {
size_t samples_per_chunk_;
- rtc::scoped_ptr<WPDTree> wpd_tree_;
+ std::unique_ptr<WPDTree> wpd_tree_;
size_t tree_leaves_data_length_;
// A MovingMoments object is needed for each leaf in the WPD tree.
- rtc::scoped_ptr<MovingMoments> moving_moments_[kLeaves];
+ std::unique_ptr<MovingMoments> moving_moments_[kLeaves];
- rtc::scoped_ptr<float[]> first_moments_;
- rtc::scoped_ptr<float[]> second_moments_;
+ std::unique_ptr<float[]> first_moments_;
+ std::unique_ptr<float[]> second_moments_;
// Stores the last calculated moments from the previous detection.
float last_first_moment_[kLeaves];
@@ -84,4 +86,4 @@ class TransientDetector {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
diff --git a/webrtc/modules/audio_processing/transient/transient_suppressor.h b/webrtc/modules/audio_processing/transient/transient_suppressor.h
index b62dcde..bb262b0 100644
--- a/webrtc/modules/audio_processing/transient/transient_suppressor.h
+++ b/webrtc/modules/audio_processing/transient/transient_suppressor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
@@ -8,30 +8,24 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
-#include <deque>
-#include <set>
-
-#include "webrtc/base/scoped_ptr.h"
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
-#include "webrtc/test/testsupport/gtest_prod_util.h"
-#endif
-#include "webrtc/typedefs.h"
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
namespace webrtc {
-class TransientDetector;
-
// Detects transients in an audio stream and suppress them using a simple
// restoration algorithm that attenuates unexpected spikes in the spectrum.
class TransientSuppressor {
public:
- TransientSuppressor();
- ~TransientSuppressor();
+ virtual ~TransientSuppressor() {}
- int Initialize(int sample_rate_hz, int detector_rate_hz, int num_channels);
+ virtual int Initialize(int sample_rate_hz,
+ int detector_rate_hz,
+ int num_channels) = 0;
// Processes a |data| chunk, and returns it with keystrokes suppressed from
// it. The float format is assumed to be int16 ranged. If there are more than
@@ -50,75 +44,17 @@ class TransientSuppressor {
// always be set to 1.
// |key_pressed| determines if a key was pressed on this audio chunk.
// Returns 0 on success and -1 otherwise.
- int Suppress(float* data,
- size_t data_length,
- int num_channels,
- const float* detection_data,
- size_t detection_length,
- const float* reference_data,
- size_t reference_length,
- float voice_probability,
- bool key_pressed);
-
- private:
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
- FRIEND_TEST_ALL_PREFIXES(TransientSuppressorTest,
- TypingDetectionLogicWorksAsExpectedForMono);
-#endif
- void Suppress(float* in_ptr, float* spectral_mean, float* out_ptr);
-
- void UpdateKeypress(bool key_pressed);
- void UpdateRestoration(float voice_probability);
-
- void UpdateBuffers(float* data);
-
- void HardRestoration(float* spectral_mean);
- void SoftRestoration(float* spectral_mean);
-
- rtc::scoped_ptr<TransientDetector> detector_;
-
- size_t data_length_;
- size_t detection_length_;
- size_t analysis_length_;
- size_t buffer_delay_;
- size_t complex_analysis_length_;
- int num_channels_;
- // Input buffer where the original samples are stored.
- rtc::scoped_ptr<float[]> in_buffer_;
- rtc::scoped_ptr<float[]> detection_buffer_;
- // Output buffer where the restored samples are stored.
- rtc::scoped_ptr<float[]> out_buffer_;
-
- // Arrays for fft.
- rtc::scoped_ptr<size_t[]> ip_;
- rtc::scoped_ptr<float[]> wfft_;
-
- rtc::scoped_ptr<float[]> spectral_mean_;
-
- // Stores the data for the fft.
- rtc::scoped_ptr<float[]> fft_buffer_;
-
- rtc::scoped_ptr<float[]> magnitudes_;
-
- const float* window_;
-
- rtc::scoped_ptr<float[]> mean_factor_;
-
- float detector_smoothed_;
-
- int keypress_counter_;
- int chunks_since_keypress_;
- bool detection_enabled_;
- bool suppression_enabled_;
-
- bool use_hard_restoration_;
- int chunks_since_voice_change_;
-
- uint32_t seed_;
-
- bool using_reference_;
+ virtual int Suppress(float* data,
+ size_t data_length,
+ int num_channels,
+ const float* detection_data,
+ size_t detection_length,
+ const float* reference_data,
+ size_t reference_length,
+ float voice_probability,
+ bool key_pressed) = 0;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
diff --git a/webrtc/modules/audio_processing/transient/transient_suppressor.cc b/webrtc/modules/audio_processing/transient/transient_suppressor_impl.cc
index c8d9e65..d515d30 100644
--- a/webrtc/modules/audio_processing/transient/transient_suppressor.cc
+++ b/webrtc/modules/audio_processing/transient/transient_suppressor_impl.cc
@@ -8,24 +8,26 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/transient/transient_suppressor.h"
+#include "modules/audio_processing/transient/transient_suppressor_impl.h"
-#include <math.h>
#include <string.h>
+
+#include <algorithm>
#include <cmath>
#include <complex>
#include <deque>
+#include <limits>
#include <set>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/fft4g.h"
-#include "webrtc/common_audio/include/audio_util.h"
-#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
-#include "webrtc/modules/audio_processing/transient/common.h"
-#include "webrtc/modules/audio_processing/transient/transient_detector.h"
-#include "webrtc/modules/audio_processing/ns/windows_private.h"
-#include "webrtc/system_wrappers/include/logging.h"
-#include "webrtc/typedefs.h"
+#include "common_audio/include/audio_util.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
+#include "modules/audio_processing/transient/common.h"
+#include "modules/audio_processing/transient/transient_detector.h"
+#include "modules/audio_processing/transient/transient_suppressor.h"
+#include "modules/audio_processing/transient/windows_private.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
namespace webrtc {
@@ -44,7 +46,7 @@ float ComplexMagnitude(float a, float b) {
} // namespace
-TransientSuppressor::TransientSuppressor()
+TransientSuppressorImpl::TransientSuppressorImpl()
: data_length_(0),
detection_length_(0),
analysis_length_(0),
@@ -60,14 +62,13 @@ TransientSuppressor::TransientSuppressor()
use_hard_restoration_(false),
chunks_since_voice_change_(0),
seed_(182),
- using_reference_(false) {
-}
+ using_reference_(false) {}
-TransientSuppressor::~TransientSuppressor() {}
+TransientSuppressorImpl::~TransientSuppressorImpl() {}
-int TransientSuppressor::Initialize(int sample_rate_hz,
- int detection_rate_hz,
- int num_channels) {
+int TransientSuppressorImpl::Initialize(int sample_rate_hz,
+ int detection_rate_hz,
+ int num_channels) {
switch (sample_rate_hz) {
case ts::kSampleRate8kHz:
analysis_length_ = 128u;
@@ -101,26 +102,23 @@ int TransientSuppressor::Initialize(int sample_rate_hz,
detector_.reset(new TransientDetector(detection_rate_hz));
data_length_ = sample_rate_hz * ts::kChunkSizeMs / 1000;
if (data_length_ > analysis_length_) {
- assert(false);
+ RTC_NOTREACHED();
return -1;
}
buffer_delay_ = analysis_length_ - data_length_;
complex_analysis_length_ = analysis_length_ / 2 + 1;
- assert(complex_analysis_length_ >= kMaxVoiceBin);
+ RTC_DCHECK_GE(complex_analysis_length_, kMaxVoiceBin);
num_channels_ = num_channels;
in_buffer_.reset(new float[analysis_length_ * num_channels_]);
- memset(in_buffer_.get(),
- 0,
+ memset(in_buffer_.get(), 0,
analysis_length_ * num_channels_ * sizeof(in_buffer_[0]));
detection_length_ = detection_rate_hz * ts::kChunkSizeMs / 1000;
detection_buffer_.reset(new float[detection_length_]);
- memset(detection_buffer_.get(),
- 0,
+ memset(detection_buffer_.get(), 0,
detection_length_ * sizeof(detection_buffer_[0]));
out_buffer_.reset(new float[analysis_length_ * num_channels_]);
- memset(out_buffer_.get(),
- 0,
+ memset(out_buffer_.get(), 0,
analysis_length_ * num_channels_ * sizeof(out_buffer_[0]));
// ip[0] must be zero to trigger initialization using rdft().
size_t ip_length = 2 + sqrtf(analysis_length_);
@@ -129,14 +127,12 @@ int TransientSuppressor::Initialize(int sample_rate_hz,
wfft_.reset(new float[complex_analysis_length_ - 1]);
memset(wfft_.get(), 0, (complex_analysis_length_ - 1) * sizeof(wfft_[0]));
spectral_mean_.reset(new float[complex_analysis_length_ * num_channels_]);
- memset(spectral_mean_.get(),
- 0,
+ memset(spectral_mean_.get(), 0,
complex_analysis_length_ * num_channels_ * sizeof(spectral_mean_[0]));
fft_buffer_.reset(new float[analysis_length_ + 2]);
memset(fft_buffer_.get(), 0, (analysis_length_ + 2) * sizeof(fft_buffer_[0]));
magnitudes_.reset(new float[complex_analysis_length_]);
- memset(magnitudes_.get(),
- 0,
+ memset(magnitudes_.get(), 0,
complex_analysis_length_ * sizeof(magnitudes_[0]));
mean_factor_.reset(new float[complex_analysis_length_]);
@@ -146,9 +142,9 @@ int TransientSuppressor::Initialize(int sample_rate_hz,
for (size_t i = 0; i < complex_analysis_length_; ++i) {
mean_factor_[i] =
kFactorHeight /
- (1.f + exp(kLowSlope * static_cast<int>(i - kMinVoiceBin))) +
+ (1.f + std::exp(kLowSlope * static_cast<int>(i - kMinVoiceBin))) +
kFactorHeight /
- (1.f + exp(kHighSlope * static_cast<int>(kMaxVoiceBin - i)));
+ (1.f + std::exp(kHighSlope * static_cast<int>(kMaxVoiceBin - i)));
}
detector_smoothed_ = 0.f;
keypress_counter_ = 0;
@@ -162,15 +158,15 @@ int TransientSuppressor::Initialize(int sample_rate_hz,
return 0;
}
-int TransientSuppressor::Suppress(float* data,
- size_t data_length,
- int num_channels,
- const float* detection_data,
- size_t detection_length,
- const float* reference_data,
- size_t reference_length,
- float voice_probability,
- bool key_pressed) {
+int TransientSuppressorImpl::Suppress(float* data,
+ size_t data_length,
+ int num_channels,
+ const float* detection_data,
+ size_t detection_length,
+ const float* reference_data,
+ size_t reference_length,
+ float voice_probability,
+ bool key_pressed) {
if (!data || data_length != data_length_ || num_channels != num_channels_ ||
detection_length != detection_length_ || voice_probability < 0 ||
voice_probability > 1) {
@@ -190,8 +186,8 @@ int TransientSuppressor::Suppress(float* data,
detection_data = &in_buffer_[buffer_delay_];
}
- float detector_result = detector_->Detect(
- detection_data, detection_length, reference_data, reference_length);
+ float detector_result = detector_->Detect(detection_data, detection_length,
+ reference_data, reference_length);
if (detector_result < 0) {
return -1;
}
@@ -229,9 +225,9 @@ int TransientSuppressor::Suppress(float* data,
// This should only be called when detection is enabled. UpdateBuffers() must
// have been called. At return, |out_buffer_| will be filled with the
// processed output.
-void TransientSuppressor::Suppress(float* in_ptr,
- float* spectral_mean,
- float* out_ptr) {
+void TransientSuppressorImpl::Suppress(float* in_ptr,
+ float* spectral_mean,
+ float* out_ptr) {
// Go to frequency domain.
for (size_t i = 0; i < analysis_length_; ++i) {
// TODO(aluebs): Rename windows
@@ -247,8 +243,8 @@ void TransientSuppressor::Suppress(float* in_ptr,
fft_buffer_[1] = 0.f;
for (size_t i = 0; i < complex_analysis_length_; ++i) {
- magnitudes_[i] = ComplexMagnitude(fft_buffer_[i * 2],
- fft_buffer_[i * 2 + 1]);
+ magnitudes_[i] =
+ ComplexMagnitude(fft_buffer_[i * 2], fft_buffer_[i * 2 + 1]);
}
// Restore audio if necessary.
if (suppression_enabled_) {
@@ -269,11 +265,7 @@ void TransientSuppressor::Suppress(float* in_ptr,
// Put R[n/2] back in fft_buffer_[1].
fft_buffer_[1] = fft_buffer_[analysis_length_];
- WebRtc_rdft(analysis_length_,
- -1,
- fft_buffer_.get(),
- ip_.get(),
- wfft_.get());
+ WebRtc_rdft(analysis_length_, -1, fft_buffer_.get(), ip_.get(), wfft_.get());
const float fft_scaling = 2.f / analysis_length_;
for (size_t i = 0; i < analysis_length_; ++i) {
@@ -281,7 +273,7 @@ void TransientSuppressor::Suppress(float* in_ptr,
}
}
-void TransientSuppressor::UpdateKeypress(bool key_pressed) {
+void TransientSuppressorImpl::UpdateKeypress(bool key_pressed) {
const int kKeypressPenalty = 1000 / ts::kChunkSizeMs;
const int kIsTypingThreshold = 1000 / ts::kChunkSizeMs;
const int kChunksUntilNotTyping = 4000 / ts::kChunkSizeMs; // 4 seconds.
@@ -295,16 +287,15 @@ void TransientSuppressor::UpdateKeypress(bool key_pressed) {
if (keypress_counter_ > kIsTypingThreshold) {
if (!suppression_enabled_) {
- LOG(LS_INFO) << "[ts] Transient suppression is now enabled.";
+ RTC_LOG(LS_INFO) << "[ts] Transient suppression is now enabled.";
}
suppression_enabled_ = true;
keypress_counter_ = 0;
}
- if (detection_enabled_ &&
- ++chunks_since_keypress_ > kChunksUntilNotTyping) {
+ if (detection_enabled_ && ++chunks_since_keypress_ > kChunksUntilNotTyping) {
if (suppression_enabled_) {
- LOG(LS_INFO) << "[ts] Transient suppression is now disabled.";
+ RTC_LOG(LS_INFO) << "[ts] Transient suppression is now disabled.";
}
detection_enabled_ = false;
suppression_enabled_ = false;
@@ -312,7 +303,7 @@ void TransientSuppressor::UpdateKeypress(bool key_pressed) {
}
}
-void TransientSuppressor::UpdateRestoration(float voice_probability) {
+void TransientSuppressorImpl::UpdateRestoration(float voice_probability) {
const int kHardRestorationOffsetDelay = 3;
const int kHardRestorationOnsetDelay = 80;
@@ -335,28 +326,24 @@ void TransientSuppressor::UpdateRestoration(float voice_probability) {
// Shift buffers to make way for new data. Must be called after
// |detection_enabled_| is updated by UpdateKeypress().
-void TransientSuppressor::UpdateBuffers(float* data) {
+void TransientSuppressorImpl::UpdateBuffers(float* data) {
// TODO(aluebs): Change to ring buffer.
- memmove(in_buffer_.get(),
- &in_buffer_[data_length_],
+ memmove(in_buffer_.get(), &in_buffer_[data_length_],
(buffer_delay_ + (num_channels_ - 1) * analysis_length_) *
sizeof(in_buffer_[0]));
// Copy new chunk to buffer.
for (int i = 0; i < num_channels_; ++i) {
memcpy(&in_buffer_[buffer_delay_ + i * analysis_length_],
- &data[i * data_length_],
- data_length_ * sizeof(*data));
+ &data[i * data_length_], data_length_ * sizeof(*data));
}
if (detection_enabled_) {
// Shift previous chunk in out buffer.
- memmove(out_buffer_.get(),
- &out_buffer_[data_length_],
+ memmove(out_buffer_.get(), &out_buffer_[data_length_],
(buffer_delay_ + (num_channels_ - 1) * analysis_length_) *
sizeof(out_buffer_[0]));
// Initialize new chunk in out buffer.
for (int i = 0; i < num_channels_; ++i) {
- memset(&out_buffer_[buffer_delay_ + i * analysis_length_],
- 0,
+ memset(&out_buffer_[buffer_delay_ + i * analysis_length_], 0,
data_length_ * sizeof(out_buffer_[0]));
}
}
@@ -366,16 +353,16 @@ void TransientSuppressor::UpdateBuffers(float* data) {
// Attenuates by a certain factor every peak in the |fft_buffer_| that exceeds
// the spectral mean. The attenuation depends on |detector_smoothed_|.
// If a restoration takes place, the |magnitudes_| are updated to the new value.
-void TransientSuppressor::HardRestoration(float* spectral_mean) {
+void TransientSuppressorImpl::HardRestoration(float* spectral_mean) {
const float detector_result =
- 1.f - pow(1.f - detector_smoothed_, using_reference_ ? 200.f : 50.f);
+ 1.f - std::pow(1.f - detector_smoothed_, using_reference_ ? 200.f : 50.f);
// To restore, we get the peaks in the spectrum. If higher than the previous
// spectral mean we adjust them.
for (size_t i = 0; i < complex_analysis_length_; ++i) {
if (magnitudes_[i] > spectral_mean[i] && magnitudes_[i] > 0) {
// RandU() generates values on [0, int16::max()]
const float phase = 2 * ts::kPi * WebRtcSpl_RandU(&seed_) /
- std::numeric_limits<int16_t>::max();
+ std::numeric_limits<int16_t>::max();
const float scaled_mean = detector_result * spectral_mean[i];
fft_buffer_[i * 2] = (1 - detector_result) * fft_buffer_[i * 2] +
@@ -393,7 +380,7 @@ void TransientSuppressor::HardRestoration(float* spectral_mean) {
// the spectral mean and that is lower than some function of the current block
// frequency mean. The attenuation depends on |detector_smoothed_|.
// If a restoration takes place, the |magnitudes_| are updated to the new value.
-void TransientSuppressor::SoftRestoration(float* spectral_mean) {
+void TransientSuppressorImpl::SoftRestoration(float* spectral_mean) {
// Get the spectral magnitude mean of the current block.
float block_frequency_mean = 0;
for (size_t i = kMinVoiceBin; i < kMaxVoiceBin; ++i) {
diff --git a/webrtc/modules/audio_processing/transient/transient_suppressor_impl.h b/webrtc/modules/audio_processing/transient/transient_suppressor_impl.h
new file mode 100644
index 0000000..4737af5
--- /dev/null
+++ b/webrtc/modules/audio_processing/transient/transient_suppressor_impl.h
@@ -0,0 +1,123 @@
+/*
+ * 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_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "modules/audio_processing/transient/transient_suppressor.h"
+#include "rtc_base/gtest_prod_util.h"
+
+namespace webrtc {
+
+class TransientDetector;
+
+// Detects transients in an audio stream and suppress them using a simple
+// restoration algorithm that attenuates unexpected spikes in the spectrum.
+class TransientSuppressorImpl : public TransientSuppressor {
+ public:
+ TransientSuppressorImpl();
+ ~TransientSuppressorImpl() override;
+
+ int Initialize(int sample_rate_hz,
+ int detector_rate_hz,
+ int num_channels) override;
+
+ // Processes a |data| chunk, and returns it with keystrokes suppressed from
+ // it. The float format is assumed to be int16 ranged. If there are more than
+ // one channel, the chunks are concatenated one after the other in |data|.
+ // |data_length| must be equal to |data_length_|.
+ // |num_channels| must be equal to |num_channels_|.
+ // A sub-band, ideally the higher, can be used as |detection_data|. If it is
+ // NULL, |data| is used for the detection too. The |detection_data| is always
+ // assumed mono.
+ // If a reference signal (e.g. keyboard microphone) is available, it can be
+ // passed in as |reference_data|. It is assumed mono and must have the same
+ // length as |data|. NULL is accepted if unavailable.
+ // This suppressor performs better if voice information is available.
+ // |voice_probability| is the probability of voice being present in this chunk
+ // of audio. If voice information is not available, |voice_probability| must
+ // always be set to 1.
+ // |key_pressed| determines if a key was pressed on this audio chunk.
+ // Returns 0 on success and -1 otherwise.
+ int Suppress(float* data,
+ size_t data_length,
+ int num_channels,
+ const float* detection_data,
+ size_t detection_length,
+ const float* reference_data,
+ size_t reference_length,
+ float voice_probability,
+ bool key_pressed) override;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(TransientSuppressorImplTest,
+ TypingDetectionLogicWorksAsExpectedForMono);
+ void Suppress(float* in_ptr, float* spectral_mean, float* out_ptr);
+
+ void UpdateKeypress(bool key_pressed);
+ void UpdateRestoration(float voice_probability);
+
+ void UpdateBuffers(float* data);
+
+ void HardRestoration(float* spectral_mean);
+ void SoftRestoration(float* spectral_mean);
+
+ std::unique_ptr<TransientDetector> detector_;
+
+ size_t data_length_;
+ size_t detection_length_;
+ size_t analysis_length_;
+ size_t buffer_delay_;
+ size_t complex_analysis_length_;
+ int num_channels_;
+ // Input buffer where the original samples are stored.
+ std::unique_ptr<float[]> in_buffer_;
+ std::unique_ptr<float[]> detection_buffer_;
+ // Output buffer where the restored samples are stored.
+ std::unique_ptr<float[]> out_buffer_;
+
+ // Arrays for fft.
+ std::unique_ptr<size_t[]> ip_;
+ std::unique_ptr<float[]> wfft_;
+
+ std::unique_ptr<float[]> spectral_mean_;
+
+ // Stores the data for the fft.
+ std::unique_ptr<float[]> fft_buffer_;
+
+ std::unique_ptr<float[]> magnitudes_;
+
+ const float* window_;
+
+ std::unique_ptr<float[]> mean_factor_;
+
+ float detector_smoothed_;
+
+ int keypress_counter_;
+ int chunks_since_keypress_;
+ bool detection_enabled_;
+ bool suppression_enabled_;
+
+ bool use_hard_restoration_;
+ int chunks_since_voice_change_;
+
+ uint32_t seed_;
+
+ bool using_reference_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_
diff --git a/webrtc/modules/audio_processing/transient/windows_private.h b/webrtc/modules/audio_processing/transient/windows_private.h
new file mode 100644
index 0000000..54e3c25
--- /dev/null
+++ b/webrtc/modules/audio_processing/transient/windows_private.h
@@ -0,0 +1,557 @@
+/*
+ * 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_AUDIO_PROCESSING_TRANSIENT_WINDOWS_PRIVATE_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_WINDOWS_PRIVATE_H_
+
+namespace webrtc {
+
+// Hanning window for 4ms 16kHz
+static const float kHanning64w128[128] = {
+ 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
+ 0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
+ 0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
+ 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
+ 0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
+ 0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
+ 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
+ 0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
+ 0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
+ 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
+ 0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
+ 0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
+ 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
+ 0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
+ 0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
+ 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
+ 1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
+ 0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f,
+ 0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f,
+ 0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
+ 0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f,
+ 0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f,
+ 0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
+ 0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f,
+ 0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f,
+ 0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
+ 0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f,
+ 0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f,
+ 0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
+ 0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f,
+ 0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f,
+ 0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f};
+
+// hybrib Hanning & flat window
+static const float kBlocks80w128[128] = {
+ 0.00000000f, 0.03271908f, 0.06540313f, 0.09801714f, 0.13052619f,
+ 0.16289547f, 0.19509032f, 0.22707626f, 0.25881905f, 0.29028468f,
+ 0.32143947f, 0.35225005f, 0.38268343f, 0.41270703f, 0.44228869f,
+ 0.47139674f, 0.50000000f, 0.52806785f, 0.55557023f, 0.58247770f,
+ 0.60876143f, 0.63439328f, 0.65934582f, 0.68359230f, 0.70710678f,
+ 0.72986407f, 0.75183981f, 0.77301045f, 0.79335334f, 0.81284668f,
+ 0.83146961f, 0.84920218f, 0.86602540f, 0.88192126f, 0.89687274f,
+ 0.91086382f, 0.92387953f, 0.93590593f, 0.94693013f, 0.95694034f,
+ 0.96592583f, 0.97387698f, 0.98078528f, 0.98664333f, 0.99144486f,
+ 0.99518473f, 0.99785892f, 0.99946459f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 0.99946459f, 0.99785892f, 0.99518473f, 0.99144486f,
+ 0.98664333f, 0.98078528f, 0.97387698f, 0.96592583f, 0.95694034f,
+ 0.94693013f, 0.93590593f, 0.92387953f, 0.91086382f, 0.89687274f,
+ 0.88192126f, 0.86602540f, 0.84920218f, 0.83146961f, 0.81284668f,
+ 0.79335334f, 0.77301045f, 0.75183981f, 0.72986407f, 0.70710678f,
+ 0.68359230f, 0.65934582f, 0.63439328f, 0.60876143f, 0.58247770f,
+ 0.55557023f, 0.52806785f, 0.50000000f, 0.47139674f, 0.44228869f,
+ 0.41270703f, 0.38268343f, 0.35225005f, 0.32143947f, 0.29028468f,
+ 0.25881905f, 0.22707626f, 0.19509032f, 0.16289547f, 0.13052619f,
+ 0.09801714f, 0.06540313f, 0.03271908f};
+
+// hybrib Hanning & flat window
+static const float kBlocks160w256[256] = {
+ 0.00000000f, 0.01636173f, 0.03271908f, 0.04906767f, 0.06540313f,
+ 0.08172107f, 0.09801714f, 0.11428696f, 0.13052619f, 0.14673047f,
+ 0.16289547f, 0.17901686f, 0.19509032f, 0.21111155f, 0.22707626f,
+ 0.24298018f, 0.25881905f, 0.27458862f, 0.29028468f, 0.30590302f,
+ 0.32143947f, 0.33688985f, 0.35225005f, 0.36751594f, 0.38268343f,
+ 0.39774847f, 0.41270703f, 0.42755509f, 0.44228869f, 0.45690388f,
+ 0.47139674f, 0.48576339f, 0.50000000f, 0.51410274f, 0.52806785f,
+ 0.54189158f, 0.55557023f, 0.56910015f, 0.58247770f, 0.59569930f,
+ 0.60876143f, 0.62166057f, 0.63439328f, 0.64695615f, 0.65934582f,
+ 0.67155895f, 0.68359230f, 0.69544264f, 0.70710678f, 0.71858162f,
+ 0.72986407f, 0.74095113f, 0.75183981f, 0.76252720f, 0.77301045f,
+ 0.78328675f, 0.79335334f, 0.80320753f, 0.81284668f, 0.82226822f,
+ 0.83146961f, 0.84044840f, 0.84920218f, 0.85772861f, 0.86602540f,
+ 0.87409034f, 0.88192126f, 0.88951608f, 0.89687274f, 0.90398929f,
+ 0.91086382f, 0.91749450f, 0.92387953f, 0.93001722f, 0.93590593f,
+ 0.94154407f, 0.94693013f, 0.95206268f, 0.95694034f, 0.96156180f,
+ 0.96592583f, 0.97003125f, 0.97387698f, 0.97746197f, 0.98078528f,
+ 0.98384601f, 0.98664333f, 0.98917651f, 0.99144486f, 0.99344778f,
+ 0.99518473f, 0.99665524f, 0.99785892f, 0.99879546f, 0.99946459f,
+ 0.99986614f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 0.99986614f, 0.99946459f, 0.99879546f, 0.99785892f,
+ 0.99665524f, 0.99518473f, 0.99344778f, 0.99144486f, 0.98917651f,
+ 0.98664333f, 0.98384601f, 0.98078528f, 0.97746197f, 0.97387698f,
+ 0.97003125f, 0.96592583f, 0.96156180f, 0.95694034f, 0.95206268f,
+ 0.94693013f, 0.94154407f, 0.93590593f, 0.93001722f, 0.92387953f,
+ 0.91749450f, 0.91086382f, 0.90398929f, 0.89687274f, 0.88951608f,
+ 0.88192126f, 0.87409034f, 0.86602540f, 0.85772861f, 0.84920218f,
+ 0.84044840f, 0.83146961f, 0.82226822f, 0.81284668f, 0.80320753f,
+ 0.79335334f, 0.78328675f, 0.77301045f, 0.76252720f, 0.75183981f,
+ 0.74095113f, 0.72986407f, 0.71858162f, 0.70710678f, 0.69544264f,
+ 0.68359230f, 0.67155895f, 0.65934582f, 0.64695615f, 0.63439328f,
+ 0.62166057f, 0.60876143f, 0.59569930f, 0.58247770f, 0.56910015f,
+ 0.55557023f, 0.54189158f, 0.52806785f, 0.51410274f, 0.50000000f,
+ 0.48576339f, 0.47139674f, 0.45690388f, 0.44228869f, 0.42755509f,
+ 0.41270703f, 0.39774847f, 0.38268343f, 0.36751594f, 0.35225005f,
+ 0.33688985f, 0.32143947f, 0.30590302f, 0.29028468f, 0.27458862f,
+ 0.25881905f, 0.24298018f, 0.22707626f, 0.21111155f, 0.19509032f,
+ 0.17901686f, 0.16289547f, 0.14673047f, 0.13052619f, 0.11428696f,
+ 0.09801714f, 0.08172107f, 0.06540313f, 0.04906767f, 0.03271908f,
+ 0.01636173f};
+
+// hybrib Hanning & flat window: for 20ms
+static const float kBlocks320w512[512] = {
+ 0.00000000f, 0.00818114f, 0.01636173f, 0.02454123f, 0.03271908f,
+ 0.04089475f, 0.04906767f, 0.05723732f, 0.06540313f, 0.07356456f,
+ 0.08172107f, 0.08987211f, 0.09801714f, 0.10615561f, 0.11428696f,
+ 0.12241068f, 0.13052619f, 0.13863297f, 0.14673047f, 0.15481816f,
+ 0.16289547f, 0.17096189f, 0.17901686f, 0.18705985f, 0.19509032f,
+ 0.20310773f, 0.21111155f, 0.21910124f, 0.22707626f, 0.23503609f,
+ 0.24298018f, 0.25090801f, 0.25881905f, 0.26671276f, 0.27458862f,
+ 0.28244610f, 0.29028468f, 0.29810383f, 0.30590302f, 0.31368174f,
+ 0.32143947f, 0.32917568f, 0.33688985f, 0.34458148f, 0.35225005f,
+ 0.35989504f, 0.36751594f, 0.37511224f, 0.38268343f, 0.39022901f,
+ 0.39774847f, 0.40524131f, 0.41270703f, 0.42014512f, 0.42755509f,
+ 0.43493645f, 0.44228869f, 0.44961133f, 0.45690388f, 0.46416584f,
+ 0.47139674f, 0.47859608f, 0.48576339f, 0.49289819f, 0.50000000f,
+ 0.50706834f, 0.51410274f, 0.52110274f, 0.52806785f, 0.53499762f,
+ 0.54189158f, 0.54874927f, 0.55557023f, 0.56235401f, 0.56910015f,
+ 0.57580819f, 0.58247770f, 0.58910822f, 0.59569930f, 0.60225052f,
+ 0.60876143f, 0.61523159f, 0.62166057f, 0.62804795f, 0.63439328f,
+ 0.64069616f, 0.64695615f, 0.65317284f, 0.65934582f, 0.66547466f,
+ 0.67155895f, 0.67759830f, 0.68359230f, 0.68954054f, 0.69544264f,
+ 0.70129818f, 0.70710678f, 0.71286806f, 0.71858162f, 0.72424708f,
+ 0.72986407f, 0.73543221f, 0.74095113f, 0.74642045f, 0.75183981f,
+ 0.75720885f, 0.76252720f, 0.76779452f, 0.77301045f, 0.77817464f,
+ 0.78328675f, 0.78834643f, 0.79335334f, 0.79830715f, 0.80320753f,
+ 0.80805415f, 0.81284668f, 0.81758481f, 0.82226822f, 0.82689659f,
+ 0.83146961f, 0.83598698f, 0.84044840f, 0.84485357f, 0.84920218f,
+ 0.85349396f, 0.85772861f, 0.86190585f, 0.86602540f, 0.87008699f,
+ 0.87409034f, 0.87803519f, 0.88192126f, 0.88574831f, 0.88951608f,
+ 0.89322430f, 0.89687274f, 0.90046115f, 0.90398929f, 0.90745693f,
+ 0.91086382f, 0.91420976f, 0.91749450f, 0.92071783f, 0.92387953f,
+ 0.92697940f, 0.93001722f, 0.93299280f, 0.93590593f, 0.93875641f,
+ 0.94154407f, 0.94426870f, 0.94693013f, 0.94952818f, 0.95206268f,
+ 0.95453345f, 0.95694034f, 0.95928317f, 0.96156180f, 0.96377607f,
+ 0.96592583f, 0.96801094f, 0.97003125f, 0.97198664f, 0.97387698f,
+ 0.97570213f, 0.97746197f, 0.97915640f, 0.98078528f, 0.98234852f,
+ 0.98384601f, 0.98527764f, 0.98664333f, 0.98794298f, 0.98917651f,
+ 0.99034383f, 0.99144486f, 0.99247953f, 0.99344778f, 0.99434953f,
+ 0.99518473f, 0.99595331f, 0.99665524f, 0.99729046f, 0.99785892f,
+ 0.99836060f, 0.99879546f, 0.99916346f, 0.99946459f, 0.99969882f,
+ 0.99986614f, 0.99996653f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+ 1.00000000f, 0.99996653f, 0.99986614f, 0.99969882f, 0.99946459f,
+ 0.99916346f, 0.99879546f, 0.99836060f, 0.99785892f, 0.99729046f,
+ 0.99665524f, 0.99595331f, 0.99518473f, 0.99434953f, 0.99344778f,
+ 0.99247953f, 0.99144486f, 0.99034383f, 0.98917651f, 0.98794298f,
+ 0.98664333f, 0.98527764f, 0.98384601f, 0.98234852f, 0.98078528f,
+ 0.97915640f, 0.97746197f, 0.97570213f, 0.97387698f, 0.97198664f,
+ 0.97003125f, 0.96801094f, 0.96592583f, 0.96377607f, 0.96156180f,
+ 0.95928317f, 0.95694034f, 0.95453345f, 0.95206268f, 0.94952818f,
+ 0.94693013f, 0.94426870f, 0.94154407f, 0.93875641f, 0.93590593f,
+ 0.93299280f, 0.93001722f, 0.92697940f, 0.92387953f, 0.92071783f,
+ 0.91749450f, 0.91420976f, 0.91086382f, 0.90745693f, 0.90398929f,
+ 0.90046115f, 0.89687274f, 0.89322430f, 0.88951608f, 0.88574831f,
+ 0.88192126f, 0.87803519f, 0.87409034f, 0.87008699f, 0.86602540f,
+ 0.86190585f, 0.85772861f, 0.85349396f, 0.84920218f, 0.84485357f,
+ 0.84044840f, 0.83598698f, 0.83146961f, 0.82689659f, 0.82226822f,
+ 0.81758481f, 0.81284668f, 0.80805415f, 0.80320753f, 0.79830715f,
+ 0.79335334f, 0.78834643f, 0.78328675f, 0.77817464f, 0.77301045f,
+ 0.76779452f, 0.76252720f, 0.75720885f, 0.75183981f, 0.74642045f,
+ 0.74095113f, 0.73543221f, 0.72986407f, 0.72424708f, 0.71858162f,
+ 0.71286806f, 0.70710678f, 0.70129818f, 0.69544264f, 0.68954054f,
+ 0.68359230f, 0.67759830f, 0.67155895f, 0.66547466f, 0.65934582f,
+ 0.65317284f, 0.64695615f, 0.64069616f, 0.63439328f, 0.62804795f,
+ 0.62166057f, 0.61523159f, 0.60876143f, 0.60225052f, 0.59569930f,
+ 0.58910822f, 0.58247770f, 0.57580819f, 0.56910015f, 0.56235401f,
+ 0.55557023f, 0.54874927f, 0.54189158f, 0.53499762f, 0.52806785f,
+ 0.52110274f, 0.51410274f, 0.50706834f, 0.50000000f, 0.49289819f,
+ 0.48576339f, 0.47859608f, 0.47139674f, 0.46416584f, 0.45690388f,
+ 0.44961133f, 0.44228869f, 0.43493645f, 0.42755509f, 0.42014512f,
+ 0.41270703f, 0.40524131f, 0.39774847f, 0.39022901f, 0.38268343f,
+ 0.37511224f, 0.36751594f, 0.35989504f, 0.35225005f, 0.34458148f,
+ 0.33688985f, 0.32917568f, 0.32143947f, 0.31368174f, 0.30590302f,
+ 0.29810383f, 0.29028468f, 0.28244610f, 0.27458862f, 0.26671276f,
+ 0.25881905f, 0.25090801f, 0.24298018f, 0.23503609f, 0.22707626f,
+ 0.21910124f, 0.21111155f, 0.20310773f, 0.19509032f, 0.18705985f,
+ 0.17901686f, 0.17096189f, 0.16289547f, 0.15481816f, 0.14673047f,
+ 0.13863297f, 0.13052619f, 0.12241068f, 0.11428696f, 0.10615561f,
+ 0.09801714f, 0.08987211f, 0.08172107f, 0.07356456f, 0.06540313f,
+ 0.05723732f, 0.04906767f, 0.04089475f, 0.03271908f, 0.02454123f,
+ 0.01636173f, 0.00818114f};
+
+// Hanning window: for 15ms at 16kHz with symmetric zeros
+static const float kBlocks240w512[512] = {
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00654494f, 0.01308960f, 0.01963369f,
+ 0.02617695f, 0.03271908f, 0.03925982f, 0.04579887f, 0.05233596f,
+ 0.05887080f, 0.06540313f, 0.07193266f, 0.07845910f, 0.08498218f,
+ 0.09150162f, 0.09801714f, 0.10452846f, 0.11103531f, 0.11753740f,
+ 0.12403446f, 0.13052620f, 0.13701233f, 0.14349262f, 0.14996676f,
+ 0.15643448f, 0.16289547f, 0.16934951f, 0.17579629f, 0.18223552f,
+ 0.18866697f, 0.19509032f, 0.20150533f, 0.20791170f, 0.21430916f,
+ 0.22069745f, 0.22707628f, 0.23344538f, 0.23980446f, 0.24615330f,
+ 0.25249159f, 0.25881904f, 0.26513544f, 0.27144045f, 0.27773386f,
+ 0.28401536f, 0.29028466f, 0.29654160f, 0.30278578f, 0.30901700f,
+ 0.31523499f, 0.32143945f, 0.32763019f, 0.33380687f, 0.33996925f,
+ 0.34611708f, 0.35225007f, 0.35836795f, 0.36447051f, 0.37055743f,
+ 0.37662852f, 0.38268346f, 0.38872197f, 0.39474389f, 0.40074885f,
+ 0.40673664f, 0.41270703f, 0.41865975f, 0.42459452f, 0.43051112f,
+ 0.43640924f, 0.44228873f, 0.44814920f, 0.45399052f, 0.45981237f,
+ 0.46561453f, 0.47139674f, 0.47715878f, 0.48290035f, 0.48862126f,
+ 0.49432120f, 0.50000000f, 0.50565743f, 0.51129311f, 0.51690692f,
+ 0.52249855f, 0.52806789f, 0.53361452f, 0.53913832f, 0.54463905f,
+ 0.55011642f, 0.55557024f, 0.56100029f, 0.56640625f, 0.57178795f,
+ 0.57714522f, 0.58247769f, 0.58778524f, 0.59306765f, 0.59832460f,
+ 0.60355598f, 0.60876143f, 0.61394083f, 0.61909395f, 0.62422055f,
+ 0.62932038f, 0.63439333f, 0.63943899f, 0.64445734f, 0.64944810f,
+ 0.65441096f, 0.65934587f, 0.66425246f, 0.66913062f, 0.67398012f,
+ 0.67880076f, 0.68359232f, 0.68835455f, 0.69308740f, 0.69779050f,
+ 0.70246369f, 0.70710677f, 0.71171963f, 0.71630198f, 0.72085363f,
+ 0.72537440f, 0.72986406f, 0.73432255f, 0.73874950f, 0.74314487f,
+ 0.74750835f, 0.75183982f, 0.75613910f, 0.76040596f, 0.76464027f,
+ 0.76884186f, 0.77301043f, 0.77714598f, 0.78124821f, 0.78531694f,
+ 0.78935206f, 0.79335338f, 0.79732066f, 0.80125386f, 0.80515265f,
+ 0.80901700f, 0.81284672f, 0.81664157f, 0.82040149f, 0.82412618f,
+ 0.82781565f, 0.83146966f, 0.83508795f, 0.83867061f, 0.84221727f,
+ 0.84572780f, 0.84920216f, 0.85264021f, 0.85604161f, 0.85940641f,
+ 0.86273444f, 0.86602545f, 0.86927933f, 0.87249607f, 0.87567532f,
+ 0.87881714f, 0.88192129f, 0.88498765f, 0.88801610f, 0.89100653f,
+ 0.89395881f, 0.89687276f, 0.89974827f, 0.90258533f, 0.90538365f,
+ 0.90814316f, 0.91086388f, 0.91354549f, 0.91618794f, 0.91879123f,
+ 0.92135513f, 0.92387950f, 0.92636442f, 0.92880958f, 0.93121493f,
+ 0.93358046f, 0.93590593f, 0.93819135f, 0.94043654f, 0.94264150f,
+ 0.94480604f, 0.94693011f, 0.94901365f, 0.95105654f, 0.95305866f,
+ 0.95501995f, 0.95694035f, 0.95881975f, 0.96065807f, 0.96245527f,
+ 0.96421117f, 0.96592581f, 0.96759909f, 0.96923089f, 0.97082120f,
+ 0.97236991f, 0.97387701f, 0.97534233f, 0.97676587f, 0.97814763f,
+ 0.97948742f, 0.98078531f, 0.98204112f, 0.98325491f, 0.98442656f,
+ 0.98555607f, 0.98664331f, 0.98768836f, 0.98869103f, 0.98965138f,
+ 0.99056935f, 0.99144489f, 0.99227792f, 0.99306846f, 0.99381649f,
+ 0.99452192f, 0.99518472f, 0.99580491f, 0.99638247f, 0.99691731f,
+ 0.99740952f, 0.99785894f, 0.99826562f, 0.99862951f, 0.99895066f,
+ 0.99922901f, 0.99946457f, 0.99965733f, 0.99980724f, 0.99991435f,
+ 0.99997860f, 1.00000000f, 0.99997860f, 0.99991435f, 0.99980724f,
+ 0.99965733f, 0.99946457f, 0.99922901f, 0.99895066f, 0.99862951f,
+ 0.99826562f, 0.99785894f, 0.99740946f, 0.99691731f, 0.99638247f,
+ 0.99580491f, 0.99518472f, 0.99452192f, 0.99381644f, 0.99306846f,
+ 0.99227792f, 0.99144489f, 0.99056935f, 0.98965138f, 0.98869103f,
+ 0.98768836f, 0.98664331f, 0.98555607f, 0.98442656f, 0.98325491f,
+ 0.98204112f, 0.98078525f, 0.97948742f, 0.97814757f, 0.97676587f,
+ 0.97534227f, 0.97387695f, 0.97236991f, 0.97082120f, 0.96923089f,
+ 0.96759909f, 0.96592581f, 0.96421117f, 0.96245521f, 0.96065807f,
+ 0.95881969f, 0.95694029f, 0.95501995f, 0.95305860f, 0.95105648f,
+ 0.94901365f, 0.94693011f, 0.94480604f, 0.94264150f, 0.94043654f,
+ 0.93819129f, 0.93590593f, 0.93358046f, 0.93121493f, 0.92880952f,
+ 0.92636436f, 0.92387950f, 0.92135507f, 0.91879123f, 0.91618794f,
+ 0.91354543f, 0.91086382f, 0.90814310f, 0.90538365f, 0.90258527f,
+ 0.89974827f, 0.89687276f, 0.89395875f, 0.89100647f, 0.88801610f,
+ 0.88498759f, 0.88192123f, 0.87881714f, 0.87567532f, 0.87249595f,
+ 0.86927933f, 0.86602539f, 0.86273432f, 0.85940641f, 0.85604161f,
+ 0.85264009f, 0.84920216f, 0.84572780f, 0.84221715f, 0.83867055f,
+ 0.83508795f, 0.83146954f, 0.82781565f, 0.82412612f, 0.82040137f,
+ 0.81664157f, 0.81284660f, 0.80901700f, 0.80515265f, 0.80125374f,
+ 0.79732066f, 0.79335332f, 0.78935200f, 0.78531694f, 0.78124815f,
+ 0.77714586f, 0.77301049f, 0.76884180f, 0.76464021f, 0.76040596f,
+ 0.75613904f, 0.75183970f, 0.74750835f, 0.74314481f, 0.73874938f,
+ 0.73432249f, 0.72986400f, 0.72537428f, 0.72085363f, 0.71630186f,
+ 0.71171951f, 0.70710677f, 0.70246363f, 0.69779032f, 0.69308734f,
+ 0.68835449f, 0.68359220f, 0.67880070f, 0.67398006f, 0.66913044f,
+ 0.66425240f, 0.65934575f, 0.65441096f, 0.64944804f, 0.64445722f,
+ 0.63943905f, 0.63439327f, 0.62932026f, 0.62422055f, 0.61909389f,
+ 0.61394072f, 0.60876143f, 0.60355592f, 0.59832448f, 0.59306765f,
+ 0.58778518f, 0.58247757f, 0.57714522f, 0.57178789f, 0.56640613f,
+ 0.56100023f, 0.55557019f, 0.55011630f, 0.54463905f, 0.53913826f,
+ 0.53361434f, 0.52806783f, 0.52249849f, 0.51690674f, 0.51129305f,
+ 0.50565726f, 0.50000006f, 0.49432117f, 0.48862115f, 0.48290038f,
+ 0.47715873f, 0.47139663f, 0.46561456f, 0.45981231f, 0.45399037f,
+ 0.44814920f, 0.44228864f, 0.43640912f, 0.43051112f, 0.42459446f,
+ 0.41865960f, 0.41270703f, 0.40673658f, 0.40074870f, 0.39474386f,
+ 0.38872188f, 0.38268328f, 0.37662849f, 0.37055734f, 0.36447033f,
+ 0.35836792f, 0.35224995f, 0.34611690f, 0.33996922f, 0.33380675f,
+ 0.32763001f, 0.32143945f, 0.31523487f, 0.30901679f, 0.30278572f,
+ 0.29654145f, 0.29028472f, 0.28401530f, 0.27773371f, 0.27144048f,
+ 0.26513538f, 0.25881892f, 0.25249159f, 0.24615324f, 0.23980433f,
+ 0.23344538f, 0.22707619f, 0.22069728f, 0.21430916f, 0.20791161f,
+ 0.20150517f, 0.19509031f, 0.18866688f, 0.18223536f, 0.17579627f,
+ 0.16934940f, 0.16289529f, 0.15643445f, 0.14996666f, 0.14349243f,
+ 0.13701232f, 0.13052608f, 0.12403426f, 0.11753736f, 0.11103519f,
+ 0.10452849f, 0.09801710f, 0.09150149f, 0.08498220f, 0.07845904f,
+ 0.07193252f, 0.06540315f, 0.05887074f, 0.05233581f, 0.04579888f,
+ 0.03925974f, 0.03271893f, 0.02617695f, 0.01963361f, 0.01308943f,
+ 0.00654493f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f};
+
+// Hanning window: for 30ms with 1024 fft with symmetric zeros at 16kHz
+static const float kBlocks480w1024[1024] = {
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00327249f, 0.00654494f,
+ 0.00981732f, 0.01308960f, 0.01636173f, 0.01963369f, 0.02290544f,
+ 0.02617695f, 0.02944817f, 0.03271908f, 0.03598964f, 0.03925982f,
+ 0.04252957f, 0.04579887f, 0.04906768f, 0.05233596f, 0.05560368f,
+ 0.05887080f, 0.06213730f, 0.06540313f, 0.06866825f, 0.07193266f,
+ 0.07519628f, 0.07845910f, 0.08172107f, 0.08498218f, 0.08824237f,
+ 0.09150162f, 0.09475989f, 0.09801714f, 0.10127335f, 0.10452846f,
+ 0.10778246f, 0.11103531f, 0.11428697f, 0.11753740f, 0.12078657f,
+ 0.12403446f, 0.12728101f, 0.13052620f, 0.13376999f, 0.13701233f,
+ 0.14025325f, 0.14349262f, 0.14673047f, 0.14996676f, 0.15320145f,
+ 0.15643448f, 0.15966582f, 0.16289547f, 0.16612339f, 0.16934951f,
+ 0.17257382f, 0.17579629f, 0.17901687f, 0.18223552f, 0.18545224f,
+ 0.18866697f, 0.19187967f, 0.19509032f, 0.19829889f, 0.20150533f,
+ 0.20470962f, 0.20791170f, 0.21111156f, 0.21430916f, 0.21750447f,
+ 0.22069745f, 0.22388805f, 0.22707628f, 0.23026206f, 0.23344538f,
+ 0.23662618f, 0.23980446f, 0.24298020f, 0.24615330f, 0.24932377f,
+ 0.25249159f, 0.25565669f, 0.25881904f, 0.26197866f, 0.26513544f,
+ 0.26828939f, 0.27144045f, 0.27458861f, 0.27773386f, 0.28087610f,
+ 0.28401536f, 0.28715158f, 0.29028466f, 0.29341471f, 0.29654160f,
+ 0.29966527f, 0.30278578f, 0.30590302f, 0.30901700f, 0.31212768f,
+ 0.31523499f, 0.31833893f, 0.32143945f, 0.32453656f, 0.32763019f,
+ 0.33072028f, 0.33380687f, 0.33688986f, 0.33996925f, 0.34304500f,
+ 0.34611708f, 0.34918544f, 0.35225007f, 0.35531089f, 0.35836795f,
+ 0.36142117f, 0.36447051f, 0.36751595f, 0.37055743f, 0.37359497f,
+ 0.37662852f, 0.37965801f, 0.38268346f, 0.38570479f, 0.38872197f,
+ 0.39173502f, 0.39474389f, 0.39774847f, 0.40074885f, 0.40374491f,
+ 0.40673664f, 0.40972406f, 0.41270703f, 0.41568562f, 0.41865975f,
+ 0.42162940f, 0.42459452f, 0.42755508f, 0.43051112f, 0.43346250f,
+ 0.43640924f, 0.43935132f, 0.44228873f, 0.44522133f, 0.44814920f,
+ 0.45107228f, 0.45399052f, 0.45690390f, 0.45981237f, 0.46271592f,
+ 0.46561453f, 0.46850815f, 0.47139674f, 0.47428030f, 0.47715878f,
+ 0.48003215f, 0.48290035f, 0.48576337f, 0.48862126f, 0.49147385f,
+ 0.49432120f, 0.49716330f, 0.50000000f, 0.50283140f, 0.50565743f,
+ 0.50847799f, 0.51129311f, 0.51410276f, 0.51690692f, 0.51970553f,
+ 0.52249855f, 0.52528602f, 0.52806789f, 0.53084403f, 0.53361452f,
+ 0.53637928f, 0.53913832f, 0.54189163f, 0.54463905f, 0.54738063f,
+ 0.55011642f, 0.55284631f, 0.55557024f, 0.55828828f, 0.56100029f,
+ 0.56370628f, 0.56640625f, 0.56910014f, 0.57178795f, 0.57446963f,
+ 0.57714522f, 0.57981455f, 0.58247769f, 0.58513463f, 0.58778524f,
+ 0.59042960f, 0.59306765f, 0.59569931f, 0.59832460f, 0.60094351f,
+ 0.60355598f, 0.60616195f, 0.60876143f, 0.61135441f, 0.61394083f,
+ 0.61652070f, 0.61909395f, 0.62166059f, 0.62422055f, 0.62677383f,
+ 0.62932038f, 0.63186020f, 0.63439333f, 0.63691956f, 0.63943899f,
+ 0.64195162f, 0.64445734f, 0.64695615f, 0.64944810f, 0.65193301f,
+ 0.65441096f, 0.65688187f, 0.65934587f, 0.66180271f, 0.66425246f,
+ 0.66669512f, 0.66913062f, 0.67155898f, 0.67398012f, 0.67639405f,
+ 0.67880076f, 0.68120021f, 0.68359232f, 0.68597710f, 0.68835455f,
+ 0.69072467f, 0.69308740f, 0.69544262f, 0.69779050f, 0.70013082f,
+ 0.70246369f, 0.70478904f, 0.70710677f, 0.70941699f, 0.71171963f,
+ 0.71401459f, 0.71630198f, 0.71858168f, 0.72085363f, 0.72311789f,
+ 0.72537440f, 0.72762316f, 0.72986406f, 0.73209721f, 0.73432255f,
+ 0.73653996f, 0.73874950f, 0.74095118f, 0.74314487f, 0.74533057f,
+ 0.74750835f, 0.74967808f, 0.75183982f, 0.75399351f, 0.75613910f,
+ 0.75827658f, 0.76040596f, 0.76252723f, 0.76464027f, 0.76674515f,
+ 0.76884186f, 0.77093029f, 0.77301043f, 0.77508241f, 0.77714598f,
+ 0.77920127f, 0.78124821f, 0.78328675f, 0.78531694f, 0.78733873f,
+ 0.78935206f, 0.79135692f, 0.79335338f, 0.79534125f, 0.79732066f,
+ 0.79929149f, 0.80125386f, 0.80320752f, 0.80515265f, 0.80708915f,
+ 0.80901700f, 0.81093621f, 0.81284672f, 0.81474853f, 0.81664157f,
+ 0.81852591f, 0.82040149f, 0.82226825f, 0.82412618f, 0.82597536f,
+ 0.82781565f, 0.82964706f, 0.83146966f, 0.83328325f, 0.83508795f,
+ 0.83688378f, 0.83867061f, 0.84044838f, 0.84221727f, 0.84397703f,
+ 0.84572780f, 0.84746957f, 0.84920216f, 0.85092574f, 0.85264021f,
+ 0.85434544f, 0.85604161f, 0.85772866f, 0.85940641f, 0.86107504f,
+ 0.86273444f, 0.86438453f, 0.86602545f, 0.86765707f, 0.86927933f,
+ 0.87089235f, 0.87249607f, 0.87409031f, 0.87567532f, 0.87725097f,
+ 0.87881714f, 0.88037390f, 0.88192129f, 0.88345921f, 0.88498765f,
+ 0.88650668f, 0.88801610f, 0.88951612f, 0.89100653f, 0.89248741f,
+ 0.89395881f, 0.89542055f, 0.89687276f, 0.89831537f, 0.89974827f,
+ 0.90117162f, 0.90258533f, 0.90398932f, 0.90538365f, 0.90676826f,
+ 0.90814316f, 0.90950841f, 0.91086388f, 0.91220951f, 0.91354549f,
+ 0.91487163f, 0.91618794f, 0.91749454f, 0.91879123f, 0.92007810f,
+ 0.92135513f, 0.92262226f, 0.92387950f, 0.92512691f, 0.92636442f,
+ 0.92759192f, 0.92880958f, 0.93001723f, 0.93121493f, 0.93240267f,
+ 0.93358046f, 0.93474817f, 0.93590593f, 0.93705362f, 0.93819135f,
+ 0.93931901f, 0.94043654f, 0.94154406f, 0.94264150f, 0.94372880f,
+ 0.94480604f, 0.94587320f, 0.94693011f, 0.94797695f, 0.94901365f,
+ 0.95004016f, 0.95105654f, 0.95206273f, 0.95305866f, 0.95404440f,
+ 0.95501995f, 0.95598525f, 0.95694035f, 0.95788521f, 0.95881975f,
+ 0.95974404f, 0.96065807f, 0.96156180f, 0.96245527f, 0.96333838f,
+ 0.96421117f, 0.96507370f, 0.96592581f, 0.96676767f, 0.96759909f,
+ 0.96842021f, 0.96923089f, 0.97003126f, 0.97082120f, 0.97160077f,
+ 0.97236991f, 0.97312868f, 0.97387701f, 0.97461486f, 0.97534233f,
+ 0.97605932f, 0.97676587f, 0.97746199f, 0.97814763f, 0.97882277f,
+ 0.97948742f, 0.98014158f, 0.98078531f, 0.98141843f, 0.98204112f,
+ 0.98265332f, 0.98325491f, 0.98384601f, 0.98442656f, 0.98499662f,
+ 0.98555607f, 0.98610497f, 0.98664331f, 0.98717111f, 0.98768836f,
+ 0.98819500f, 0.98869103f, 0.98917651f, 0.98965138f, 0.99011570f,
+ 0.99056935f, 0.99101239f, 0.99144489f, 0.99186671f, 0.99227792f,
+ 0.99267852f, 0.99306846f, 0.99344778f, 0.99381649f, 0.99417448f,
+ 0.99452192f, 0.99485862f, 0.99518472f, 0.99550015f, 0.99580491f,
+ 0.99609905f, 0.99638247f, 0.99665523f, 0.99691731f, 0.99716878f,
+ 0.99740952f, 0.99763954f, 0.99785894f, 0.99806762f, 0.99826562f,
+ 0.99845290f, 0.99862951f, 0.99879545f, 0.99895066f, 0.99909520f,
+ 0.99922901f, 0.99935216f, 0.99946457f, 0.99956632f, 0.99965733f,
+ 0.99973762f, 0.99980724f, 0.99986613f, 0.99991435f, 0.99995178f,
+ 0.99997860f, 0.99999464f, 1.00000000f, 0.99999464f, 0.99997860f,
+ 0.99995178f, 0.99991435f, 0.99986613f, 0.99980724f, 0.99973762f,
+ 0.99965733f, 0.99956632f, 0.99946457f, 0.99935216f, 0.99922901f,
+ 0.99909520f, 0.99895066f, 0.99879545f, 0.99862951f, 0.99845290f,
+ 0.99826562f, 0.99806762f, 0.99785894f, 0.99763954f, 0.99740946f,
+ 0.99716872f, 0.99691731f, 0.99665523f, 0.99638247f, 0.99609905f,
+ 0.99580491f, 0.99550015f, 0.99518472f, 0.99485862f, 0.99452192f,
+ 0.99417448f, 0.99381644f, 0.99344778f, 0.99306846f, 0.99267852f,
+ 0.99227792f, 0.99186671f, 0.99144489f, 0.99101239f, 0.99056935f,
+ 0.99011564f, 0.98965138f, 0.98917651f, 0.98869103f, 0.98819494f,
+ 0.98768836f, 0.98717111f, 0.98664331f, 0.98610497f, 0.98555607f,
+ 0.98499656f, 0.98442656f, 0.98384601f, 0.98325491f, 0.98265326f,
+ 0.98204112f, 0.98141843f, 0.98078525f, 0.98014158f, 0.97948742f,
+ 0.97882277f, 0.97814757f, 0.97746193f, 0.97676587f, 0.97605932f,
+ 0.97534227f, 0.97461486f, 0.97387695f, 0.97312862f, 0.97236991f,
+ 0.97160077f, 0.97082120f, 0.97003126f, 0.96923089f, 0.96842015f,
+ 0.96759909f, 0.96676761f, 0.96592581f, 0.96507365f, 0.96421117f,
+ 0.96333838f, 0.96245521f, 0.96156180f, 0.96065807f, 0.95974404f,
+ 0.95881969f, 0.95788515f, 0.95694029f, 0.95598525f, 0.95501995f,
+ 0.95404440f, 0.95305860f, 0.95206267f, 0.95105648f, 0.95004016f,
+ 0.94901365f, 0.94797695f, 0.94693011f, 0.94587314f, 0.94480604f,
+ 0.94372880f, 0.94264150f, 0.94154406f, 0.94043654f, 0.93931895f,
+ 0.93819129f, 0.93705362f, 0.93590593f, 0.93474817f, 0.93358046f,
+ 0.93240267f, 0.93121493f, 0.93001723f, 0.92880952f, 0.92759192f,
+ 0.92636436f, 0.92512691f, 0.92387950f, 0.92262226f, 0.92135507f,
+ 0.92007804f, 0.91879123f, 0.91749448f, 0.91618794f, 0.91487157f,
+ 0.91354543f, 0.91220951f, 0.91086382f, 0.90950835f, 0.90814310f,
+ 0.90676820f, 0.90538365f, 0.90398932f, 0.90258527f, 0.90117157f,
+ 0.89974827f, 0.89831525f, 0.89687276f, 0.89542055f, 0.89395875f,
+ 0.89248741f, 0.89100647f, 0.88951600f, 0.88801610f, 0.88650662f,
+ 0.88498759f, 0.88345915f, 0.88192123f, 0.88037384f, 0.87881714f,
+ 0.87725091f, 0.87567532f, 0.87409031f, 0.87249595f, 0.87089223f,
+ 0.86927933f, 0.86765701f, 0.86602539f, 0.86438447f, 0.86273432f,
+ 0.86107504f, 0.85940641f, 0.85772860f, 0.85604161f, 0.85434544f,
+ 0.85264009f, 0.85092574f, 0.84920216f, 0.84746951f, 0.84572780f,
+ 0.84397697f, 0.84221715f, 0.84044844f, 0.83867055f, 0.83688372f,
+ 0.83508795f, 0.83328319f, 0.83146954f, 0.82964706f, 0.82781565f,
+ 0.82597530f, 0.82412612f, 0.82226813f, 0.82040137f, 0.81852591f,
+ 0.81664157f, 0.81474847f, 0.81284660f, 0.81093609f, 0.80901700f,
+ 0.80708915f, 0.80515265f, 0.80320752f, 0.80125374f, 0.79929143f,
+ 0.79732066f, 0.79534125f, 0.79335332f, 0.79135686f, 0.78935200f,
+ 0.78733861f, 0.78531694f, 0.78328675f, 0.78124815f, 0.77920121f,
+ 0.77714586f, 0.77508223f, 0.77301049f, 0.77093029f, 0.76884180f,
+ 0.76674509f, 0.76464021f, 0.76252711f, 0.76040596f, 0.75827658f,
+ 0.75613904f, 0.75399339f, 0.75183970f, 0.74967796f, 0.74750835f,
+ 0.74533057f, 0.74314481f, 0.74095106f, 0.73874938f, 0.73653996f,
+ 0.73432249f, 0.73209721f, 0.72986400f, 0.72762305f, 0.72537428f,
+ 0.72311789f, 0.72085363f, 0.71858162f, 0.71630186f, 0.71401453f,
+ 0.71171951f, 0.70941705f, 0.70710677f, 0.70478898f, 0.70246363f,
+ 0.70013070f, 0.69779032f, 0.69544268f, 0.69308734f, 0.69072461f,
+ 0.68835449f, 0.68597704f, 0.68359220f, 0.68120021f, 0.67880070f,
+ 0.67639399f, 0.67398006f, 0.67155886f, 0.66913044f, 0.66669512f,
+ 0.66425240f, 0.66180259f, 0.65934575f, 0.65688181f, 0.65441096f,
+ 0.65193301f, 0.64944804f, 0.64695609f, 0.64445722f, 0.64195150f,
+ 0.63943905f, 0.63691956f, 0.63439327f, 0.63186014f, 0.62932026f,
+ 0.62677372f, 0.62422055f, 0.62166059f, 0.61909389f, 0.61652064f,
+ 0.61394072f, 0.61135429f, 0.60876143f, 0.60616189f, 0.60355592f,
+ 0.60094339f, 0.59832448f, 0.59569913f, 0.59306765f, 0.59042960f,
+ 0.58778518f, 0.58513451f, 0.58247757f, 0.57981461f, 0.57714522f,
+ 0.57446963f, 0.57178789f, 0.56910002f, 0.56640613f, 0.56370628f,
+ 0.56100023f, 0.55828822f, 0.55557019f, 0.55284619f, 0.55011630f,
+ 0.54738069f, 0.54463905f, 0.54189152f, 0.53913826f, 0.53637916f,
+ 0.53361434f, 0.53084403f, 0.52806783f, 0.52528596f, 0.52249849f,
+ 0.51970541f, 0.51690674f, 0.51410276f, 0.51129305f, 0.50847787f,
+ 0.50565726f, 0.50283122f, 0.50000006f, 0.49716327f, 0.49432117f,
+ 0.49147379f, 0.48862115f, 0.48576325f, 0.48290038f, 0.48003212f,
+ 0.47715873f, 0.47428021f, 0.47139663f, 0.46850798f, 0.46561456f,
+ 0.46271589f, 0.45981231f, 0.45690379f, 0.45399037f, 0.45107210f,
+ 0.44814920f, 0.44522130f, 0.44228864f, 0.43935123f, 0.43640912f,
+ 0.43346232f, 0.43051112f, 0.42755505f, 0.42459446f, 0.42162928f,
+ 0.41865960f, 0.41568545f, 0.41270703f, 0.40972400f, 0.40673658f,
+ 0.40374479f, 0.40074870f, 0.39774850f, 0.39474386f, 0.39173496f,
+ 0.38872188f, 0.38570464f, 0.38268328f, 0.37965804f, 0.37662849f,
+ 0.37359491f, 0.37055734f, 0.36751580f, 0.36447033f, 0.36142117f,
+ 0.35836792f, 0.35531086f, 0.35224995f, 0.34918529f, 0.34611690f,
+ 0.34304500f, 0.33996922f, 0.33688980f, 0.33380675f, 0.33072016f,
+ 0.32763001f, 0.32453656f, 0.32143945f, 0.31833887f, 0.31523487f,
+ 0.31212750f, 0.30901679f, 0.30590302f, 0.30278572f, 0.29966521f,
+ 0.29654145f, 0.29341453f, 0.29028472f, 0.28715155f, 0.28401530f,
+ 0.28087601f, 0.27773371f, 0.27458847f, 0.27144048f, 0.26828936f,
+ 0.26513538f, 0.26197854f, 0.25881892f, 0.25565651f, 0.25249159f,
+ 0.24932374f, 0.24615324f, 0.24298008f, 0.23980433f, 0.23662600f,
+ 0.23344538f, 0.23026201f, 0.22707619f, 0.22388794f, 0.22069728f,
+ 0.21750426f, 0.21430916f, 0.21111152f, 0.20791161f, 0.20470949f,
+ 0.20150517f, 0.19829892f, 0.19509031f, 0.19187963f, 0.18866688f,
+ 0.18545210f, 0.18223536f, 0.17901689f, 0.17579627f, 0.17257376f,
+ 0.16934940f, 0.16612324f, 0.16289529f, 0.15966584f, 0.15643445f,
+ 0.15320137f, 0.14996666f, 0.14673033f, 0.14349243f, 0.14025325f,
+ 0.13701232f, 0.13376991f, 0.13052608f, 0.12728085f, 0.12403426f,
+ 0.12078657f, 0.11753736f, 0.11428688f, 0.11103519f, 0.10778230f,
+ 0.10452849f, 0.10127334f, 0.09801710f, 0.09475980f, 0.09150149f,
+ 0.08824220f, 0.08498220f, 0.08172106f, 0.07845904f, 0.07519618f,
+ 0.07193252f, 0.06866808f, 0.06540315f, 0.06213728f, 0.05887074f,
+ 0.05560357f, 0.05233581f, 0.04906749f, 0.04579888f, 0.04252954f,
+ 0.03925974f, 0.03598953f, 0.03271893f, 0.02944798f, 0.02617695f,
+ 0.02290541f, 0.01963361f, 0.01636161f, 0.01308943f, 0.00981712f,
+ 0.00654493f, 0.00327244f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WINDOWS_PRIVATE_H_
diff --git a/webrtc/modules/audio_processing/transient/wpd_node.cc b/webrtc/modules/audio_processing/transient/wpd_node.cc
index 8114a70..2e0ee7e 100644
--- a/webrtc/modules/audio_processing/transient/wpd_node.cc
+++ b/webrtc/modules/audio_processing/transient/wpd_node.cc
@@ -8,29 +8,30 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/transient/wpd_node.h"
+#include "modules/audio_processing/transient/wpd_node.h"
-#include <assert.h>
#include <math.h>
#include <string.h>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/fir_filter.h"
-#include "webrtc/modules/audio_processing/transient/dyadic_decimator.h"
+#include "common_audio/fir_filter.h"
+#include "common_audio/fir_filter_factory.h"
+#include "modules/audio_processing/transient/dyadic_decimator.h"
+#include "rtc_base/checks.h"
namespace webrtc {
WPDNode::WPDNode(size_t length,
const float* coefficients,
size_t coefficients_length)
- : // The data buffer has parent data length to be able to contain and filter
- // it.
+ : // The data buffer has parent data length to be able to contain and
+ // filter it.
data_(new float[2 * length + 1]),
length_(length),
- filter_(FIRFilter::Create(coefficients,
- coefficients_length,
- 2 * length + 1)) {
- assert(length > 0 && coefficients && coefficients_length > 0);
+ filter_(
+ CreateFirFilter(coefficients, coefficients_length, 2 * length + 1)) {
+ RTC_DCHECK_GT(length, 0);
+ RTC_DCHECK(coefficients);
+ RTC_DCHECK_GT(coefficients_length, 0);
memset(data_.get(), 0.f, (2 * length + 1) * sizeof(data_[0]));
}
@@ -46,8 +47,8 @@ int WPDNode::Update(const float* parent_data, size_t parent_data_length) {
// Decimate data.
const bool kOddSequence = true;
- size_t output_samples = DyadicDecimate(
- data_.get(), parent_data_length, kOddSequence, data_.get(), length_);
+ size_t output_samples = DyadicDecimate(data_.get(), parent_data_length,
+ kOddSequence, data_.get(), length_);
if (output_samples != length_) {
return -1;
}
diff --git a/webrtc/modules/audio_processing/transient/wpd_node.h b/webrtc/modules/audio_processing/transient/wpd_node.h
index f66cad9..6a52fb7 100644
--- a/webrtc/modules/audio_processing/transient/wpd_node.h
+++ b/webrtc/modules/audio_processing/transient/wpd_node.h
@@ -8,11 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/typedefs.h"
+#include <memory>
namespace webrtc {
@@ -36,11 +35,11 @@ class WPDNode {
size_t length() const { return length_; }
private:
- rtc::scoped_ptr<float[]> data_;
+ std::unique_ptr<float[]> data_;
size_t length_;
- rtc::scoped_ptr<FIRFilter> filter_;
+ std::unique_ptr<FIRFilter> filter_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
diff --git a/webrtc/modules/audio_processing/transient/wpd_tree.cc b/webrtc/modules/audio_processing/transient/wpd_tree.cc
index 40a37a0..c8aa615 100644
--- a/webrtc/modules/audio_processing/transient/wpd_tree.cc
+++ b/webrtc/modules/audio_processing/transient/wpd_tree.cc
@@ -8,31 +8,30 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/transient/wpd_tree.h"
+#include "modules/audio_processing/transient/wpd_tree.h"
-#include <assert.h>
-#include <math.h>
#include <string.h>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/transient/dyadic_decimator.h"
-#include "webrtc/modules/audio_processing/transient/wpd_node.h"
+#include "modules/audio_processing/transient/wpd_node.h"
+#include "rtc_base/checks.h"
namespace webrtc {
-WPDTree::WPDTree(size_t data_length, const float* high_pass_coefficients,
- const float* low_pass_coefficients, size_t coefficients_length,
+WPDTree::WPDTree(size_t data_length,
+ const float* high_pass_coefficients,
+ const float* low_pass_coefficients,
+ size_t coefficients_length,
int levels)
: data_length_(data_length),
levels_(levels),
num_nodes_((1 << (levels + 1)) - 1) {
- assert(data_length > (static_cast<size_t>(1) << levels) &&
- high_pass_coefficients &&
- low_pass_coefficients &&
- levels > 0);
+ RTC_DCHECK_GT(data_length, (static_cast<size_t>(1) << levels));
+ RTC_DCHECK(high_pass_coefficients);
+ RTC_DCHECK(low_pass_coefficients);
+ RTC_DCHECK_GT(levels, 0);
// Size is 1 more, so we can use the array as 1-based. nodes_[0] is never
// allocated.
- nodes_.reset(new rtc::scoped_ptr<WPDNode>[num_nodes_ + 1]);
+ nodes_.reset(new std::unique_ptr<WPDNode>[num_nodes_ + 1]);
// Create the first node
const float kRootCoefficient = 1.f; // Identity Coefficient.
@@ -66,10 +65,10 @@ WPDTree::WPDTree(size_t data_length, const float* high_pass_coefficients,
WPDTree::~WPDTree() {}
WPDNode* WPDTree::NodeAt(int level, int index) {
- const int kNumNodesAtLevel = 1 << level;
- if (level < 0 || level > levels_ || index < 0 || index >= kNumNodesAtLevel) {
+ if (level < 0 || level > levels_ || index < 0 || index >= 1 << level) {
return NULL;
}
+
return nodes_[(1 << level) + index].get();
}
@@ -99,8 +98,8 @@ int WPDTree::Update(const float* data, size_t data_length) {
index_left_child = index * 2;
index_right_child = index_left_child + 1;
- update_result = nodes_[index_left_child]->Update(
- nodes_[index]->data(), nodes_[index]->length());
+ update_result = nodes_[index_left_child]->Update(nodes_[index]->data(),
+ nodes_[index]->length());
if (update_result != 0) {
return -1;
}
diff --git a/webrtc/modules/audio_processing/transient/wpd_tree.h b/webrtc/modules/audio_processing/transient/wpd_tree.h
index 7f0fc79..c54220f 100644
--- a/webrtc/modules/audio_processing/transient/wpd_tree.h
+++ b/webrtc/modules/audio_processing/transient/wpd_tree.h
@@ -8,11 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/transient/wpd_node.h"
+#include <stddef.h>
+
+#include <memory>
+
+#include "modules/audio_processing/transient/wpd_node.h"
namespace webrtc {
@@ -46,9 +49,7 @@ class WPDTree {
~WPDTree();
// Returns the number of nodes at any given level.
- static int NumberOfNodesAtLevel(int level) {
- return 1 << level;
- }
+ static int NumberOfNodesAtLevel(int level) { return 1 << level; }
// Returns a pointer to the node at the given level and index(of that level).
// Level goes from 0 to levels().
@@ -83,9 +84,9 @@ class WPDTree {
size_t data_length_;
int levels_;
int num_nodes_;
- rtc::scoped_ptr<rtc::scoped_ptr<WPDNode>[]> nodes_;
+ std::unique_ptr<std::unique_ptr<WPDNode>[]> nodes_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
diff --git a/webrtc/modules/audio_processing/typing_detection.cc b/webrtc/modules/audio_processing/typing_detection.cc
index 5f5ce0a..e725b26 100644
--- a/webrtc/modules/audio_processing/typing_detection.cc
+++ b/webrtc/modules/audio_processing/typing_detection.cc
@@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/typing_detection.h"
+#include "modules/audio_processing/typing_detection.h"
namespace webrtc {
@@ -24,8 +24,7 @@ TypingDetection::TypingDetection()
reporting_threshold_(300),
penalty_decay_(1),
type_event_delay_(2),
- report_detection_update_period_(1) {
-}
+ report_detection_update_period_(1) {}
TypingDetection::~TypingDetection() {}
@@ -41,8 +40,7 @@ bool TypingDetection::Process(bool key_pressed, bool vad_activity) {
else
++time_since_last_typing_;
- if (time_since_last_typing_ < type_event_delay_ &&
- vad_activity &&
+ if (time_since_last_typing_ < type_event_delay_ && vad_activity &&
time_active_ < time_window_) {
penalty_counter_ += cost_per_typing_;
if (penalty_counter_ > reporting_threshold_)
@@ -73,15 +71,20 @@ void TypingDetection::SetParameters(int time_window,
int penalty_decay,
int type_event_delay,
int report_detection_update_period) {
- if (time_window) time_window_ = time_window;
+ if (time_window)
+ time_window_ = time_window;
- if (cost_per_typing) cost_per_typing_ = cost_per_typing;
+ if (cost_per_typing)
+ cost_per_typing_ = cost_per_typing;
- if (reporting_threshold) reporting_threshold_ = reporting_threshold;
+ if (reporting_threshold)
+ reporting_threshold_ = reporting_threshold;
- if (penalty_decay) penalty_decay_ = penalty_decay;
+ if (penalty_decay)
+ penalty_decay_ = penalty_decay;
- if (type_event_delay) type_event_delay_ = type_event_delay;
+ if (type_event_delay)
+ type_event_delay_ = type_event_delay;
if (report_detection_update_period)
report_detection_update_period_ = report_detection_update_period;
diff --git a/webrtc/modules/audio_processing/typing_detection.h b/webrtc/modules/audio_processing/typing_detection.h
index 5fa6456..d8fb359 100644
--- a/webrtc/modules/audio_processing/typing_detection.h
+++ b/webrtc/modules/audio_processing/typing_detection.h
@@ -8,15 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_
+#ifndef MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_
+#define MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_
-#include "webrtc/modules/interface/module_common_types.h"
-#include "webrtc/typedefs.h"
+#include "rtc_base/system/rtc_export.h"
namespace webrtc {
-class TypingDetection {
+class RTC_EXPORT TypingDetection {
public:
TypingDetection();
virtual ~TypingDetection();
@@ -90,4 +89,4 @@ class TypingDetection {
} // namespace webrtc
-#endif // #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_
+#endif // #ifndef MODULES_AUDIO_PROCESSING_TYPING_DETECTION_H_
diff --git a/webrtc/modules/audio_processing/utility/BUILD.gn b/webrtc/modules/audio_processing/utility/BUILD.gn
new file mode 100644
index 0000000..437b544
--- /dev/null
+++ b/webrtc/modules/audio_processing/utility/BUILD.gn
@@ -0,0 +1,81 @@
+# 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_library("cascaded_biquad_filter") {
+ sources = [
+ "cascaded_biquad_filter.cc",
+ "cascaded_biquad_filter.h",
+ ]
+ deps = [
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ ]
+}
+
+rtc_library("legacy_delay_estimator") {
+ sources = [
+ "delay_estimator.cc",
+ "delay_estimator.h",
+ "delay_estimator_internal.h",
+ "delay_estimator_wrapper.cc",
+ "delay_estimator_wrapper.h",
+ ]
+ deps = [ "../../../rtc_base:checks" ]
+}
+
+rtc_library("pffft_wrapper") {
+ visibility = [ "../*" ]
+ sources = [
+ "pffft_wrapper.cc",
+ "pffft_wrapper.h",
+ ]
+ deps = [
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ "//third_party/pffft",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("cascaded_biquad_filter_unittest") {
+ testonly = true
+
+ sources = [ "cascaded_biquad_filter_unittest.cc" ]
+ deps = [
+ ":cascaded_biquad_filter",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+
+ rtc_library("legacy_delay_estimator_unittest") {
+ testonly = true
+
+ sources = [ "delay_estimator_unittest.cc" ]
+ deps = [
+ ":legacy_delay_estimator",
+ "../../../rtc_base:rtc_base_approved",
+ "../../../test:test_support",
+ "//testing/gtest",
+ ]
+ }
+
+ rtc_library("pffft_wrapper_unittest") {
+ testonly = true
+ sources = [ "pffft_wrapper_unittest.cc" ]
+ deps = [
+ ":pffft_wrapper",
+ "../../../test:test_support",
+ "//testing/gtest",
+ "//third_party/pffft",
+ ]
+ }
+}
diff --git a/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.cc b/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.cc
new file mode 100644
index 0000000..08b9464
--- /dev/null
+++ b/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.cc
@@ -0,0 +1,117 @@
+/*
+ * 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/audio_processing/utility/cascaded_biquad_filter.h"
+
+#include <algorithm>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+CascadedBiQuadFilter::BiQuadParam::BiQuadParam(std::complex<float> zero,
+ std::complex<float> pole,
+ float gain,
+ bool mirror_zero_along_i_axis)
+ : zero(zero),
+ pole(pole),
+ gain(gain),
+ mirror_zero_along_i_axis(mirror_zero_along_i_axis) {}
+
+CascadedBiQuadFilter::BiQuadParam::BiQuadParam(const BiQuadParam&) = default;
+
+CascadedBiQuadFilter::BiQuad::BiQuad(
+ const CascadedBiQuadFilter::BiQuadParam& param)
+ : x(), y() {
+ float z_r = std::real(param.zero);
+ float z_i = std::imag(param.zero);
+ float p_r = std::real(param.pole);
+ float p_i = std::imag(param.pole);
+ float gain = param.gain;
+
+ if (param.mirror_zero_along_i_axis) {
+ // Assuming zeroes at z_r and -z_r.
+ RTC_DCHECK(z_i == 0.f);
+ coefficients.b[0] = gain * 1.f;
+ coefficients.b[1] = 0.f;
+ coefficients.b[2] = gain * -(z_r * z_r);
+ } else {
+ // Assuming zeros at (z_r + z_i*i) and (z_r - z_i*i).
+ coefficients.b[0] = gain * 1.f;
+ coefficients.b[1] = gain * -2.f * z_r;
+ coefficients.b[2] = gain * (z_r * z_r + z_i * z_i);
+ }
+
+ // Assuming poles at (p_r + p_i*i) and (p_r - p_i*i).
+ coefficients.a[0] = -2.f * p_r;
+ coefficients.a[1] = p_r * p_r + p_i * p_i;
+}
+
+void CascadedBiQuadFilter::BiQuad::BiQuad::Reset() {
+ x[0] = x[1] = y[0] = y[1] = 0.f;
+}
+
+CascadedBiQuadFilter::CascadedBiQuadFilter(
+ const CascadedBiQuadFilter::BiQuadCoefficients& coefficients,
+ size_t num_biquads)
+ : biquads_(num_biquads, BiQuad(coefficients)) {}
+
+CascadedBiQuadFilter::CascadedBiQuadFilter(
+ const std::vector<CascadedBiQuadFilter::BiQuadParam>& biquad_params) {
+ for (const auto& param : biquad_params) {
+ biquads_.push_back(BiQuad(param));
+ }
+}
+
+CascadedBiQuadFilter::~CascadedBiQuadFilter() = default;
+
+void CascadedBiQuadFilter::Process(rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> y) {
+ if (biquads_.size() > 0) {
+ ApplyBiQuad(x, y, &biquads_[0]);
+ for (size_t k = 1; k < biquads_.size(); ++k) {
+ ApplyBiQuad(y, y, &biquads_[k]);
+ }
+ } else {
+ std::copy(x.begin(), x.end(), y.begin());
+ }
+}
+
+void CascadedBiQuadFilter::Process(rtc::ArrayView<float> y) {
+ for (auto& biquad : biquads_) {
+ ApplyBiQuad(y, y, &biquad);
+ }
+}
+
+void CascadedBiQuadFilter::Reset() {
+ for (auto& biquad : biquads_) {
+ biquad.Reset();
+ }
+}
+
+void CascadedBiQuadFilter::ApplyBiQuad(rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> y,
+ CascadedBiQuadFilter::BiQuad* biquad) {
+ RTC_DCHECK_EQ(x.size(), y.size());
+ const auto* c_b = biquad->coefficients.b;
+ const auto* c_a = biquad->coefficients.a;
+ auto* m_x = biquad->x;
+ auto* m_y = biquad->y;
+ for (size_t k = 0; k < x.size(); ++k) {
+ const float tmp = x[k];
+ y[k] = c_b[0] * tmp + c_b[1] * m_x[0] + c_b[2] * m_x[1] - c_a[0] * m_y[0] -
+ c_a[1] * m_y[1];
+ m_x[1] = m_x[0];
+ m_x[0] = tmp;
+ m_y[1] = m_y[0];
+ m_y[0] = y[k];
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.h b/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.h
new file mode 100644
index 0000000..120b52a
--- /dev/null
+++ b/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.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_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_
+
+#include <stddef.h>
+
+#include <complex>
+#include <vector>
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+// Applies a number of biquads in a cascaded manner. The filter implementation
+// is direct form 1.
+class CascadedBiQuadFilter {
+ public:
+ struct BiQuadParam {
+ BiQuadParam(std::complex<float> zero,
+ std::complex<float> pole,
+ float gain,
+ bool mirror_zero_along_i_axis = false);
+ explicit BiQuadParam(const BiQuadParam&);
+ std::complex<float> zero;
+ std::complex<float> pole;
+ float gain;
+ bool mirror_zero_along_i_axis;
+ };
+
+ struct BiQuadCoefficients {
+ float b[3];
+ float a[2];
+ };
+
+ struct BiQuad {
+ explicit BiQuad(const BiQuadCoefficients& coefficients)
+ : coefficients(coefficients), x(), y() {}
+ explicit BiQuad(const CascadedBiQuadFilter::BiQuadParam& param);
+ void Reset();
+ BiQuadCoefficients coefficients;
+ float x[2];
+ float y[2];
+ };
+
+ CascadedBiQuadFilter(
+ const CascadedBiQuadFilter::BiQuadCoefficients& coefficients,
+ size_t num_biquads);
+ explicit CascadedBiQuadFilter(
+ const std::vector<CascadedBiQuadFilter::BiQuadParam>& biquad_params);
+ ~CascadedBiQuadFilter();
+ CascadedBiQuadFilter(const CascadedBiQuadFilter&) = delete;
+ CascadedBiQuadFilter& operator=(const CascadedBiQuadFilter&) = delete;
+
+ // Applies the biquads on the values in x in order to form the output in y.
+ void Process(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
+ // Applies the biquads on the values in y in an in-place manner.
+ void Process(rtc::ArrayView<float> y);
+ // Resets the filter to its initial state.
+ void Reset();
+
+ private:
+ void ApplyBiQuad(rtc::ArrayView<const float> x,
+ rtc::ArrayView<float> y,
+ CascadedBiQuadFilter::BiQuad* biquad);
+
+ std::vector<BiQuad> biquads_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_CASCADED_BIQUAD_FILTER_H_
diff --git a/webrtc/modules/audio_processing/utility/delay_estimator.c b/webrtc/modules/audio_processing/utility/delay_estimator.cc
index f9f3dc2..73c70b0 100644
--- a/webrtc/modules/audio_processing/utility/delay_estimator.c
+++ b/webrtc/modules/audio_processing/utility/delay_estimator.cc
@@ -8,20 +8,27 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/utility/delay_estimator.h"
+#include "modules/audio_processing/utility/delay_estimator.h"
-#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <algorithm>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
// Number of right shifts for scaling is linearly depending on number of bits in
// the far-end binary spectrum.
static const int kShiftsAtZero = 13; // Right shifts at zero binary spectrum.
static const int kShiftsLinearSlope = 3;
-static const int32_t kProbabilityOffset = 1024; // 2 in Q9.
+static const int32_t kProbabilityOffset = 1024; // 2 in Q9.
static const int32_t kProbabilityLowerLimit = 8704; // 17 in Q9.
-static const int32_t kProbabilityMinSpread = 2816; // 5.5 in Q9.
+static const int32_t kProbabilityMinSpread = 2816; // 5.5 in Q9.
// Robust validation settings
static const float kHistogramMax = 3000.f;
@@ -35,15 +42,17 @@ static const float kFractionSlope = 0.05f;
static const float kMinFractionWhenPossiblyCausal = 0.5f;
static const float kMinFractionWhenPossiblyNonCausal = 0.25f;
+} // namespace
+
// Counts and returns number of bits of a 32-bit word.
static int BitCount(uint32_t u32) {
- uint32_t tmp = u32 - ((u32 >> 1) & 033333333333) -
- ((u32 >> 2) & 011111111111);
+ uint32_t tmp =
+ u32 - ((u32 >> 1) & 033333333333) - ((u32 >> 2) & 011111111111);
tmp = ((tmp + (tmp >> 3)) & 030707070707);
tmp = (tmp + (tmp >> 6));
tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077;
- return ((int) tmp);
+ return ((int)tmp);
}
// Compares the |binary_vector| with all rows of the |binary_matrix| and counts
@@ -67,7 +76,7 @@ static void BitCountComparison(uint32_t binary_vector,
// Compare |binary_vector| with all rows of the |binary_matrix|
for (; n < matrix_size; n++) {
- bit_counts[n] = (int32_t) BitCount(binary_vector ^ binary_matrix[n]);
+ bit_counts[n] = (int32_t)BitCount(binary_vector ^ binary_matrix[n]);
}
}
@@ -94,11 +103,12 @@ static void UpdateRobustValidationStatistics(BinaryDelayEstimator* self,
int32_t valley_level_q14) {
const float valley_depth = valley_depth_q14 * kQ14Scaling;
float decrease_in_last_set = valley_depth;
- const int max_hits_for_slow_change = (candidate_delay < self->last_delay) ?
- kMaxHitsWhenPossiblyNonCausal : kMaxHitsWhenPossiblyCausal;
+ const int max_hits_for_slow_change = (candidate_delay < self->last_delay)
+ ? kMaxHitsWhenPossiblyNonCausal
+ : kMaxHitsWhenPossiblyCausal;
int i = 0;
- assert(self->history_size == self->farend->history_size);
+ RTC_DCHECK_EQ(self->history_size, self->farend->history_size);
// Reset |candidate_hits| if we have a new candidate.
if (candidate_delay != self->last_candidate_delay) {
self->candidate_hits = 0;
@@ -125,18 +135,20 @@ static void UpdateRobustValidationStatistics(BinaryDelayEstimator* self,
// |candidate_delay| is a "potential" candidate and we start decreasing
// these histogram bins more rapidly with |valley_depth|.
if (self->candidate_hits < max_hits_for_slow_change) {
- decrease_in_last_set = (self->mean_bit_counts[self->compare_delay] -
- valley_level_q14) * kQ14Scaling;
+ decrease_in_last_set =
+ (self->mean_bit_counts[self->compare_delay] - valley_level_q14) *
+ kQ14Scaling;
}
// 4. All other bins are decreased with |valley_depth|.
// TODO(bjornv): Investigate how to make this loop more efficient. Split up
// the loop? Remove parts that doesn't add too much.
for (i = 0; i < self->history_size; ++i) {
int is_in_last_set = (i >= self->last_delay - 2) &&
- (i <= self->last_delay + 1) && (i != candidate_delay);
- int is_in_candidate_set = (i >= candidate_delay - 2) &&
- (i <= candidate_delay + 1);
- self->histogram[i] -= decrease_in_last_set * is_in_last_set +
+ (i <= self->last_delay + 1) && (i != candidate_delay);
+ int is_in_candidate_set =
+ (i >= candidate_delay - 2) && (i <= candidate_delay + 1);
+ self->histogram[i] -=
+ decrease_in_last_set * is_in_last_set +
valley_depth * (!is_in_last_set && !is_in_candidate_set);
// 5. No histogram bin can go below 0.
if (self->histogram[i] < 0) {
@@ -194,16 +206,18 @@ static int HistogramBasedValidation(const BinaryDelayEstimator* self,
// into tables?
if (delay_difference > self->allowed_offset) {
fraction = 1.f - kFractionSlope * (delay_difference - self->allowed_offset);
- fraction = (fraction > kMinFractionWhenPossiblyCausal ? fraction :
- kMinFractionWhenPossiblyCausal);
+ fraction = (fraction > kMinFractionWhenPossiblyCausal
+ ? fraction
+ : kMinFractionWhenPossiblyCausal);
} else if (delay_difference < 0) {
- fraction = kMinFractionWhenPossiblyNonCausal -
- kFractionSlope * delay_difference;
+ fraction =
+ kMinFractionWhenPossiblyNonCausal - kFractionSlope * delay_difference;
fraction = (fraction > 1.f ? 1.f : fraction);
}
histogram_threshold *= fraction;
- histogram_threshold = (histogram_threshold > kMinHistogramThreshold ?
- histogram_threshold : kMinHistogramThreshold);
+ histogram_threshold =
+ (histogram_threshold > kMinHistogramThreshold ? histogram_threshold
+ : kMinHistogramThreshold);
is_histogram_valid =
(self->histogram[candidate_delay] >= histogram_threshold) &&
@@ -241,8 +255,8 @@ static int RobustValidation(const BinaryDelayEstimator* self,
// i) Before we actually have a valid estimate (|last_delay| == -2), we say
// a candidate is valid if either algorithm states so
// (|is_instantaneous_valid| OR |is_histogram_valid|).
- is_robust = (self->last_delay < 0) &&
- (is_instantaneous_valid || is_histogram_valid);
+ is_robust =
+ (self->last_delay < 0) && (is_instantaneous_valid || is_histogram_valid);
// ii) Otherwise, we need both algorithms to be certain
// (|is_instantaneous_valid| AND |is_histogram_valid|)
is_robust |= is_instantaneous_valid && is_histogram_valid;
@@ -250,13 +264,12 @@ static int RobustValidation(const BinaryDelayEstimator* self,
// the instantaneous one if |is_histogram_valid| = 1 and the histogram
// is significantly strong.
is_robust |= is_histogram_valid &&
- (self->histogram[candidate_delay] > self->last_delay_histogram);
+ (self->histogram[candidate_delay] > self->last_delay_histogram);
return is_robust;
}
void WebRtc_FreeBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self) {
-
if (self == NULL) {
return;
}
@@ -276,7 +289,8 @@ BinaryDelayEstimatorFarend* WebRtc_CreateBinaryDelayEstimatorFarend(
if (history_size > 1) {
// Sanity conditions fulfilled.
- self = malloc(sizeof(BinaryDelayEstimatorFarend));
+ self = static_cast<BinaryDelayEstimatorFarend*>(
+ malloc(sizeof(BinaryDelayEstimatorFarend)));
}
if (self == NULL) {
return NULL;
@@ -294,24 +308,22 @@ BinaryDelayEstimatorFarend* WebRtc_CreateBinaryDelayEstimatorFarend(
int WebRtc_AllocateFarendBufferMemory(BinaryDelayEstimatorFarend* self,
int history_size) {
- assert(self != NULL);
+ RTC_DCHECK(self);
// (Re-)Allocate memory for history buffers.
- self->binary_far_history =
+ self->binary_far_history = static_cast<uint32_t*>(
realloc(self->binary_far_history,
- history_size * sizeof(*self->binary_far_history));
- self->far_bit_counts = realloc(self->far_bit_counts,
- history_size * sizeof(*self->far_bit_counts));
+ history_size * sizeof(*self->binary_far_history)));
+ self->far_bit_counts = static_cast<int*>(realloc(
+ self->far_bit_counts, history_size * sizeof(*self->far_bit_counts)));
if ((self->binary_far_history == NULL) || (self->far_bit_counts == NULL)) {
history_size = 0;
}
// Fill with zeros if we have expanded the buffers.
if (history_size > self->history_size) {
int size_diff = history_size - self->history_size;
- memset(&self->binary_far_history[self->history_size],
- 0,
+ memset(&self->binary_far_history[self->history_size], 0,
sizeof(*self->binary_far_history) * size_diff);
- memset(&self->far_bit_counts[self->history_size],
- 0,
+ memset(&self->far_bit_counts[self->history_size], 0,
sizeof(*self->far_bit_counts) * size_diff);
}
self->history_size = history_size;
@@ -320,22 +332,23 @@ int WebRtc_AllocateFarendBufferMemory(BinaryDelayEstimatorFarend* self,
}
void WebRtc_InitBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self) {
- assert(self != NULL);
+ RTC_DCHECK(self);
memset(self->binary_far_history, 0, sizeof(uint32_t) * self->history_size);
memset(self->far_bit_counts, 0, sizeof(int) * self->history_size);
}
void WebRtc_SoftResetBinaryDelayEstimatorFarend(
- BinaryDelayEstimatorFarend* self, int delay_shift) {
+ BinaryDelayEstimatorFarend* self,
+ int delay_shift) {
int abs_shift = abs(delay_shift);
int shift_size = 0;
int dest_index = 0;
int src_index = 0;
int padding_index = 0;
- assert(self != NULL);
+ RTC_DCHECK(self);
shift_size = self->history_size - abs_shift;
- assert(shift_size > 0);
+ RTC_DCHECK_GT(shift_size, 0);
if (delay_shift == 0) {
return;
} else if (delay_shift > 0) {
@@ -351,8 +364,7 @@ void WebRtc_SoftResetBinaryDelayEstimatorFarend(
sizeof(*self->binary_far_history) * shift_size);
memset(&self->binary_far_history[padding_index], 0,
sizeof(*self->binary_far_history) * abs_shift);
- memmove(&self->far_bit_counts[dest_index],
- &self->far_bit_counts[src_index],
+ memmove(&self->far_bit_counts[dest_index], &self->far_bit_counts[src_index],
sizeof(*self->far_bit_counts) * shift_size);
memset(&self->far_bit_counts[padding_index], 0,
sizeof(*self->far_bit_counts) * abs_shift);
@@ -360,7 +372,7 @@ void WebRtc_SoftResetBinaryDelayEstimatorFarend(
void WebRtc_AddBinaryFarSpectrum(BinaryDelayEstimatorFarend* handle,
uint32_t binary_far_spectrum) {
- assert(handle != NULL);
+ RTC_DCHECK(handle);
// Shift binary spectrum history and insert current |binary_far_spectrum|.
memmove(&(handle->binary_far_history[1]), &(handle->binary_far_history[0]),
(handle->history_size - 1) * sizeof(uint32_t));
@@ -374,7 +386,6 @@ void WebRtc_AddBinaryFarSpectrum(BinaryDelayEstimatorFarend* handle,
}
void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self) {
-
if (self == NULL) {
return;
}
@@ -399,12 +410,14 @@ void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self) {
}
BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(
- BinaryDelayEstimatorFarend* farend, int max_lookahead) {
+ BinaryDelayEstimatorFarend* farend,
+ int max_lookahead) {
BinaryDelayEstimator* self = NULL;
if ((farend != NULL) && (max_lookahead >= 0)) {
// Sanity conditions fulfilled.
- self = malloc(sizeof(BinaryDelayEstimator));
+ self = static_cast<BinaryDelayEstimator*>(
+ malloc(sizeof(BinaryDelayEstimator)));
}
if (self == NULL) {
return NULL;
@@ -422,8 +435,8 @@ BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(
self->mean_bit_counts = NULL;
self->bit_counts = NULL;
self->histogram = NULL;
- self->binary_near_history =
- malloc((max_lookahead + 1) * sizeof(*self->binary_near_history));
+ self->binary_near_history = static_cast<uint32_t*>(
+ malloc((max_lookahead + 1) * sizeof(*self->binary_near_history)));
if (self->binary_near_history == NULL ||
WebRtc_AllocateHistoryBufferMemory(self, farend->history_size) == 0) {
WebRtc_FreeBinaryDelayEstimator(self);
@@ -444,30 +457,26 @@ int WebRtc_AllocateHistoryBufferMemory(BinaryDelayEstimator* self,
// The extra array element in |mean_bit_counts| and |histogram| is a dummy
// element only used while |last_delay| == -2, i.e., before we have a valid
// estimate.
- self->mean_bit_counts =
+ self->mean_bit_counts = static_cast<int32_t*>(
realloc(self->mean_bit_counts,
- (history_size + 1) * sizeof(*self->mean_bit_counts));
- self->bit_counts =
- realloc(self->bit_counts, history_size * sizeof(*self->bit_counts));
- self->histogram =
- realloc(self->histogram, (history_size + 1) * sizeof(*self->histogram));
-
- if ((self->mean_bit_counts == NULL) ||
- (self->bit_counts == NULL) ||
+ (history_size + 1) * sizeof(*self->mean_bit_counts)));
+ self->bit_counts = static_cast<int32_t*>(
+ realloc(self->bit_counts, history_size * sizeof(*self->bit_counts)));
+ self->histogram = static_cast<float*>(
+ realloc(self->histogram, (history_size + 1) * sizeof(*self->histogram)));
+
+ if ((self->mean_bit_counts == NULL) || (self->bit_counts == NULL) ||
(self->histogram == NULL)) {
history_size = 0;
}
// Fill with zeros if we have expanded the buffers.
if (history_size > self->history_size) {
int size_diff = history_size - self->history_size;
- memset(&self->mean_bit_counts[self->history_size],
- 0,
+ memset(&self->mean_bit_counts[self->history_size], 0,
sizeof(*self->mean_bit_counts) * size_diff);
- memset(&self->bit_counts[self->history_size],
- 0,
+ memset(&self->bit_counts[self->history_size], 0,
sizeof(*self->bit_counts) * size_diff);
- memset(&self->histogram[self->history_size],
- 0,
+ memset(&self->histogram[self->history_size], 0,
sizeof(*self->histogram) * size_diff);
}
self->history_size = history_size;
@@ -477,18 +486,17 @@ int WebRtc_AllocateHistoryBufferMemory(BinaryDelayEstimator* self,
void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* self) {
int i = 0;
- assert(self != NULL);
+ RTC_DCHECK(self);
memset(self->bit_counts, 0, sizeof(int32_t) * self->history_size);
- memset(self->binary_near_history,
- 0,
+ memset(self->binary_near_history, 0,
sizeof(uint32_t) * self->near_history_size);
for (i = 0; i <= self->history_size; ++i) {
self->mean_bit_counts[i] = (20 << 9); // 20 in Q9.
self->histogram[i] = 0.f;
}
- self->minimum_probability = kMaxBitCountsQ9; // 32 in Q9.
- self->last_delay_probability = (int) kMaxBitCountsQ9; // 32 in Q9.
+ self->minimum_probability = kMaxBitCountsQ9; // 32 in Q9.
+ self->last_delay_probability = (int)kMaxBitCountsQ9; // 32 in Q9.
// Default return value if we're unable to estimate. -1 is used for errors.
self->last_delay = -2;
@@ -502,7 +510,7 @@ void WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* self) {
int WebRtc_SoftResetBinaryDelayEstimator(BinaryDelayEstimator* self,
int delay_shift) {
int lookahead = 0;
- assert(self != NULL);
+ RTC_DCHECK(self);
lookahead = self->lookahead;
self->lookahead -= delay_shift;
if (self->lookahead < 0) {
@@ -524,7 +532,7 @@ int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* self,
int32_t value_worst_candidate = 0;
int32_t valley_depth = 0;
- assert(self != NULL);
+ RTC_DCHECK(self);
if (self->farend->history_size != self->history_size) {
// Non matching history sizes.
return -1;
@@ -612,22 +620,36 @@ int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* self,
// and deeper than the best estimate so far
// (|value_best_candidate| < |last_delay_probability|)
valid_candidate = ((valley_depth > kProbabilityOffset) &&
- ((value_best_candidate < self->minimum_probability) ||
- (value_best_candidate < self->last_delay_probability)));
+ ((value_best_candidate < self->minimum_probability) ||
+ (value_best_candidate < self->last_delay_probability)));
+
+ // Check for nonstationary farend signal.
+ const bool non_stationary_farend =
+ std::any_of(self->farend->far_bit_counts,
+ self->farend->far_bit_counts + self->history_size,
+ [](int a) { return a > 0; });
+
+ if (non_stationary_farend) {
+ // Only update the validation statistics when the farend is nonstationary
+ // as the underlying estimates are otherwise frozen.
+ UpdateRobustValidationStatistics(self, candidate_delay, valley_depth,
+ value_best_candidate);
+ }
- UpdateRobustValidationStatistics(self, candidate_delay, valley_depth,
- value_best_candidate);
if (self->robust_validation_enabled) {
int is_histogram_valid = HistogramBasedValidation(self, candidate_delay);
valid_candidate = RobustValidation(self, candidate_delay, valid_candidate,
is_histogram_valid);
-
}
- if (valid_candidate) {
+
+ // Only update the delay estimate when the farend is nonstationary and when
+ // a valid delay candidate is available.
+ if (non_stationary_farend && valid_candidate) {
if (candidate_delay != self->last_delay) {
self->last_delay_histogram =
- (self->histogram[candidate_delay] > kLastHistogramMax ?
- kLastHistogramMax : self->histogram[candidate_delay]);
+ (self->histogram[candidate_delay] > kLastHistogramMax
+ ? kLastHistogramMax
+ : self->histogram[candidate_delay]);
// Adjust the histogram if we made a change to |last_delay|, though it was
// not the most likely one according to the histogram.
if (self->histogram[candidate_delay] <
@@ -646,13 +668,13 @@ int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* self,
}
int WebRtc_binary_last_delay(BinaryDelayEstimator* self) {
- assert(self != NULL);
+ RTC_DCHECK(self);
return self->last_delay;
}
float WebRtc_binary_last_delay_quality(BinaryDelayEstimator* self) {
float quality = 0;
- assert(self != NULL);
+ RTC_DCHECK(self);
if (self->robust_validation_enabled) {
// Simply a linear function of the histogram height at delay estimate.
@@ -660,8 +682,8 @@ float WebRtc_binary_last_delay_quality(BinaryDelayEstimator* self) {
} else {
// Note that |last_delay_probability| states how deep the minimum of the
// cost function is, so it is rather an error probability.
- quality = (float) (kMaxBitCountsQ9 - self->last_delay_probability) /
- kMaxBitCountsQ9;
+ quality = (float)(kMaxBitCountsQ9 - self->last_delay_probability) /
+ kMaxBitCountsQ9;
if (quality < 0) {
quality = 0;
}
@@ -682,3 +704,5 @@ void WebRtc_MeanEstimatorFix(int32_t new_value,
}
*mean_value += diff;
}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/utility/delay_estimator.h b/webrtc/modules/audio_processing/utility/delay_estimator.h
index 65c3f03..df281bc 100644
--- a/webrtc/modules/audio_processing/utility/delay_estimator.h
+++ b/webrtc/modules/audio_processing/utility/delay_estimator.h
@@ -11,10 +11,12 @@
// Performs delay estimation on binary converted spectra.
// The return value is 0 - OK and -1 - Error, unless otherwise stated.
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
+#ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
-#include "webrtc/typedefs.h"
+#include <stdint.h>
+
+namespace webrtc {
static const int32_t kMaxBitCountsQ9 = (32 << 9); // 32 matching bits in Q9.
@@ -117,7 +119,8 @@ void WebRtc_InitBinaryDelayEstimatorFarend(BinaryDelayEstimatorFarend* self);
// - delay_shift : The amount of blocks to shift history buffers.
//
void WebRtc_SoftResetBinaryDelayEstimatorFarend(
- BinaryDelayEstimatorFarend* self, int delay_shift);
+ BinaryDelayEstimatorFarend* self,
+ int delay_shift);
// Adds the binary far-end spectrum to the internal far-end history buffer. This
// spectrum is used as reference when calculating the delay using
@@ -153,7 +156,8 @@ void WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* self);
// See WebRtc_CreateDelayEstimator(..) in delay_estimator_wrapper.c for detailed
// description.
BinaryDelayEstimator* WebRtc_CreateBinaryDelayEstimator(
- BinaryDelayEstimatorFarend* farend, int max_lookahead);
+ BinaryDelayEstimatorFarend* farend,
+ int max_lookahead);
// Re-allocates |history_size| dependent buffers. The far-end buffers will be
// updated at the same time if needed.
@@ -248,4 +252,6 @@ void WebRtc_MeanEstimatorFix(int32_t new_value,
int factor,
int32_t* mean_value);
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_
diff --git a/webrtc/modules/audio_processing/utility/delay_estimator_internal.h b/webrtc/modules/audio_processing/utility/delay_estimator_internal.h
index fd11028..fce95d8 100644
--- a/webrtc/modules/audio_processing/utility/delay_estimator_internal.h
+++ b/webrtc/modules/audio_processing/utility/delay_estimator_internal.h
@@ -10,11 +10,12 @@
// Header file including the delay estimator handle used for testing.
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
+#ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
-#include "webrtc/modules/audio_processing/utility/delay_estimator.h"
-#include "webrtc/typedefs.h"
+#include "modules/audio_processing/utility/delay_estimator.h"
+
+namespace webrtc {
typedef union {
float float_;
@@ -45,4 +46,6 @@ typedef struct {
BinaryDelayEstimator* binary_handle;
} DelayEstimator;
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_INTERNAL_H_
diff --git a/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.c b/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc
index b5448bc..8eac2f6 100644
--- a/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.c
+++ b/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc
@@ -8,15 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
+#include "modules/audio_processing/utility/delay_estimator_wrapper.h"
-#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "webrtc/modules/audio_processing/utility/delay_estimator.h"
-#include "webrtc/modules/audio_processing/utility/delay_estimator_internal.h"
-#include "webrtc/system_wrappers/include/compile_assert_c.h"
+#include "modules/audio_processing/utility/delay_estimator.h"
+#include "modules/audio_processing/utility/delay_estimator_internal.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
// Only bit |kBandFirst| through bit |kBandLast| are processed and
// |kBandFirst| - |kBandLast| must be < 32.
@@ -43,7 +44,7 @@ static __inline uint32_t SetBit(uint32_t in, int pos) {
static void MeanEstimatorFloat(float new_value,
float scale,
float* mean_value) {
- assert(scale < 1.0f);
+ RTC_DCHECK_LT(scale, 1.0f);
*mean_value += (new_value - *mean_value) * scale;
}
@@ -65,7 +66,7 @@ static uint32_t BinarySpectrumFix(const uint16_t* spectrum,
int i = kBandFirst;
uint32_t out = 0;
- assert(q_domain < 16);
+ RTC_DCHECK_LT(q_domain, 16);
if (!(*threshold_initialized)) {
// Set the |threshold_spectrum| to half the input |spectrum| as starting
@@ -73,7 +74,7 @@ static uint32_t BinarySpectrumFix(const uint16_t* spectrum,
for (i = kBandFirst; i <= kBandLast; i++) {
if (spectrum[i] > 0) {
// Convert input spectrum from Q(|q_domain|) to Q15.
- int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain);
+ int32_t spectrum_q15 = ((int32_t)spectrum[i]) << (15 - q_domain);
threshold_spectrum[i].int32_ = (spectrum_q15 >> 1);
*threshold_initialized = 1;
}
@@ -81,7 +82,7 @@ static uint32_t BinarySpectrumFix(const uint16_t* spectrum,
}
for (i = kBandFirst; i <= kBandLast; i++) {
// Convert input spectrum from Q(|q_domain|) to Q15.
- int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain);
+ int32_t spectrum_q15 = ((int32_t)spectrum[i]) << (15 - q_domain);
// Update the |threshold_spectrum|.
WebRtc_MeanEstimatorFix(spectrum_q15, 6, &(threshold_spectrum[i].int32_));
// Convert |spectrum| at current frequency bin to a binary value.
@@ -124,7 +125,7 @@ static uint32_t BinarySpectrumFloat(const float* spectrum,
}
void WebRtc_FreeDelayEstimatorFarend(void* handle) {
- DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+ DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
if (handle == NULL) {
return;
@@ -144,10 +145,11 @@ void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size) {
// Check if the sub band used in the delay estimation is small enough to fit
// the binary spectra in a uint32_t.
- COMPILE_ASSERT(kBandLast - kBandFirst < 32);
+ static_assert(kBandLast - kBandFirst < 32, "");
if (spectrum_size >= kBandLast) {
- self = malloc(sizeof(DelayEstimatorFarend));
+ self = static_cast<DelayEstimatorFarend*>(
+ malloc(sizeof(DelayEstimatorFarend)));
}
if (self != NULL) {
@@ -158,7 +160,8 @@ void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size) {
memory_fail |= (self->binary_farend == NULL);
// Allocate memory for spectrum buffers.
- self->mean_far_spectrum = malloc(spectrum_size * sizeof(SpectrumType));
+ self->mean_far_spectrum = static_cast<SpectrumType*>(
+ malloc(spectrum_size * sizeof(SpectrumType)));
memory_fail |= (self->mean_far_spectrum == NULL);
self->spectrum_size = spectrum_size;
@@ -173,7 +176,7 @@ void* WebRtc_CreateDelayEstimatorFarend(int spectrum_size, int history_size) {
}
int WebRtc_InitDelayEstimatorFarend(void* handle) {
- DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+ DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
if (self == NULL) {
return -1;
@@ -192,8 +195,8 @@ int WebRtc_InitDelayEstimatorFarend(void* handle) {
}
void WebRtc_SoftResetDelayEstimatorFarend(void* handle, int delay_shift) {
- DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
- assert(self != NULL);
+ DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
+ RTC_DCHECK(self);
WebRtc_SoftResetBinaryDelayEstimatorFarend(self->binary_farend, delay_shift);
}
@@ -201,7 +204,7 @@ int WebRtc_AddFarSpectrumFix(void* handle,
const uint16_t* far_spectrum,
int spectrum_size,
int far_q) {
- DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+ DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
uint32_t binary_spectrum = 0;
if (self == NULL) {
@@ -231,7 +234,7 @@ int WebRtc_AddFarSpectrumFix(void* handle,
int WebRtc_AddFarSpectrumFloat(void* handle,
const float* far_spectrum,
int spectrum_size) {
- DelayEstimatorFarend* self = (DelayEstimatorFarend*) handle;
+ DelayEstimatorFarend* self = (DelayEstimatorFarend*)handle;
uint32_t binary_spectrum = 0;
if (self == NULL) {
@@ -255,7 +258,7 @@ int WebRtc_AddFarSpectrumFloat(void* handle,
}
void WebRtc_FreeDelayEstimator(void* handle) {
- DelayEstimator* self = (DelayEstimator*) handle;
+ DelayEstimator* self = (DelayEstimator*)handle;
if (handle == NULL) {
return;
@@ -272,10 +275,10 @@ void WebRtc_FreeDelayEstimator(void* handle) {
void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead) {
DelayEstimator* self = NULL;
- DelayEstimatorFarend* farend = (DelayEstimatorFarend*) farend_handle;
+ DelayEstimatorFarend* farend = (DelayEstimatorFarend*)farend_handle;
if (farend_handle != NULL) {
- self = malloc(sizeof(DelayEstimator));
+ self = static_cast<DelayEstimator*>(malloc(sizeof(DelayEstimator)));
}
if (self != NULL) {
@@ -287,8 +290,8 @@ void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead) {
memory_fail |= (self->binary_handle == NULL);
// Allocate memory for spectrum buffers.
- self->mean_near_spectrum = malloc(farend->spectrum_size *
- sizeof(SpectrumType));
+ self->mean_near_spectrum = static_cast<SpectrumType*>(
+ malloc(farend->spectrum_size * sizeof(SpectrumType)));
memory_fail |= (self->mean_near_spectrum == NULL);
self->spectrum_size = farend->spectrum_size;
@@ -303,7 +306,7 @@ void* WebRtc_CreateDelayEstimator(void* farend_handle, int max_lookahead) {
}
int WebRtc_InitDelayEstimator(void* handle) {
- DelayEstimator* self = (DelayEstimator*) handle;
+ DelayEstimator* self = (DelayEstimator*)handle;
if (self == NULL) {
return -1;
@@ -322,13 +325,13 @@ int WebRtc_InitDelayEstimator(void* handle) {
}
int WebRtc_SoftResetDelayEstimator(void* handle, int delay_shift) {
- DelayEstimator* self = (DelayEstimator*) handle;
- assert(self != NULL);
+ DelayEstimator* self = (DelayEstimator*)handle;
+ RTC_DCHECK(self);
return WebRtc_SoftResetBinaryDelayEstimator(self->binary_handle, delay_shift);
}
int WebRtc_set_history_size(void* handle, int history_size) {
- DelayEstimator* self = handle;
+ DelayEstimator* self = static_cast<DelayEstimator*>(handle);
if ((self == NULL) || (history_size <= 1)) {
return -1;
@@ -337,7 +340,7 @@ int WebRtc_set_history_size(void* handle, int history_size) {
}
int WebRtc_history_size(const void* handle) {
- const DelayEstimator* self = handle;
+ const DelayEstimator* self = static_cast<const DelayEstimator*>(handle);
if (self == NULL) {
return -1;
@@ -351,9 +354,9 @@ int WebRtc_history_size(const void* handle) {
}
int WebRtc_set_lookahead(void* handle, int lookahead) {
- DelayEstimator* self = (DelayEstimator*) handle;
- assert(self != NULL);
- assert(self->binary_handle != NULL);
+ DelayEstimator* self = (DelayEstimator*)handle;
+ RTC_DCHECK(self);
+ RTC_DCHECK(self->binary_handle);
if ((lookahead > self->binary_handle->near_history_size - 1) ||
(lookahead < 0)) {
return -1;
@@ -363,14 +366,14 @@ int WebRtc_set_lookahead(void* handle, int lookahead) {
}
int WebRtc_lookahead(void* handle) {
- DelayEstimator* self = (DelayEstimator*) handle;
- assert(self != NULL);
- assert(self->binary_handle != NULL);
+ DelayEstimator* self = (DelayEstimator*)handle;
+ RTC_DCHECK(self);
+ RTC_DCHECK(self->binary_handle);
return self->binary_handle->lookahead;
}
int WebRtc_set_allowed_offset(void* handle, int allowed_offset) {
- DelayEstimator* self = (DelayEstimator*) handle;
+ DelayEstimator* self = (DelayEstimator*)handle;
if ((self == NULL) || (allowed_offset < 0)) {
return -1;
@@ -380,7 +383,7 @@ int WebRtc_set_allowed_offset(void* handle, int allowed_offset) {
}
int WebRtc_get_allowed_offset(const void* handle) {
- const DelayEstimator* self = (const DelayEstimator*) handle;
+ const DelayEstimator* self = (const DelayEstimator*)handle;
if (self == NULL) {
return -1;
@@ -389,7 +392,7 @@ int WebRtc_get_allowed_offset(const void* handle) {
}
int WebRtc_enable_robust_validation(void* handle, int enable) {
- DelayEstimator* self = (DelayEstimator*) handle;
+ DelayEstimator* self = (DelayEstimator*)handle;
if (self == NULL) {
return -1;
@@ -397,13 +400,13 @@ int WebRtc_enable_robust_validation(void* handle, int enable) {
if ((enable < 0) || (enable > 1)) {
return -1;
}
- assert(self->binary_handle != NULL);
+ RTC_DCHECK(self->binary_handle);
self->binary_handle->robust_validation_enabled = enable;
return 0;
}
int WebRtc_is_robust_validation_enabled(const void* handle) {
- const DelayEstimator* self = (const DelayEstimator*) handle;
+ const DelayEstimator* self = (const DelayEstimator*)handle;
if (self == NULL) {
return -1;
@@ -415,7 +418,7 @@ int WebRtc_DelayEstimatorProcessFix(void* handle,
const uint16_t* near_spectrum,
int spectrum_size,
int near_q) {
- DelayEstimator* self = (DelayEstimator*) handle;
+ DelayEstimator* self = (DelayEstimator*)handle;
uint32_t binary_spectrum = 0;
if (self == NULL) {
@@ -435,10 +438,9 @@ int WebRtc_DelayEstimatorProcessFix(void* handle,
}
// Get binary spectra.
- binary_spectrum = BinarySpectrumFix(near_spectrum,
- self->mean_near_spectrum,
- near_q,
- &(self->near_spectrum_initialized));
+ binary_spectrum =
+ BinarySpectrumFix(near_spectrum, self->mean_near_spectrum, near_q,
+ &(self->near_spectrum_initialized));
return WebRtc_ProcessBinarySpectrum(self->binary_handle, binary_spectrum);
}
@@ -446,7 +448,7 @@ int WebRtc_DelayEstimatorProcessFix(void* handle,
int WebRtc_DelayEstimatorProcessFloat(void* handle,
const float* near_spectrum,
int spectrum_size) {
- DelayEstimator* self = (DelayEstimator*) handle;
+ DelayEstimator* self = (DelayEstimator*)handle;
uint32_t binary_spectrum = 0;
if (self == NULL) {
@@ -469,7 +471,7 @@ int WebRtc_DelayEstimatorProcessFloat(void* handle,
}
int WebRtc_last_delay(void* handle) {
- DelayEstimator* self = (DelayEstimator*) handle;
+ DelayEstimator* self = (DelayEstimator*)handle;
if (self == NULL) {
return -1;
@@ -479,7 +481,9 @@ int WebRtc_last_delay(void* handle) {
}
float WebRtc_last_delay_quality(void* handle) {
- DelayEstimator* self = (DelayEstimator*) handle;
- assert(self != NULL);
+ DelayEstimator* self = (DelayEstimator*)handle;
+ RTC_DCHECK(self);
return WebRtc_binary_last_delay_quality(self->binary_handle);
}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h b/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h
index fdadebe..dbcafaf 100644
--- a/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h
+++ b/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h
@@ -11,10 +11,12 @@
// Performs delay estimation on block by block basis.
// The return value is 0 - OK and -1 - Error, unless otherwise stated.
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
+#ifndef MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
-#include "webrtc/typedefs.h"
+#include <stdint.h>
+
+namespace webrtc {
// Releases the memory allocated by WebRtc_CreateDelayEstimatorFarend(...)
void WebRtc_FreeDelayEstimatorFarend(void* handle);
@@ -241,4 +243,6 @@ int WebRtc_last_delay(void* handle);
// - delay_quality : >= 0 - Estimation quality of last calculated delay.
float WebRtc_last_delay_quality(void* handle);
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_
diff --git a/webrtc/modules/audio_processing/utility/pffft_wrapper.cc b/webrtc/modules/audio_processing/utility/pffft_wrapper.cc
new file mode 100644
index 0000000..88642fb
--- /dev/null
+++ b/webrtc/modules/audio_processing/utility/pffft_wrapper.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/utility/pffft_wrapper.h"
+
+#include "rtc_base/checks.h"
+#include "third_party/pffft/src/pffft.h"
+
+namespace webrtc {
+namespace {
+
+size_t GetBufferSize(size_t fft_size, Pffft::FftType fft_type) {
+ return fft_size * (fft_type == Pffft::FftType::kReal ? 1 : 2);
+}
+
+float* AllocatePffftBuffer(size_t size) {
+ return static_cast<float*>(pffft_aligned_malloc(size * sizeof(float)));
+}
+
+} // namespace
+
+Pffft::FloatBuffer::FloatBuffer(size_t fft_size, FftType fft_type)
+ : size_(GetBufferSize(fft_size, fft_type)),
+ data_(AllocatePffftBuffer(size_)) {}
+
+Pffft::FloatBuffer::~FloatBuffer() {
+ pffft_aligned_free(data_);
+}
+
+rtc::ArrayView<const float> Pffft::FloatBuffer::GetConstView() const {
+ return {data_, size_};
+}
+
+rtc::ArrayView<float> Pffft::FloatBuffer::GetView() {
+ return {data_, size_};
+}
+
+Pffft::Pffft(size_t fft_size, FftType fft_type)
+ : fft_size_(fft_size),
+ fft_type_(fft_type),
+ pffft_status_(pffft_new_setup(
+ fft_size_,
+ fft_type == Pffft::FftType::kReal ? PFFFT_REAL : PFFFT_COMPLEX)),
+ scratch_buffer_(
+ AllocatePffftBuffer(GetBufferSize(fft_size_, fft_type_))) {
+ RTC_DCHECK(pffft_status_);
+ RTC_DCHECK(scratch_buffer_);
+}
+
+Pffft::~Pffft() {
+ pffft_destroy_setup(pffft_status_);
+ pffft_aligned_free(scratch_buffer_);
+}
+
+bool Pffft::IsValidFftSize(size_t fft_size, FftType fft_type) {
+ if (fft_size == 0) {
+ return false;
+ }
+ // PFFFT only supports transforms for inputs of length N of the form
+ // N = (2^a)*(3^b)*(5^c) where b >=0 and c >= 0 and a >= 5 for the real FFT
+ // and a >= 4 for the complex FFT.
+ constexpr int kFactors[] = {2, 3, 5};
+ int factorization[] = {0, 0, 0};
+ int n = static_cast<int>(fft_size);
+ for (int i = 0; i < 3; ++i) {
+ while (n % kFactors[i] == 0) {
+ n = n / kFactors[i];
+ factorization[i]++;
+ }
+ }
+ int a_min = (fft_type == Pffft::FftType::kReal) ? 5 : 4;
+ return factorization[0] >= a_min && n == 1;
+}
+
+bool Pffft::IsSimdEnabled() {
+ return pffft_simd_size() > 1;
+}
+
+std::unique_ptr<Pffft::FloatBuffer> Pffft::CreateBuffer() const {
+ // Cannot use make_unique from absl because Pffft is the only friend of
+ // Pffft::FloatBuffer.
+ std::unique_ptr<Pffft::FloatBuffer> buffer(
+ new Pffft::FloatBuffer(fft_size_, fft_type_));
+ return buffer;
+}
+
+void Pffft::ForwardTransform(const FloatBuffer& in,
+ FloatBuffer* out,
+ bool ordered) {
+ RTC_DCHECK_EQ(in.size(), GetBufferSize(fft_size_, fft_type_));
+ RTC_DCHECK_EQ(in.size(), out->size());
+ RTC_DCHECK(scratch_buffer_);
+ if (ordered) {
+ pffft_transform_ordered(pffft_status_, in.const_data(), out->data(),
+ scratch_buffer_, PFFFT_FORWARD);
+ } else {
+ pffft_transform(pffft_status_, in.const_data(), out->data(),
+ scratch_buffer_, PFFFT_FORWARD);
+ }
+}
+
+void Pffft::BackwardTransform(const FloatBuffer& in,
+ FloatBuffer* out,
+ bool ordered) {
+ RTC_DCHECK_EQ(in.size(), GetBufferSize(fft_size_, fft_type_));
+ RTC_DCHECK_EQ(in.size(), out->size());
+ RTC_DCHECK(scratch_buffer_);
+ if (ordered) {
+ pffft_transform_ordered(pffft_status_, in.const_data(), out->data(),
+ scratch_buffer_, PFFFT_BACKWARD);
+ } else {
+ pffft_transform(pffft_status_, in.const_data(), out->data(),
+ scratch_buffer_, PFFFT_BACKWARD);
+ }
+}
+
+void Pffft::FrequencyDomainConvolve(const FloatBuffer& fft_x,
+ const FloatBuffer& fft_y,
+ FloatBuffer* out,
+ float scaling) {
+ RTC_DCHECK_EQ(fft_x.size(), GetBufferSize(fft_size_, fft_type_));
+ RTC_DCHECK_EQ(fft_x.size(), fft_y.size());
+ RTC_DCHECK_EQ(fft_x.size(), out->size());
+ pffft_zconvolve_accumulate(pffft_status_, fft_x.const_data(),
+ fft_y.const_data(), out->data(), scaling);
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/utility/pffft_wrapper.h b/webrtc/modules/audio_processing/utility/pffft_wrapper.h
new file mode 100644
index 0000000..160f0da
--- /dev/null
+++ b/webrtc/modules/audio_processing/utility/pffft_wrapper.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
+#define MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
+
+#include <memory>
+
+#include "api/array_view.h"
+
+// Forward declaration.
+struct PFFFT_Setup;
+
+namespace webrtc {
+
+// Pretty-Fast Fast Fourier Transform (PFFFT) wrapper class.
+// Not thread safe.
+class Pffft {
+ public:
+ enum class FftType { kReal, kComplex };
+
+ // 1D floating point buffer used as input/output data type for the FFT ops.
+ // It must be constructed using Pffft::CreateBuffer().
+ class FloatBuffer {
+ public:
+ FloatBuffer(const FloatBuffer&) = delete;
+ FloatBuffer& operator=(const FloatBuffer&) = delete;
+ ~FloatBuffer();
+
+ rtc::ArrayView<const float> GetConstView() const;
+ rtc::ArrayView<float> GetView();
+
+ private:
+ friend class Pffft;
+ FloatBuffer(size_t fft_size, FftType fft_type);
+ const float* const_data() const { return data_; }
+ float* data() { return data_; }
+ size_t size() const { return size_; }
+
+ const size_t size_;
+ float* const data_;
+ };
+
+ // TODO(https://crbug.com/webrtc/9577): Consider adding a factory and making
+ // the ctor private.
+ // static std::unique_ptr<Pffft> Create(size_t fft_size,
+ // FftType fft_type); Ctor. |fft_size| must be a supported size (see
+ // Pffft::IsValidFftSize()). If not supported, the code will crash.
+ Pffft(size_t fft_size, FftType fft_type);
+ Pffft(const Pffft&) = delete;
+ Pffft& operator=(const Pffft&) = delete;
+ ~Pffft();
+
+ // Returns true if the FFT size is supported.
+ static bool IsValidFftSize(size_t fft_size, FftType fft_type);
+
+ // Returns true if SIMD code optimizations are being used.
+ static bool IsSimdEnabled();
+
+ // Creates a buffer of the right size.
+ std::unique_ptr<FloatBuffer> CreateBuffer() const;
+
+ // TODO(https://crbug.com/webrtc/9577): Overload with rtc::ArrayView args.
+ // Computes the forward fast Fourier transform.
+ void ForwardTransform(const FloatBuffer& in, FloatBuffer* out, bool ordered);
+ // Computes the backward fast Fourier transform.
+ void BackwardTransform(const FloatBuffer& in, FloatBuffer* out, bool ordered);
+
+ // Multiplies the frequency components of |fft_x| and |fft_y| and accumulates
+ // them into |out|. The arrays must have been obtained with
+ // ForwardTransform(..., /*ordered=*/false) - i.e., |fft_x| and |fft_y| must
+ // not be ordered.
+ void FrequencyDomainConvolve(const FloatBuffer& fft_x,
+ const FloatBuffer& fft_y,
+ FloatBuffer* out,
+ float scaling = 1.f);
+
+ private:
+ const size_t fft_size_;
+ const FftType fft_type_;
+ PFFFT_Setup* pffft_status_;
+ float* const scratch_buffer_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_UTILITY_PFFFT_WRAPPER_H_
diff --git a/webrtc/modules/audio_processing/vad/BUILD.gn b/webrtc/modules/audio_processing/vad/BUILD.gn
new file mode 100644
index 0000000..71e079d
--- /dev/null
+++ b/webrtc/modules/audio_processing/vad/BUILD.gn
@@ -0,0 +1,69 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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_library("vad") {
+ visibility = [
+ "../*",
+ "../../../rtc_tools:*",
+ ]
+ sources = [
+ "common.h",
+ "gmm.cc",
+ "gmm.h",
+ "noise_gmm_tables.h",
+ "pitch_based_vad.cc",
+ "pitch_based_vad.h",
+ "pitch_internal.cc",
+ "pitch_internal.h",
+ "pole_zero_filter.cc",
+ "pole_zero_filter.h",
+ "standalone_vad.cc",
+ "standalone_vad.h",
+ "vad_audio_proc.cc",
+ "vad_audio_proc.h",
+ "vad_audio_proc_internal.h",
+ "vad_circular_buffer.cc",
+ "vad_circular_buffer.h",
+ "voice_activity_detector.cc",
+ "voice_activity_detector.h",
+ "voice_gmm_tables.h",
+ ]
+ deps = [
+ "../../../audio/utility:audio_frame_operations",
+ "../../../common_audio",
+ "../../../common_audio:common_audio_c",
+ "../../../common_audio/third_party/ooura:fft_size_256",
+ "../../../rtc_base:checks",
+ "../../audio_coding:isac_vad",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("vad_unittests") {
+ testonly = true
+ sources = [
+ "gmm_unittest.cc",
+ "pitch_based_vad_unittest.cc",
+ "pitch_internal_unittest.cc",
+ "pole_zero_filter_unittest.cc",
+ "standalone_vad_unittest.cc",
+ "vad_audio_proc_unittest.cc",
+ "vad_circular_buffer_unittest.cc",
+ "voice_activity_detector_unittest.cc",
+ ]
+ deps = [
+ ":vad",
+ "../../../common_audio",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+ }
+}
diff --git a/webrtc/modules/audio_processing/vad/common.h b/webrtc/modules/audio_processing/vad/common.h
index be99c1c..b5a5fb3 100644
--- a/webrtc/modules/audio_processing/vad/common.h
+++ b/webrtc/modules/audio_processing/vad/common.h
@@ -8,8 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_COMMON_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_COMMON_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_VAD_COMMON_H_
+
+#include <stddef.h>
static const int kSampleRateHz = 16000;
static const size_t kLength10Ms = kSampleRateHz / 100;
@@ -24,4 +26,4 @@ struct AudioFeatures {
bool silence;
};
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_COMMON_H_
+#endif // MODULES_AUDIO_PROCESSING_VAD_COMMON_H_
diff --git a/webrtc/modules/audio_processing/vad/gmm.cc b/webrtc/modules/audio_processing/vad/gmm.cc
index 9651975..3b8764c 100644
--- a/webrtc/modules/audio_processing/vad/gmm.cc
+++ b/webrtc/modules/audio_processing/vad/gmm.cc
@@ -8,12 +8,9 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/vad/gmm.h"
+#include "modules/audio_processing/vad/gmm.h"
#include <math.h>
-#include <stdlib.h>
-
-#include "webrtc/typedefs.h"
namespace webrtc {
diff --git a/webrtc/modules/audio_processing/vad/gmm.h b/webrtc/modules/audio_processing/vad/gmm.h
index 9f3e578..93eb675 100644
--- a/webrtc/modules/audio_processing/vad/gmm.h
+++ b/webrtc/modules/audio_processing/vad/gmm.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_GMM_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_GMM_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_GMM_H_
+#define MODULES_AUDIO_PROCESSING_VAD_GMM_H_
namespace webrtc {
@@ -42,4 +42,4 @@ struct GmmParameters {
double EvaluateGmm(const double* x, const GmmParameters& gmm_parameters);
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_GMM_H_
+#endif // MODULES_AUDIO_PROCESSING_VAD_GMM_H_
diff --git a/webrtc/modules/audio_processing/vad/noise_gmm_tables.h b/webrtc/modules/audio_processing/vad/noise_gmm_tables.h
index 293af57..944a540 100644
--- a/webrtc/modules/audio_processing/vad/noise_gmm_tables.h
+++ b/webrtc/modules/audio_processing/vad/noise_gmm_tables.h
@@ -10,8 +10,10 @@
// GMM tables for inactive segments. Generated by MakeGmmTables.m.
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_
+#define MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_
+
+namespace webrtc {
static const int kNoiseGmmNumMixtures = 12;
static const int kNoiseGmmDim = 3;
@@ -70,16 +72,11 @@ static const double kNoiseGmmMean[kNoiseGmmNumMixtures][kNoiseGmmDim] = {
{-2.30193040814533e+00, 1.43953696546439e+03, 7.04085275122649e+01}};
static const double kNoiseGmmWeights[kNoiseGmmNumMixtures] = {
- -1.09422832086193e+01,
- -1.10847897513425e+01,
- -1.36767587732187e+01,
- -1.79789356118641e+01,
- -1.42830169160894e+01,
- -1.56500228061379e+01,
- -1.83124990950113e+01,
- -1.69979436177477e+01,
- -1.12329424387828e+01,
- -1.41311785780639e+01,
- -1.47171861448585e+01,
- -1.35963362781839e+01};
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_
+ -1.09422832086193e+01, -1.10847897513425e+01, -1.36767587732187e+01,
+ -1.79789356118641e+01, -1.42830169160894e+01, -1.56500228061379e+01,
+ -1.83124990950113e+01, -1.69979436177477e+01, -1.12329424387828e+01,
+ -1.41311785780639e+01, -1.47171861448585e+01, -1.35963362781839e+01};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_VAD_NOISE_GMM_TABLES_H_
diff --git a/webrtc/modules/audio_processing/vad/pitch_based_vad.cc b/webrtc/modules/audio_processing/vad/pitch_based_vad.cc
index 39ec37e..68e60dc 100644
--- a/webrtc/modules/audio_processing/vad/pitch_based_vad.cc
+++ b/webrtc/modules/audio_processing/vad/pitch_based_vad.cc
@@ -8,17 +8,14 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/vad/pitch_based_vad.h"
+#include "modules/audio_processing/vad/pitch_based_vad.h"
-#include <assert.h>
-#include <math.h>
#include <string.h>
-#include "webrtc/modules/audio_processing/vad/vad_circular_buffer.h"
-#include "webrtc/modules/audio_processing/vad/common.h"
-#include "webrtc/modules/audio_processing/vad/noise_gmm_tables.h"
-#include "webrtc/modules/audio_processing/vad/voice_gmm_tables.h"
-#include "webrtc/modules/interface/module_common_types.h"
+#include "modules/audio_processing/vad/common.h"
+#include "modules/audio_processing/vad/noise_gmm_tables.h"
+#include "modules/audio_processing/vad/vad_circular_buffer.h"
+#include "modules/audio_processing/vad/voice_gmm_tables.h"
namespace webrtc {
@@ -60,8 +57,7 @@ PitchBasedVad::PitchBasedVad()
voice_gmm_.covar_inverse = &kVoiceGmmCovarInverse[0][0][0];
}
-PitchBasedVad::~PitchBasedVad() {
-}
+PitchBasedVad::~PitchBasedVad() {}
int PitchBasedVad::VoicingProbability(const AudioFeatures& features,
double* p_combined) {
diff --git a/webrtc/modules/audio_processing/vad/pitch_based_vad.h b/webrtc/modules/audio_processing/vad/pitch_based_vad.h
index c502184..e005e23 100644
--- a/webrtc/modules/audio_processing/vad/pitch_based_vad.h
+++ b/webrtc/modules/audio_processing/vad/pitch_based_vad.h
@@ -8,17 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_
+#define MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/vad/common.h"
-#include "webrtc/modules/audio_processing/vad/gmm.h"
-#include "webrtc/typedefs.h"
+#include <memory>
+
+#include "modules/audio_processing/vad/common.h"
+#include "modules/audio_processing/vad/gmm.h"
namespace webrtc {
-class AudioFrame;
class VadCircularBuffer;
// Computes the probability of the input audio frame to be active given
@@ -50,8 +49,9 @@ class PitchBasedVad {
double p_prior_;
- rtc::scoped_ptr<VadCircularBuffer> circular_buffer_;
+ std::unique_ptr<VadCircularBuffer> circular_buffer_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_
+
+#endif // MODULES_AUDIO_PROCESSING_VAD_PITCH_BASED_VAD_H_
diff --git a/webrtc/modules/audio_processing/vad/pitch_internal.cc b/webrtc/modules/audio_processing/vad/pitch_internal.cc
index 309b45a..8f86918 100644
--- a/webrtc/modules/audio_processing/vad/pitch_internal.cc
+++ b/webrtc/modules/audio_processing/vad/pitch_internal.cc
@@ -8,10 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/vad/pitch_internal.h"
+#include "modules/audio_processing/vad/pitch_internal.h"
#include <cmath>
+namespace webrtc {
+
// A 4-to-3 linear interpolation.
// The interpolation constants are derived as following:
// Input pitch parameters are updated every 7.5 ms. Within a 30-ms interval
@@ -49,3 +51,5 @@ void GetSubframesPitchParameters(int sampling_rate_hz,
pitch_lag_hz[n] = (sampling_rate_hz) / (pitch_lag_hz[n]);
}
}
+
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/vad/pitch_internal.h b/webrtc/modules/audio_processing/vad/pitch_internal.h
index b25b1a8..938745d 100644
--- a/webrtc/modules/audio_processing/vad/pitch_internal.h
+++ b/webrtc/modules/audio_processing/vad/pitch_internal.h
@@ -8,8 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_
+#define MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_
+
+namespace webrtc {
// TODO(turajs): Write a description of this function. Also be consistent with
// usage of |sampling_rate_hz| vs |kSamplingFreqHz|.
@@ -23,4 +25,6 @@ void GetSubframesPitchParameters(int sampling_rate_hz,
double* log_pitch_gain,
double* pitch_lag_hz);
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_VAD_PITCH_INTERNAL_H_
diff --git a/webrtc/modules/audio_processing/vad/pole_zero_filter.cc b/webrtc/modules/audio_processing/vad/pole_zero_filter.cc
index 9769515..e7a6113 100644
--- a/webrtc/modules/audio_processing/vad/pole_zero_filter.cc
+++ b/webrtc/modules/audio_processing/vad/pole_zero_filter.cc
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/vad/pole_zero_filter.h"
+#include "modules/audio_processing/vad/pole_zero_filter.h"
-#include <stdlib.h>
#include <string.h>
+
#include <algorithm>
namespace webrtc {
@@ -53,7 +53,8 @@ PoleZeroFilter::PoleZeroFilter(const float* numerator_coefficients,
}
template <typename T>
-static float FilterArPast(const T* past, size_t order,
+static float FilterArPast(const T* past,
+ size_t order,
const float* coefficients) {
float sum = 0.0f;
size_t past_index = order - 1;
diff --git a/webrtc/modules/audio_processing/vad/pole_zero_filter.h b/webrtc/modules/audio_processing/vad/pole_zero_filter.h
index bd13050..11a0511 100644
--- a/webrtc/modules/audio_processing/vad/pole_zero_filter.h
+++ b/webrtc/modules/audio_processing/vad/pole_zero_filter.h
@@ -8,12 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_
-#include <cstddef>
-
-#include "webrtc/typedefs.h"
+#include <stddef.h>
+#include <stdint.h>
namespace webrtc {
@@ -49,4 +48,4 @@ class PoleZeroFilter {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_
+#endif // MODULES_AUDIO_PROCESSING_VAD_POLE_ZERO_FILTER_H_
diff --git a/webrtc/modules/audio_processing/vad/standalone_vad.cc b/webrtc/modules/audio_processing/vad/standalone_vad.cc
index 468b8ff..1397668 100644
--- a/webrtc/modules/audio_processing/vad/standalone_vad.cc
+++ b/webrtc/modules/audio_processing/vad/standalone_vad.cc
@@ -8,21 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/vad/standalone_vad.h"
+#include "modules/audio_processing/vad/standalone_vad.h"
-#include <assert.h>
+#include <string.h>
-#include "webrtc/modules/interface/module_common_types.h"
-#include "webrtc/modules/utility/interface/audio_frame_operations.h"
-#include "webrtc/typedefs.h"
+#include "common_audio/vad/include/webrtc_vad.h"
+#include "rtc_base/checks.h"
namespace webrtc {
static const int kDefaultStandaloneVadMode = 3;
StandaloneVad::StandaloneVad(VadInst* vad)
- : vad_(vad), buffer_(), index_(0), mode_(kDefaultStandaloneVadMode) {
-}
+ : vad_(vad), buffer_(), index_(0), mode_(kDefaultStandaloneVadMode) {}
StandaloneVad::~StandaloneVad() {
WebRtcVad_Free(vad_);
@@ -64,7 +62,7 @@ int StandaloneVad::GetActivity(double* p, size_t length_p) {
const size_t num_frames = index_ / kLength10Ms;
if (num_frames > length_p)
return -1;
- assert(WebRtcVad_ValidRateAndFrameLength(kSampleRateHz, index_) == 0);
+ RTC_DCHECK_EQ(0, WebRtcVad_ValidRateAndFrameLength(kSampleRateHz, index_));
int activity = WebRtcVad_Process(vad_, kSampleRateHz, buffer_, index_);
if (activity < 0)
diff --git a/webrtc/modules/audio_processing/vad/standalone_vad.h b/webrtc/modules/audio_processing/vad/standalone_vad.h
index 6a25424..3dff416 100644
--- a/webrtc/modules/audio_processing/vad/standalone_vad.h
+++ b/webrtc/modules/audio_processing/vad/standalone_vad.h
@@ -8,17 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_
+#ifndef MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_
+#define MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/vad/common.h"
-#include "webrtc/common_audio/vad/include/webrtc_vad.h"
-#include "webrtc/typedefs.h"
+#include <stddef.h>
+#include <stdint.h>
-namespace webrtc {
+#include "common_audio/vad/include/webrtc_vad.h"
+#include "modules/audio_processing/vad/common.h"
-class AudioFrame;
+namespace webrtc {
class StandaloneVad {
public:
@@ -67,4 +66,4 @@ class StandaloneVad {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_
+#endif // MODULES_AUDIO_PROCESSING_AGC_STANDALONE_VAD_H_
diff --git a/webrtc/modules/audio_processing/vad/vad_audio_proc.cc b/webrtc/modules/audio_processing/vad/vad_audio_proc.cc
index 8535d1f..97cf651 100644
--- a/webrtc/modules/audio_processing/vad/vad_audio_proc.cc
+++ b/webrtc/modules/audio_processing/vad/vad_audio_proc.cc
@@ -8,22 +8,23 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/vad/vad_audio_proc.h"
+#include "modules/audio_processing/vad/vad_audio_proc.h"
#include <math.h>
#include <stdio.h>
+#include <string.h>
-#include "webrtc/common_audio/fft4g.h"
-#include "webrtc/modules/audio_processing/vad/vad_audio_proc_internal.h"
-#include "webrtc/modules/audio_processing/vad/pitch_internal.h"
-#include "webrtc/modules/audio_processing/vad/pole_zero_filter.h"
+#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
+#include "modules/audio_processing/vad/pitch_internal.h"
+#include "modules/audio_processing/vad/pole_zero_filter.h"
+#include "modules/audio_processing/vad/vad_audio_proc_internal.h"
+#include "rtc_base/checks.h"
extern "C" {
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/codec.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
-#include "webrtc/modules/audio_coding/codecs/isac/main/source/structs.h"
+#include "modules/audio_coding/codecs/isac/main/source/filter_functions.h"
+#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
+#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
+#include "modules/audio_coding/codecs/isac/main/source/structs.h"
}
-#include "webrtc/modules/interface/module_common_types.h"
namespace webrtc {
@@ -32,9 +33,9 @@ namespace webrtc {
struct VadAudioProc::PitchAnalysisStruct : public ::PitchAnalysisStruct {};
struct VadAudioProc::PreFiltBankstr : public ::PreFiltBankstr {};
-static const float kFrequencyResolution =
+static constexpr float kFrequencyResolution =
kSampleRateHz / static_cast<float>(VadAudioProc::kDftSize);
-static const int kSilenceRms = 5;
+static constexpr int kSilenceRms = 5;
// TODO(turajs): Make a Create or Init for VadAudioProc.
VadAudioProc::VadAudioProc()
@@ -66,8 +67,7 @@ VadAudioProc::VadAudioProc()
WebRtcIsac_InitPitchAnalysis(pitch_analysis_handle_.get());
}
-VadAudioProc::~VadAudioProc() {
-}
+VadAudioProc::~VadAudioProc() {}
void VadAudioProc::ResetBuffer() {
memcpy(audio_buffer_, &audio_buffer_[kNumSamplesToProcess],
@@ -95,7 +95,7 @@ int VadAudioProc::ExtractFeatures(const int16_t* frame,
if (num_buffer_samples_ < kBufferLength) {
return 0;
}
- assert(num_buffer_samples_ == kBufferLength);
+ RTC_DCHECK_EQ(num_buffer_samples_, kBufferLength);
features->num_frames = kNum10msSubframes;
features->silence = false;
@@ -121,7 +121,7 @@ int VadAudioProc::ExtractFeatures(const int16_t* frame,
void VadAudioProc::SubframeCorrelation(double* corr,
size_t length_corr,
size_t subframe_index) {
- assert(length_corr >= kLpcOrder + 1);
+ RTC_DCHECK_GE(length_corr, kLpcOrder + 1);
double windowed_audio[kNumSubframeSamples + kNumPastSignalSamples];
size_t buffer_index = subframe_index * kNumSubframeSamples;
@@ -137,7 +137,7 @@ void VadAudioProc::SubframeCorrelation(double* corr,
// each 10ms sub-frame. This is equivalent to computing LPC coefficients for the
// first half of each 10 ms subframe.
void VadAudioProc::GetLpcPolynomials(double* lpc, size_t length_lpc) {
- assert(length_lpc >= kNum10msSubframes * (kLpcOrder + 1));
+ RTC_DCHECK_GE(length_lpc, kNum10msSubframes * (kLpcOrder + 1));
double corr[kLpcOrder + 1];
double reflec_coeff[kLpcOrder];
for (size_t i = 0, offset_lpc = 0; i < kNum10msSubframes;
@@ -165,7 +165,7 @@ static float QuadraticInterpolation(float prev_val,
fractional_index =
-(next_val - prev_val) * 0.5f / (next_val + prev_val - 2.f * curr_val);
- assert(fabs(fractional_index) < 1);
+ RTC_DCHECK_LT(fabs(fractional_index), 1);
return fractional_index;
}
@@ -176,7 +176,7 @@ static float QuadraticInterpolation(float prev_val,
// to save on one square root.
void VadAudioProc::FindFirstSpectralPeaks(double* f_peak,
size_t length_f_peak) {
- assert(length_f_peak >= kNum10msSubframes);
+ RTC_DCHECK_GE(length_f_peak, kNum10msSubframes);
double lpc[kNum10msSubframes * (kLpcOrder + 1)];
// For all sub-frames.
GetLpcPolynomials(lpc, kNum10msSubframes * (kLpcOrder + 1));
@@ -232,7 +232,7 @@ void VadAudioProc::PitchAnalysis(double* log_pitch_gains,
size_t length) {
// TODO(turajs): This can be "imported" from iSAC & and the next two
// constants.
- assert(length >= kNum10msSubframes);
+ RTC_DCHECK_GE(length, kNum10msSubframes);
const int kNumPitchSubframes = 4;
double gains[kNumPitchSubframes];
double lags[kNumPitchSubframes];
@@ -262,7 +262,7 @@ void VadAudioProc::PitchAnalysis(double* log_pitch_gains,
}
void VadAudioProc::Rms(double* rms, size_t length_rms) {
- assert(length_rms >= kNum10msSubframes);
+ RTC_DCHECK_GE(length_rms, kNum10msSubframes);
size_t offset = kNumPastSignalSamples;
for (size_t i = 0; i < kNum10msSubframes; i++) {
rms[i] = 0;
diff --git a/webrtc/modules/audio_processing/vad/vad_audio_proc.h b/webrtc/modules/audio_processing/vad/vad_audio_proc.h
index 85500ae..4a71ce3 100644
--- a/webrtc/modules/audio_processing/vad/vad_audio_proc.h
+++ b/webrtc/modules/audio_processing/vad/vad_audio_proc.h
@@ -8,16 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_
+#define MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/modules/audio_processing/vad/common.h"
-#include "webrtc/typedefs.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "modules/audio_processing/vad/common.h" // AudioFeatures, kSampleR...
namespace webrtc {
-class AudioFrame;
class PoleZeroFilter;
class VadAudioProc {
@@ -49,25 +51,28 @@ class VadAudioProc {
// For every 30 ms we compute 3 spectral peak there for 3 LPC analysis.
// LPC is computed over 15 ms of windowed audio. For every 10 ms sub-frame
// we need 5 ms of past signal to create the input of LPC analysis.
- static const size_t kNumPastSignalSamples =
- static_cast<size_t>(kSampleRateHz / 200);
+ enum : size_t {
+ kNumPastSignalSamples = static_cast<size_t>(kSampleRateHz / 200)
+ };
// TODO(turajs): maybe defining this at a higher level (maybe enum) so that
// all the code recognize it as "no-error."
- static const int kNoError = 0;
-
- static const size_t kNum10msSubframes = 3;
- static const size_t kNumSubframeSamples =
- static_cast<size_t>(kSampleRateHz / 100);
- static const size_t kNumSamplesToProcess =
- kNum10msSubframes *
- kNumSubframeSamples; // Samples in 30 ms @ given sampling rate.
- static const size_t kBufferLength =
- kNumPastSignalSamples + kNumSamplesToProcess;
- static const size_t kIpLength = kDftSize >> 1;
- static const size_t kWLength = kDftSize >> 1;
-
- static const size_t kLpcOrder = 16;
+ enum : int { kNoError = 0 };
+
+ enum : size_t { kNum10msSubframes = 3 };
+ enum : size_t {
+ kNumSubframeSamples = static_cast<size_t>(kSampleRateHz / 100)
+ };
+ enum : size_t {
+ // Samples in 30 ms @ given sampling rate.
+ kNumSamplesToProcess = kNum10msSubframes * kNumSubframeSamples
+ };
+ enum : size_t {
+ kBufferLength = kNumPastSignalSamples + kNumSamplesToProcess
+ };
+ enum : size_t { kIpLength = kDftSize >> 1 };
+ enum : size_t { kWLength = kDftSize >> 1 };
+ enum : size_t { kLpcOrder = 16 };
size_t ip_[kIpLength];
float w_fft_[kWLength];
@@ -79,11 +84,11 @@ class VadAudioProc {
double log_old_gain_;
double old_lag_;
- rtc::scoped_ptr<PitchAnalysisStruct> pitch_analysis_handle_;
- rtc::scoped_ptr<PreFiltBankstr> pre_filter_handle_;
- rtc::scoped_ptr<PoleZeroFilter> high_pass_filter_;
+ std::unique_ptr<PitchAnalysisStruct> pitch_analysis_handle_;
+ std::unique_ptr<PreFiltBankstr> pre_filter_handle_;
+ std::unique_ptr<PoleZeroFilter> high_pass_filter_;
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_
+#endif // MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_H_
diff --git a/webrtc/modules/audio_processing/vad/vad_audio_proc_internal.h b/webrtc/modules/audio_processing/vad/vad_audio_proc_internal.h
index 45586b9..915524f 100644
--- a/webrtc/modules/audio_processing/vad/vad_audio_proc_internal.h
+++ b/webrtc/modules/audio_processing/vad/vad_audio_proc_internal.h
@@ -8,29 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_INTERNAL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_INTERNAL_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_INTERNAL_H_
+#define MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROC_INTERNAL_H_
namespace webrtc {
// These values should match MATLAB counterparts for unit-tests to pass.
-static const double kCorrWeight[] = {1.000000,
- 0.985000,
- 0.970225,
- 0.955672,
- 0.941337,
- 0.927217,
- 0.913308,
- 0.899609,
- 0.886115,
- 0.872823,
- 0.859730,
- 0.846834,
- 0.834132,
- 0.821620,
- 0.809296,
- 0.797156,
- 0.785199};
+static const double kCorrWeight[] = {
+ 1.000000, 0.985000, 0.970225, 0.955672, 0.941337, 0.927217,
+ 0.913308, 0.899609, 0.886115, 0.872823, 0.859730, 0.846834,
+ 0.834132, 0.821620, 0.809296, 0.797156, 0.785199};
static const double kLpcAnalWin[] = {
0.00000000, 0.01314436, 0.02628645, 0.03942400, 0.05255473, 0.06567639,
@@ -75,11 +62,9 @@ static const double kLpcAnalWin[] = {
0.06567639, 0.05255473, 0.03942400, 0.02628645, 0.01314436, 0.00000000};
static const size_t kFilterOrder = 2;
-static const float kCoeffNumerator[kFilterOrder + 1] = {0.974827f,
- -1.949650f,
+static const float kCoeffNumerator[kFilterOrder + 1] = {0.974827f, -1.949650f,
0.974827f};
-static const float kCoeffDenominator[kFilterOrder + 1] = {1.0f,
- -1.971999f,
+static const float kCoeffDenominator[kFilterOrder + 1] = {1.0f, -1.971999f,
0.972457f};
static_assert(kFilterOrder + 1 ==
@@ -91,4 +76,4 @@ static_assert(kFilterOrder + 1 ==
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROCESSING_H_
+#endif // MODULES_AUDIO_PROCESSING_VAD_VAD_AUDIO_PROCESSING_H_
diff --git a/webrtc/modules/audio_processing/vad/vad_circular_buffer.cc b/webrtc/modules/audio_processing/vad/vad_circular_buffer.cc
index d337893..31f14d7 100644
--- a/webrtc/modules/audio_processing/vad/vad_circular_buffer.cc
+++ b/webrtc/modules/audio_processing/vad/vad_circular_buffer.cc
@@ -8,9 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/vad/vad_circular_buffer.h"
+#include "modules/audio_processing/vad/vad_circular_buffer.h"
-#include <assert.h>
#include <stdlib.h>
namespace webrtc {
@@ -20,11 +19,9 @@ VadCircularBuffer::VadCircularBuffer(int buffer_size)
is_full_(false),
index_(0),
buffer_size_(buffer_size),
- sum_(0) {
-}
+ sum_(0) {}
-VadCircularBuffer::~VadCircularBuffer() {
-}
+VadCircularBuffer::~VadCircularBuffer() {}
void VadCircularBuffer::Reset() {
is_full_ = false;
diff --git a/webrtc/modules/audio_processing/vad/vad_circular_buffer.h b/webrtc/modules/audio_processing/vad/vad_circular_buffer.h
index 5238f77..46b03d4 100644
--- a/webrtc/modules/audio_processing/vad/vad_circular_buffer.h
+++ b/webrtc/modules/audio_processing/vad/vad_circular_buffer.h
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_
+#define MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_
-#include "webrtc/base/scoped_ptr.h"
+#include <memory>
namespace webrtc {
@@ -58,7 +58,7 @@ class VadCircularBuffer {
// corresponding linear index.
int ConvertToLinearIndex(int* index) const;
- rtc::scoped_ptr<double[]> buffer_;
+ std::unique_ptr<double[]> buffer_;
bool is_full_;
int index_;
int buffer_size_;
@@ -66,4 +66,4 @@ class VadCircularBuffer {
};
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_
+#endif // MODULES_AUDIO_PROCESSING_VAD_VAD_CIRCULAR_BUFFER_H_
diff --git a/webrtc/modules/audio_processing/vad/voice_activity_detector.cc b/webrtc/modules/audio_processing/vad/voice_activity_detector.cc
index ef56a35..f0d34c6 100644
--- a/webrtc/modules/audio_processing/vad/voice_activity_detector.cc
+++ b/webrtc/modules/audio_processing/vad/voice_activity_detector.cc
@@ -8,17 +8,16 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/modules/audio_processing/vad/voice_activity_detector.h"
+#include "modules/audio_processing/vad/voice_activity_detector.h"
#include <algorithm>
-#include "webrtc/base/checks.h"
+#include "rtc_base/checks.h"
namespace webrtc {
namespace {
-const size_t kMaxLength = 320;
-const int kNumChannels = 1;
+const size_t kNumChannels = 1;
const double kDefaultVoiceValue = 1.0;
const double kNeutralProbability = 0.5;
@@ -28,8 +27,9 @@ const double kLowProbability = 0.01;
VoiceActivityDetector::VoiceActivityDetector()
: last_voice_probability_(kDefaultVoiceValue),
- standalone_vad_(StandaloneVad::Create()) {
-}
+ standalone_vad_(StandaloneVad::Create()) {}
+
+VoiceActivityDetector::~VoiceActivityDetector() = default;
// Because ISAC has a different chunk length, it updates
// |chunkwise_voice_probabilities_| and |chunkwise_rms_| when there is new data.
@@ -37,8 +37,7 @@ VoiceActivityDetector::VoiceActivityDetector()
void VoiceActivityDetector::ProcessChunk(const int16_t* audio,
size_t length,
int sample_rate_hz) {
- RTC_DCHECK_EQ(static_cast<int>(length), sample_rate_hz / 100);
- RTC_DCHECK_LE(length, kMaxLength);
+ RTC_DCHECK_EQ(length, sample_rate_hz / 100);
// Resample to the required rate.
const int16_t* resampled_ptr = audio;
if (sample_rate_hz != kSampleRateHz) {
diff --git a/webrtc/modules/audio_processing/vad/voice_activity_detector.h b/webrtc/modules/audio_processing/vad/voice_activity_detector.h
index e2dcf02..a19883d 100644
--- a/webrtc/modules/audio_processing/vad/voice_activity_detector.h
+++ b/webrtc/modules/audio_processing/vad/voice_activity_detector.h
@@ -8,17 +8,20 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_
+#define MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
#include <vector>
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_audio/resampler/include/resampler.h"
-#include "webrtc/modules/audio_processing/vad/vad_audio_proc.h"
-#include "webrtc/modules/audio_processing/vad/common.h"
-#include "webrtc/modules/audio_processing/vad/pitch_based_vad.h"
-#include "webrtc/modules/audio_processing/vad/standalone_vad.h"
+#include "common_audio/resampler/include/resampler.h"
+#include "modules/audio_processing/vad/common.h"
+#include "modules/audio_processing/vad/pitch_based_vad.h"
+#include "modules/audio_processing/vad/standalone_vad.h"
+#include "modules/audio_processing/vad/vad_audio_proc.h"
namespace webrtc {
@@ -27,10 +30,9 @@ namespace webrtc {
class VoiceActivityDetector {
public:
VoiceActivityDetector();
+ ~VoiceActivityDetector();
- // Processes each audio chunk and estimates the voice probability. The maximum
- // supported sample rate is 32kHz.
- // TODO(aluebs): Change |length| to size_t.
+ // Processes each audio chunk and estimates the voice probability.
void ProcessChunk(const int16_t* audio, size_t length, int sample_rate_hz);
// Returns a vector of voice probabilities for each chunk. It can be empty for
@@ -58,7 +60,7 @@ class VoiceActivityDetector {
Resampler resampler_;
VadAudioProc audio_processing_;
- rtc::scoped_ptr<StandaloneVad> standalone_vad_;
+ std::unique_ptr<StandaloneVad> standalone_vad_;
PitchBasedVad pitch_based_vad_;
int16_t resampled_[kLength10Ms];
@@ -67,4 +69,4 @@ class VoiceActivityDetector {
} // namespace webrtc
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_
+#endif // MODULES_AUDIO_PROCESSING_VAD_VOICE_ACTIVITY_DETECTOR_H_
diff --git a/webrtc/modules/audio_processing/vad/voice_gmm_tables.h b/webrtc/modules/audio_processing/vad/voice_gmm_tables.h
index 2f247c3..ef4ad7e 100644
--- a/webrtc/modules/audio_processing/vad/voice_gmm_tables.h
+++ b/webrtc/modules/audio_processing/vad/voice_gmm_tables.h
@@ -10,8 +10,8 @@
// GMM tables for active segments. Generated by MakeGmmTables.m.
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_
+#ifndef MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_
+#define MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_
static const int kVoiceGmmNumMixtures = 12;
static const int kVoiceGmmDim = 3;
@@ -70,16 +70,8 @@ static const double kVoiceGmmMean[kVoiceGmmNumMixtures][kVoiceGmmDim] = {
{-7.29187507662854e-01, 5.22717685022855e+02, 1.16377942283991e+02}};
static const double kVoiceGmmWeights[kVoiceGmmNumMixtures] = {
- -1.39789694361035e+01,
- -1.19527720202104e+01,
- -1.32396317929055e+01,
- -1.09436815209238e+01,
- -1.13440027478149e+01,
- -1.12200721834504e+01,
- -1.02537324043693e+01,
- -1.60789861938302e+01,
- -1.03394494048344e+01,
- -1.83207938586818e+01,
- -1.31186044948288e+01,
- -9.52479998673554e+00};
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_
+ -1.39789694361035e+01, -1.19527720202104e+01, -1.32396317929055e+01,
+ -1.09436815209238e+01, -1.13440027478149e+01, -1.12200721834504e+01,
+ -1.02537324043693e+01, -1.60789861938302e+01, -1.03394494048344e+01,
+ -1.83207938586818e+01, -1.31186044948288e+01, -9.52479998673554e+00};
+#endif // MODULES_AUDIO_PROCESSING_VAD_VOICE_GMM_TABLES_H_
diff --git a/webrtc/modules/audio_processing/voice_detection.cc b/webrtc/modules/audio_processing/voice_detection.cc
new file mode 100644
index 0000000..e6c92ae
--- /dev/null
+++ b/webrtc/modules/audio_processing/voice_detection.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/voice_detection.h"
+
+#include "common_audio/vad/include/webrtc_vad.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+class VoiceDetection::Vad {
+ public:
+ Vad() {
+ state_ = WebRtcVad_Create();
+ RTC_CHECK(state_);
+ int error = WebRtcVad_Init(state_);
+ RTC_DCHECK_EQ(0, error);
+ }
+ ~Vad() { WebRtcVad_Free(state_); }
+
+ Vad(Vad&) = delete;
+ Vad& operator=(Vad&) = delete;
+
+ VadInst* state() { return state_; }
+
+ private:
+ VadInst* state_ = nullptr;
+};
+
+VoiceDetection::VoiceDetection(int sample_rate_hz, Likelihood likelihood)
+ : sample_rate_hz_(sample_rate_hz),
+ frame_size_samples_(static_cast<size_t>(sample_rate_hz_ / 100)),
+ likelihood_(likelihood),
+ vad_(new Vad()) {
+ int mode = 2;
+ switch (likelihood) {
+ case VoiceDetection::kVeryLowLikelihood:
+ mode = 3;
+ break;
+ case VoiceDetection::kLowLikelihood:
+ mode = 2;
+ break;
+ case VoiceDetection::kModerateLikelihood:
+ mode = 1;
+ break;
+ case VoiceDetection::kHighLikelihood:
+ mode = 0;
+ break;
+ default:
+ RTC_NOTREACHED();
+ break;
+ }
+ int error = WebRtcVad_set_mode(vad_->state(), mode);
+ RTC_DCHECK_EQ(0, error);
+}
+
+VoiceDetection::~VoiceDetection() {}
+
+bool VoiceDetection::ProcessCaptureAudio(AudioBuffer* audio) {
+ RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
+ audio->num_frames_per_band());
+ std::array<int16_t, AudioBuffer::kMaxSplitFrameLength> mixed_low_pass_data;
+ rtc::ArrayView<const int16_t> mixed_low_pass(mixed_low_pass_data.data(),
+ audio->num_frames_per_band());
+ if (audio->num_channels() == 1) {
+ FloatS16ToS16(audio->split_bands_const(0)[kBand0To8kHz],
+ audio->num_frames_per_band(), mixed_low_pass_data.data());
+ } else {
+ const int num_channels = static_cast<int>(audio->num_channels());
+ for (size_t i = 0; i < audio->num_frames_per_band(); ++i) {
+ int32_t value =
+ FloatS16ToS16(audio->split_channels_const(kBand0To8kHz)[0][i]);
+ for (int j = 1; j < num_channels; ++j) {
+ value += FloatS16ToS16(audio->split_channels_const(kBand0To8kHz)[j][i]);
+ }
+ mixed_low_pass_data[i] = value / num_channels;
+ }
+ }
+
+ int vad_ret = WebRtcVad_Process(vad_->state(), sample_rate_hz_,
+ mixed_low_pass.data(), frame_size_samples_);
+ RTC_DCHECK(vad_ret == 0 || vad_ret == 1);
+ return vad_ret == 0 ? false : true;
+}
+} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/voice_detection.h b/webrtc/modules/audio_processing/voice_detection.h
new file mode 100644
index 0000000..79d44e6
--- /dev/null
+++ b/webrtc/modules/audio_processing/voice_detection.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_VOICE_DETECTION_H_
+#define MODULES_AUDIO_PROCESSING_VOICE_DETECTION_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "modules/audio_processing/include/audio_processing.h"
+
+namespace webrtc {
+
+class AudioBuffer;
+
+// The voice activity detection (VAD) component analyzes the stream to
+// determine if voice is present.
+class VoiceDetection {
+ public:
+ // Specifies the likelihood that a frame will be declared to contain voice.
+ // A higher value makes it more likely that speech will not be clipped, at
+ // the expense of more noise being detected as voice.
+ enum Likelihood {
+ kVeryLowLikelihood,
+ kLowLikelihood,
+ kModerateLikelihood,
+ kHighLikelihood
+ };
+
+ VoiceDetection(int sample_rate_hz, Likelihood likelihood);
+ ~VoiceDetection();
+
+ VoiceDetection(VoiceDetection&) = delete;
+ VoiceDetection& operator=(VoiceDetection&) = delete;
+
+ // Returns true if voice is detected in the current frame.
+ bool ProcessCaptureAudio(AudioBuffer* audio);
+
+ Likelihood likelihood() const { return likelihood_; }
+
+ private:
+ class Vad;
+
+ int sample_rate_hz_;
+ size_t frame_size_samples_;
+ Likelihood likelihood_;
+ std::unique_ptr<Vad> vad_;
+};
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_VOICE_DETECTION_H_
diff --git a/webrtc/modules/audio_processing/voice_detection_impl.cc b/webrtc/modules/audio_processing/voice_detection_impl.cc
deleted file mode 100644
index 374189e..0000000
--- a/webrtc/modules/audio_processing/voice_detection_impl.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/audio_processing/voice_detection_impl.h"
-
-#include <assert.h>
-
-#include "webrtc/common_audio/vad/include/webrtc_vad.h"
-#include "webrtc/modules/audio_processing/audio_buffer.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-
-namespace webrtc {
-
-typedef VadInst Handle;
-
-namespace {
-int MapSetting(VoiceDetection::Likelihood likelihood) {
- switch (likelihood) {
- case VoiceDetection::kVeryLowLikelihood:
- return 3;
- case VoiceDetection::kLowLikelihood:
- return 2;
- case VoiceDetection::kModerateLikelihood:
- return 1;
- case VoiceDetection::kHighLikelihood:
- return 0;
- }
- assert(false);
- return -1;
-}
-} // namespace
-
-VoiceDetectionImpl::VoiceDetectionImpl(const AudioProcessing* apm,
- CriticalSectionWrapper* crit)
- : ProcessingComponent(),
- apm_(apm),
- crit_(crit),
- stream_has_voice_(false),
- using_external_vad_(false),
- likelihood_(kLowLikelihood),
- frame_size_ms_(10),
- frame_size_samples_(0) {}
-
-VoiceDetectionImpl::~VoiceDetectionImpl() {}
-
-int VoiceDetectionImpl::ProcessCaptureAudio(AudioBuffer* audio) {
- if (!is_component_enabled()) {
- return apm_->kNoError;
- }
-
- if (using_external_vad_) {
- using_external_vad_ = false;
- return apm_->kNoError;
- }
- assert(audio->num_frames_per_band() <= 160);
-
- // TODO(ajm): concatenate data in frame buffer here.
-
- int vad_ret = WebRtcVad_Process(static_cast<Handle*>(handle(0)),
- apm_->proc_split_sample_rate_hz(),
- audio->mixed_low_pass_data(),
- frame_size_samples_);
- if (vad_ret == 0) {
- stream_has_voice_ = false;
- audio->set_activity(AudioFrame::kVadPassive);
- } else if (vad_ret == 1) {
- stream_has_voice_ = true;
- audio->set_activity(AudioFrame::kVadActive);
- } else {
- return apm_->kUnspecifiedError;
- }
-
- return apm_->kNoError;
-}
-
-int VoiceDetectionImpl::Enable(bool enable) {
- CriticalSectionScoped crit_scoped(crit_);
- return EnableComponent(enable);
-}
-
-bool VoiceDetectionImpl::is_enabled() const {
- return is_component_enabled();
-}
-
-int VoiceDetectionImpl::set_stream_has_voice(bool has_voice) {
- using_external_vad_ = true;
- stream_has_voice_ = has_voice;
- return apm_->kNoError;
-}
-
-bool VoiceDetectionImpl::stream_has_voice() const {
- // TODO(ajm): enable this assertion?
- //assert(using_external_vad_ || is_component_enabled());
- return stream_has_voice_;
-}
-
-int VoiceDetectionImpl::set_likelihood(VoiceDetection::Likelihood likelihood) {
- CriticalSectionScoped crit_scoped(crit_);
- if (MapSetting(likelihood) == -1) {
- return apm_->kBadParameterError;
- }
-
- likelihood_ = likelihood;
- return Configure();
-}
-
-VoiceDetection::Likelihood VoiceDetectionImpl::likelihood() const {
- return likelihood_;
-}
-
-int VoiceDetectionImpl::set_frame_size_ms(int size) {
- CriticalSectionScoped crit_scoped(crit_);
- assert(size == 10); // TODO(ajm): remove when supported.
- if (size != 10 &&
- size != 20 &&
- size != 30) {
- return apm_->kBadParameterError;
- }
-
- frame_size_ms_ = size;
-
- return Initialize();
-}
-
-int VoiceDetectionImpl::frame_size_ms() const {
- return frame_size_ms_;
-}
-
-int VoiceDetectionImpl::Initialize() {
- int err = ProcessingComponent::Initialize();
- if (err != apm_->kNoError || !is_component_enabled()) {
- return err;
- }
-
- using_external_vad_ = false;
- frame_size_samples_ = static_cast<size_t>(
- frame_size_ms_ * apm_->proc_split_sample_rate_hz() / 1000);
- // TODO(ajm): intialize frame buffer here.
-
- return apm_->kNoError;
-}
-
-void* VoiceDetectionImpl::CreateHandle() const {
- return WebRtcVad_Create();
-}
-
-void VoiceDetectionImpl::DestroyHandle(void* handle) const {
- WebRtcVad_Free(static_cast<Handle*>(handle));
-}
-
-int VoiceDetectionImpl::InitializeHandle(void* handle) const {
- return WebRtcVad_Init(static_cast<Handle*>(handle));
-}
-
-int VoiceDetectionImpl::ConfigureHandle(void* handle) const {
- return WebRtcVad_set_mode(static_cast<Handle*>(handle),
- MapSetting(likelihood_));
-}
-
-int VoiceDetectionImpl::num_handles_required() const {
- return 1;
-}
-
-int VoiceDetectionImpl::GetHandleError(void* handle) const {
- // The VAD has no get_error() function.
- assert(handle != NULL);
- return apm_->kUnspecifiedError;
-}
-} // namespace webrtc
diff --git a/webrtc/modules/audio_processing/voice_detection_impl.h b/webrtc/modules/audio_processing/voice_detection_impl.h
deleted file mode 100644
index b188083..0000000
--- a/webrtc/modules/audio_processing/voice_detection_impl.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VOICE_DETECTION_IMPL_H_
-#define WEBRTC_MODULES_AUDIO_PROCESSING_VOICE_DETECTION_IMPL_H_
-
-#include "webrtc/modules/audio_processing/include/audio_processing.h"
-#include "webrtc/modules/audio_processing/processing_component.h"
-
-namespace webrtc {
-
-class AudioBuffer;
-class CriticalSectionWrapper;
-
-class VoiceDetectionImpl : public VoiceDetection,
- public ProcessingComponent {
- public:
- VoiceDetectionImpl(const AudioProcessing* apm, CriticalSectionWrapper* crit);
- virtual ~VoiceDetectionImpl();
-
- int ProcessCaptureAudio(AudioBuffer* audio);
-
- // VoiceDetection implementation.
- bool is_enabled() const override;
-
- // ProcessingComponent implementation.
- int Initialize() override;
-
- private:
- // VoiceDetection implementation.
- int Enable(bool enable) override;
- int set_stream_has_voice(bool has_voice) override;
- bool stream_has_voice() const override;
- int set_likelihood(Likelihood likelihood) override;
- Likelihood likelihood() const override;
- int set_frame_size_ms(int size) override;
- int frame_size_ms() const override;
-
- // ProcessingComponent implementation.
- void* CreateHandle() const override;
- int InitializeHandle(void* handle) const override;
- int ConfigureHandle(void* handle) const override;
- void DestroyHandle(void* handle) const override;
- int num_handles_required() const override;
- int GetHandleError(void* handle) const override;
-
- const AudioProcessing* apm_;
- CriticalSectionWrapper* crit_;
- bool stream_has_voice_;
- bool using_external_vad_;
- Likelihood likelihood_;
- int frame_size_ms_;
- size_t frame_size_samples_;
-};
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VOICE_DETECTION_IMPL_H_
diff --git a/webrtc/modules/interface/meson.build b/webrtc/modules/interface/meson.build
deleted file mode 100644
index a74b3f0..0000000
--- a/webrtc/modules/interface/meson.build
+++ /dev/null
@@ -1,7 +0,0 @@
-interface_headers = [
- 'module_common_types.h',
-]
-
-install_headers(interface_headers,
- subdir: 'webrtc_audio_processing/webrtc/modules/interface'
-)
diff --git a/webrtc/modules/interface/module_common_types.h b/webrtc/modules/interface/module_common_types.h
deleted file mode 100644
index cc4993a..0000000
--- a/webrtc/modules/interface/module_common_types.h
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULE_COMMON_TYPES_H
-#define MODULE_COMMON_TYPES_H
-
-#include <assert.h>
-#include <string.h> // memcpy
-
-#include <algorithm>
-#include <limits>
-
-#include "webrtc/base/constructormagic.h"
-#include "webrtc/common_types.h"
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
-#include "webrtc/common_video/rotation.h"
-#endif
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-struct RTPAudioHeader {
- uint8_t numEnergy; // number of valid entries in arrOfEnergy
- uint8_t arrOfEnergy[kRtpCsrcSize]; // one energy byte (0-9) per channel
- bool isCNG; // is this CNG
- uint8_t channel; // number of channels 2 = stereo
-};
-
-const int16_t kNoPictureId = -1;
-const int16_t kMaxOneBytePictureId = 0x7F; // 7 bits
-const int16_t kMaxTwoBytePictureId = 0x7FFF; // 15 bits
-const int16_t kNoTl0PicIdx = -1;
-const uint8_t kNoTemporalIdx = 0xFF;
-const uint8_t kNoSpatialIdx = 0xFF;
-const uint8_t kNoGofIdx = 0xFF;
-const size_t kMaxVp9RefPics = 3;
-const size_t kMaxVp9FramesInGof = 0xFF; // 8 bits
-const size_t kMaxVp9NumberOfSpatialLayers = 8;
-const int kNoKeyIdx = -1;
-
-struct RTPVideoHeaderVP8 {
- void InitRTPVideoHeaderVP8() {
- nonReference = false;
- pictureId = kNoPictureId;
- tl0PicIdx = kNoTl0PicIdx;
- temporalIdx = kNoTemporalIdx;
- layerSync = false;
- keyIdx = kNoKeyIdx;
- partitionId = 0;
- beginningOfPartition = false;
- }
-
- bool nonReference; // Frame is discardable.
- int16_t pictureId; // Picture ID index, 15 bits;
- // kNoPictureId if PictureID does not exist.
- int16_t tl0PicIdx; // TL0PIC_IDX, 8 bits;
- // kNoTl0PicIdx means no value provided.
- uint8_t temporalIdx; // Temporal layer index, or kNoTemporalIdx.
- bool layerSync; // This frame is a layer sync frame.
- // Disabled if temporalIdx == kNoTemporalIdx.
- int keyIdx; // 5 bits; kNoKeyIdx means not used.
- int partitionId; // VP8 partition ID
- bool beginningOfPartition; // True if this packet is the first
- // in a VP8 partition. Otherwise false
-};
-
-enum TemporalStructureMode {
- kTemporalStructureMode1, // 1 temporal layer structure - i.e., IPPP...
- kTemporalStructureMode2, // 2 temporal layers 0-1-0-1...
- kTemporalStructureMode3 // 3 temporal layers 0-2-1-2-0-2-1-2...
-};
-
-struct GofInfoVP9 {
- void SetGofInfoVP9(TemporalStructureMode tm) {
- switch (tm) {
- case kTemporalStructureMode1:
- num_frames_in_gof = 1;
- temporal_idx[0] = 0;
- temporal_up_switch[0] = false;
- num_ref_pics[0] = 1;
- pid_diff[0][0] = 1;
- break;
- case kTemporalStructureMode2:
- num_frames_in_gof = 2;
- temporal_idx[0] = 0;
- temporal_up_switch[0] = false;
- num_ref_pics[0] = 1;
- pid_diff[0][0] = 2;
-
- temporal_idx[1] = 1;
- temporal_up_switch[1] = true;
- num_ref_pics[1] = 1;
- pid_diff[1][0] = 1;
- break;
- case kTemporalStructureMode3:
- num_frames_in_gof = 4;
- temporal_idx[0] = 0;
- temporal_up_switch[0] = false;
- num_ref_pics[0] = 1;
- pid_diff[0][0] = 4;
-
- temporal_idx[1] = 2;
- temporal_up_switch[1] = true;
- num_ref_pics[1] = 1;
- pid_diff[1][0] = 1;
-
- temporal_idx[2] = 1;
- temporal_up_switch[2] = true;
- num_ref_pics[2] = 1;
- pid_diff[2][0] = 2;
-
- temporal_idx[3] = 2;
- temporal_up_switch[3] = false;
- num_ref_pics[3] = 2;
- pid_diff[3][0] = 1;
- pid_diff[3][1] = 2;
- break;
- default:
- assert(false);
- }
- }
-
- void CopyGofInfoVP9(const GofInfoVP9& src) {
- num_frames_in_gof = src.num_frames_in_gof;
- for (size_t i = 0; i < num_frames_in_gof; ++i) {
- temporal_idx[i] = src.temporal_idx[i];
- temporal_up_switch[i] = src.temporal_up_switch[i];
- num_ref_pics[i] = src.num_ref_pics[i];
- for (size_t r = 0; r < num_ref_pics[i]; ++r) {
- pid_diff[i][r] = src.pid_diff[i][r];
- }
- }
- }
-
- size_t num_frames_in_gof;
- uint8_t temporal_idx[kMaxVp9FramesInGof];
- bool temporal_up_switch[kMaxVp9FramesInGof];
- size_t num_ref_pics[kMaxVp9FramesInGof];
- int16_t pid_diff[kMaxVp9FramesInGof][kMaxVp9RefPics];
-};
-
-struct RTPVideoHeaderVP9 {
- void InitRTPVideoHeaderVP9() {
- inter_pic_predicted = false;
- flexible_mode = false;
- beginning_of_frame = false;
- end_of_frame = false;
- ss_data_available = false;
- picture_id = kNoPictureId;
- max_picture_id = kMaxTwoBytePictureId;
- tl0_pic_idx = kNoTl0PicIdx;
- temporal_idx = kNoTemporalIdx;
- spatial_idx = kNoSpatialIdx;
- temporal_up_switch = false;
- inter_layer_predicted = false;
- gof_idx = kNoGofIdx;
- num_ref_pics = 0;
- num_spatial_layers = 1;
- }
-
- bool inter_pic_predicted; // This layer frame is dependent on previously
- // coded frame(s).
- bool flexible_mode; // This frame is in flexible mode.
- bool beginning_of_frame; // True if this packet is the first in a VP9 layer
- // frame.
- bool end_of_frame; // True if this packet is the last in a VP9 layer frame.
- bool ss_data_available; // True if SS data is available in this payload
- // descriptor.
- int16_t picture_id; // PictureID index, 15 bits;
- // kNoPictureId if PictureID does not exist.
- int16_t max_picture_id; // Maximum picture ID index; either 0x7F or 0x7FFF;
- int16_t tl0_pic_idx; // TL0PIC_IDX, 8 bits;
- // kNoTl0PicIdx means no value provided.
- uint8_t temporal_idx; // Temporal layer index, or kNoTemporalIdx.
- uint8_t spatial_idx; // Spatial layer index, or kNoSpatialIdx.
- bool temporal_up_switch; // True if upswitch to higher frame rate is possible
- // starting from this frame.
- bool inter_layer_predicted; // Frame is dependent on directly lower spatial
- // layer frame.
-
- uint8_t gof_idx; // Index to predefined temporal frame info in SS data.
-
- size_t num_ref_pics; // Number of reference pictures used by this layer
- // frame.
- int16_t pid_diff[kMaxVp9RefPics]; // P_DIFF signaled to derive the PictureID
- // of the reference pictures.
- int16_t ref_picture_id[kMaxVp9RefPics]; // PictureID of reference pictures.
-
- // SS data.
- size_t num_spatial_layers; // Always populated.
- bool spatial_layer_resolution_present;
- uint16_t width[kMaxVp9NumberOfSpatialLayers];
- uint16_t height[kMaxVp9NumberOfSpatialLayers];
- GofInfoVP9 gof;
-};
-
-// The packetization types that we support: single, aggregated, and fragmented.
-enum H264PacketizationTypes {
- kH264SingleNalu, // This packet contains a single NAL unit.
- kH264StapA, // This packet contains STAP-A (single time
- // aggregation) packets. If this packet has an
- // associated NAL unit type, it'll be for the
- // first such aggregated packet.
- kH264FuA, // This packet contains a FU-A (fragmentation
- // unit) packet, meaning it is a part of a frame
- // that was too large to fit into a single packet.
-};
-
-struct RTPVideoHeaderH264 {
- uint8_t nalu_type; // The NAL unit type. If this is a header for a
- // fragmented packet, it's the NAL unit type of
- // the original data. If this is the header for an
- // aggregated packet, it's the NAL unit type of
- // the first NAL unit in the packet.
- H264PacketizationTypes packetization_type;
-};
-
-union RTPVideoTypeHeader {
- RTPVideoHeaderVP8 VP8;
- RTPVideoHeaderVP9 VP9;
- RTPVideoHeaderH264 H264;
-};
-
-enum RtpVideoCodecTypes {
- kRtpVideoNone,
- kRtpVideoGeneric,
- kRtpVideoVp8,
- kRtpVideoVp9,
- kRtpVideoH264
-};
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
-// Since RTPVideoHeader is used as a member of a union, it can't have a
-// non-trivial default constructor.
-struct RTPVideoHeader {
- uint16_t width; // size
- uint16_t height;
- VideoRotation rotation;
-
- bool isFirstPacket; // first packet in frame
- uint8_t simulcastIdx; // Index if the simulcast encoder creating
- // this frame, 0 if not using simulcast.
- RtpVideoCodecTypes codec;
- RTPVideoTypeHeader codecHeader;
-};
-#endif
-union RTPTypeHeader {
- RTPAudioHeader Audio;
-#ifndef WEBRTC_AUDIO_PROCESSING_ONLY_BUILD
- RTPVideoHeader Video;
-#endif
-};
-
-struct WebRtcRTPHeader {
- RTPHeader header;
- FrameType frameType;
- RTPTypeHeader type;
- // NTP time of the capture time in local timebase in milliseconds.
- int64_t ntp_time_ms;
-};
-
-class RTPFragmentationHeader {
- public:
- RTPFragmentationHeader()
- : fragmentationVectorSize(0),
- fragmentationOffset(NULL),
- fragmentationLength(NULL),
- fragmentationTimeDiff(NULL),
- fragmentationPlType(NULL) {};
-
- ~RTPFragmentationHeader() {
- delete[] fragmentationOffset;
- delete[] fragmentationLength;
- delete[] fragmentationTimeDiff;
- delete[] fragmentationPlType;
- }
-
- void CopyFrom(const RTPFragmentationHeader& src) {
- if (this == &src) {
- return;
- }
-
- if (src.fragmentationVectorSize != fragmentationVectorSize) {
- // new size of vectors
-
- // delete old
- delete[] fragmentationOffset;
- fragmentationOffset = NULL;
- delete[] fragmentationLength;
- fragmentationLength = NULL;
- delete[] fragmentationTimeDiff;
- fragmentationTimeDiff = NULL;
- delete[] fragmentationPlType;
- fragmentationPlType = NULL;
-
- if (src.fragmentationVectorSize > 0) {
- // allocate new
- if (src.fragmentationOffset) {
- fragmentationOffset = new size_t[src.fragmentationVectorSize];
- }
- if (src.fragmentationLength) {
- fragmentationLength = new size_t[src.fragmentationVectorSize];
- }
- if (src.fragmentationTimeDiff) {
- fragmentationTimeDiff = new uint16_t[src.fragmentationVectorSize];
- }
- if (src.fragmentationPlType) {
- fragmentationPlType = new uint8_t[src.fragmentationVectorSize];
- }
- }
- // set new size
- fragmentationVectorSize = src.fragmentationVectorSize;
- }
-
- if (src.fragmentationVectorSize > 0) {
- // copy values
- if (src.fragmentationOffset) {
- memcpy(fragmentationOffset, src.fragmentationOffset,
- src.fragmentationVectorSize * sizeof(size_t));
- }
- if (src.fragmentationLength) {
- memcpy(fragmentationLength, src.fragmentationLength,
- src.fragmentationVectorSize * sizeof(size_t));
- }
- if (src.fragmentationTimeDiff) {
- memcpy(fragmentationTimeDiff, src.fragmentationTimeDiff,
- src.fragmentationVectorSize * sizeof(uint16_t));
- }
- if (src.fragmentationPlType) {
- memcpy(fragmentationPlType, src.fragmentationPlType,
- src.fragmentationVectorSize * sizeof(uint8_t));
- }
- }
- }
-
- void VerifyAndAllocateFragmentationHeader(const size_t size) {
- assert(size <= std::numeric_limits<uint16_t>::max());
- const uint16_t size16 = static_cast<uint16_t>(size);
- if (fragmentationVectorSize < size16) {
- uint16_t oldVectorSize = fragmentationVectorSize;
- {
- // offset
- size_t* oldOffsets = fragmentationOffset;
- fragmentationOffset = new size_t[size16];
- memset(fragmentationOffset + oldVectorSize, 0,
- sizeof(size_t) * (size16 - oldVectorSize));
- // copy old values
- memcpy(fragmentationOffset, oldOffsets,
- sizeof(size_t) * oldVectorSize);
- delete[] oldOffsets;
- }
- // length
- {
- size_t* oldLengths = fragmentationLength;
- fragmentationLength = new size_t[size16];
- memset(fragmentationLength + oldVectorSize, 0,
- sizeof(size_t) * (size16 - oldVectorSize));
- memcpy(fragmentationLength, oldLengths,
- sizeof(size_t) * oldVectorSize);
- delete[] oldLengths;
- }
- // time diff
- {
- uint16_t* oldTimeDiffs = fragmentationTimeDiff;
- fragmentationTimeDiff = new uint16_t[size16];
- memset(fragmentationTimeDiff + oldVectorSize, 0,
- sizeof(uint16_t) * (size16 - oldVectorSize));
- memcpy(fragmentationTimeDiff, oldTimeDiffs,
- sizeof(uint16_t) * oldVectorSize);
- delete[] oldTimeDiffs;
- }
- // payload type
- {
- uint8_t* oldTimePlTypes = fragmentationPlType;
- fragmentationPlType = new uint8_t[size16];
- memset(fragmentationPlType + oldVectorSize, 0,
- sizeof(uint8_t) * (size16 - oldVectorSize));
- memcpy(fragmentationPlType, oldTimePlTypes,
- sizeof(uint8_t) * oldVectorSize);
- delete[] oldTimePlTypes;
- }
- fragmentationVectorSize = size16;
- }
- }
-
- uint16_t fragmentationVectorSize; // Number of fragmentations
- size_t* fragmentationOffset; // Offset of pointer to data for each
- // fragmentation
- size_t* fragmentationLength; // Data size for each fragmentation
- uint16_t* fragmentationTimeDiff; // Timestamp difference relative "now" for
- // each fragmentation
- uint8_t* fragmentationPlType; // Payload type of each fragmentation
-
- private:
- RTC_DISALLOW_COPY_AND_ASSIGN(RTPFragmentationHeader);
-};
-
-struct RTCPVoIPMetric {
- // RFC 3611 4.7
- uint8_t lossRate;
- uint8_t discardRate;
- uint8_t burstDensity;
- uint8_t gapDensity;
- uint16_t burstDuration;
- uint16_t gapDuration;
- uint16_t roundTripDelay;
- uint16_t endSystemDelay;
- uint8_t signalLevel;
- uint8_t noiseLevel;
- uint8_t RERL;
- uint8_t Gmin;
- uint8_t Rfactor;
- uint8_t extRfactor;
- uint8_t MOSLQ;
- uint8_t MOSCQ;
- uint8_t RXconfig;
- uint16_t JBnominal;
- uint16_t JBmax;
- uint16_t JBabsMax;
-};
-
-// Types for the FEC packet masks. The type |kFecMaskRandom| is based on a
-// random loss model. The type |kFecMaskBursty| is based on a bursty/consecutive
-// loss model. The packet masks are defined in
-// modules/rtp_rtcp/fec_private_tables_random(bursty).h
-enum FecMaskType {
- kFecMaskRandom,
- kFecMaskBursty,
-};
-
-// Struct containing forward error correction settings.
-struct FecProtectionParams {
- int fec_rate;
- bool use_uep_protection;
- int max_fec_frames;
- FecMaskType fec_mask_type;
-};
-
-// Interface used by the CallStats class to distribute call statistics.
-// Callbacks will be triggered as soon as the class has been registered to a
-// CallStats object using RegisterStatsObserver.
-class CallStatsObserver {
- public:
- virtual void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) = 0;
-
- virtual ~CallStatsObserver() {}
-};
-
-struct VideoContentMetrics {
- VideoContentMetrics()
- : motion_magnitude(0.0f),
- spatial_pred_err(0.0f),
- spatial_pred_err_h(0.0f),
- spatial_pred_err_v(0.0f) {}
-
- void Reset() {
- motion_magnitude = 0.0f;
- spatial_pred_err = 0.0f;
- spatial_pred_err_h = 0.0f;
- spatial_pred_err_v = 0.0f;
- }
- float motion_magnitude;
- float spatial_pred_err;
- float spatial_pred_err_h;
- float spatial_pred_err_v;
-};
-
-/* This class holds up to 60 ms of super-wideband (32 kHz) stereo audio. It
- * allows for adding and subtracting frames while keeping track of the resulting
- * states.
- *
- * Notes
- * - The total number of samples in |data_| is
- * samples_per_channel_ * num_channels_
- *
- * - Stereo data is interleaved starting with the left channel.
- *
- * - The +operator assume that you would never add exactly opposite frames when
- * deciding the resulting state. To do this use the -operator.
- */
-class AudioFrame {
- public:
- // Stereo, 32 kHz, 60 ms (2 * 32 * 60)
- static const size_t kMaxDataSizeSamples = 3840;
-
- enum VADActivity {
- kVadActive = 0,
- kVadPassive = 1,
- kVadUnknown = 2
- };
- enum SpeechType {
- kNormalSpeech = 0,
- kPLC = 1,
- kCNG = 2,
- kPLCCNG = 3,
- kUndefined = 4
- };
-
- AudioFrame();
- virtual ~AudioFrame() {}
-
- // Resets all members to their default state (except does not modify the
- // contents of |data_|).
- void Reset();
-
- // |interleaved_| is not changed by this method.
- void UpdateFrame(int id, uint32_t timestamp, const int16_t* data,
- size_t samples_per_channel, int sample_rate_hz,
- SpeechType speech_type, VADActivity vad_activity,
- int num_channels = 1, uint32_t energy = -1);
-
- AudioFrame& Append(const AudioFrame& rhs);
-
- void CopyFrom(const AudioFrame& src);
-
- void Mute();
-
- AudioFrame& operator>>=(const int rhs);
- AudioFrame& operator+=(const AudioFrame& rhs);
- AudioFrame& operator-=(const AudioFrame& rhs);
-
- int id_;
- // RTP timestamp of the first sample in the AudioFrame.
- uint32_t timestamp_;
- // Time since the first frame in milliseconds.
- // -1 represents an uninitialized value.
- int64_t elapsed_time_ms_;
- // NTP time of the estimated capture time in local timebase in milliseconds.
- // -1 represents an uninitialized value.
- int64_t ntp_time_ms_;
- int16_t data_[kMaxDataSizeSamples];
- size_t samples_per_channel_;
- int sample_rate_hz_;
- int num_channels_;
- SpeechType speech_type_;
- VADActivity vad_activity_;
- // Note that there is no guarantee that |energy_| is correct. Any user of this
- // member must verify that the value is correct.
- // TODO(henrike) Remove |energy_|.
- // See https://code.google.com/p/webrtc/issues/detail?id=3315.
- uint32_t energy_;
- bool interleaved_;
-
- private:
- RTC_DISALLOW_COPY_AND_ASSIGN(AudioFrame);
-};
-
-inline AudioFrame::AudioFrame()
- : data_() {
- Reset();
-}
-
-inline void AudioFrame::Reset() {
- id_ = -1;
- // TODO(wu): Zero is a valid value for |timestamp_|. We should initialize
- // to an invalid value, or add a new member to indicate invalidity.
- timestamp_ = 0;
- elapsed_time_ms_ = -1;
- ntp_time_ms_ = -1;
- samples_per_channel_ = 0;
- sample_rate_hz_ = 0;
- num_channels_ = 0;
- speech_type_ = kUndefined;
- vad_activity_ = kVadUnknown;
- energy_ = 0xffffffff;
- interleaved_ = true;
-}
-
-inline void AudioFrame::UpdateFrame(int id,
- uint32_t timestamp,
- const int16_t* data,
- size_t samples_per_channel,
- int sample_rate_hz,
- SpeechType speech_type,
- VADActivity vad_activity,
- int num_channels,
- uint32_t energy) {
- id_ = id;
- timestamp_ = timestamp;
- samples_per_channel_ = samples_per_channel;
- sample_rate_hz_ = sample_rate_hz;
- speech_type_ = speech_type;
- vad_activity_ = vad_activity;
- num_channels_ = num_channels;
- energy_ = energy;
-
- assert(num_channels >= 0);
- const size_t length = samples_per_channel * num_channels;
- assert(length <= kMaxDataSizeSamples);
- if (data != NULL) {
- memcpy(data_, data, sizeof(int16_t) * length);
- } else {
- memset(data_, 0, sizeof(int16_t) * length);
- }
-}
-
-inline void AudioFrame::CopyFrom(const AudioFrame& src) {
- if (this == &src) return;
-
- id_ = src.id_;
- timestamp_ = src.timestamp_;
- elapsed_time_ms_ = src.elapsed_time_ms_;
- ntp_time_ms_ = src.ntp_time_ms_;
- samples_per_channel_ = src.samples_per_channel_;
- sample_rate_hz_ = src.sample_rate_hz_;
- speech_type_ = src.speech_type_;
- vad_activity_ = src.vad_activity_;
- num_channels_ = src.num_channels_;
- energy_ = src.energy_;
- interleaved_ = src.interleaved_;
-
- assert(num_channels_ >= 0);
- const size_t length = samples_per_channel_ * num_channels_;
- assert(length <= kMaxDataSizeSamples);
- memcpy(data_, src.data_, sizeof(int16_t) * length);
-}
-
-inline void AudioFrame::Mute() {
- memset(data_, 0, samples_per_channel_ * num_channels_ * sizeof(int16_t));
-}
-
-inline AudioFrame& AudioFrame::operator>>=(const int rhs) {
- assert((num_channels_ > 0) && (num_channels_ < 3));
- if ((num_channels_ > 2) || (num_channels_ < 1)) return *this;
-
- for (size_t i = 0; i < samples_per_channel_ * num_channels_; i++) {
- data_[i] = static_cast<int16_t>(data_[i] >> rhs);
- }
- return *this;
-}
-
-inline AudioFrame& AudioFrame::Append(const AudioFrame& rhs) {
- // Sanity check
- assert((num_channels_ > 0) && (num_channels_ < 3));
- assert(interleaved_ == rhs.interleaved_);
- if ((num_channels_ > 2) || (num_channels_ < 1)) return *this;
- if (num_channels_ != rhs.num_channels_) return *this;
-
- if ((vad_activity_ == kVadActive) || rhs.vad_activity_ == kVadActive) {
- vad_activity_ = kVadActive;
- } else if (vad_activity_ == kVadUnknown || rhs.vad_activity_ == kVadUnknown) {
- vad_activity_ = kVadUnknown;
- }
- if (speech_type_ != rhs.speech_type_) {
- speech_type_ = kUndefined;
- }
-
- size_t offset = samples_per_channel_ * num_channels_;
- for (size_t i = 0; i < rhs.samples_per_channel_ * rhs.num_channels_; i++) {
- data_[offset + i] = rhs.data_[i];
- }
- samples_per_channel_ += rhs.samples_per_channel_;
- return *this;
-}
-
-namespace {
-inline int16_t ClampToInt16(int32_t input) {
- if (input < -0x00008000) {
- return -0x8000;
- } else if (input > 0x00007FFF) {
- return 0x7FFF;
- } else {
- return static_cast<int16_t>(input);
- }
-}
-}
-
-inline AudioFrame& AudioFrame::operator+=(const AudioFrame& rhs) {
- // Sanity check
- assert((num_channels_ > 0) && (num_channels_ < 3));
- assert(interleaved_ == rhs.interleaved_);
- if ((num_channels_ > 2) || (num_channels_ < 1)) return *this;
- if (num_channels_ != rhs.num_channels_) return *this;
-
- bool noPrevData = false;
- if (samples_per_channel_ != rhs.samples_per_channel_) {
- if (samples_per_channel_ == 0) {
- // special case we have no data to start with
- samples_per_channel_ = rhs.samples_per_channel_;
- noPrevData = true;
- } else {
- return *this;
- }
- }
-
- if ((vad_activity_ == kVadActive) || rhs.vad_activity_ == kVadActive) {
- vad_activity_ = kVadActive;
- } else if (vad_activity_ == kVadUnknown || rhs.vad_activity_ == kVadUnknown) {
- vad_activity_ = kVadUnknown;
- }
-
- if (speech_type_ != rhs.speech_type_) speech_type_ = kUndefined;
-
- if (noPrevData) {
- memcpy(data_, rhs.data_,
- sizeof(int16_t) * rhs.samples_per_channel_ * num_channels_);
- } else {
- // IMPROVEMENT this can be done very fast in assembly
- for (size_t i = 0; i < samples_per_channel_ * num_channels_; i++) {
- int32_t wrap_guard =
- static_cast<int32_t>(data_[i]) + static_cast<int32_t>(rhs.data_[i]);
- data_[i] = ClampToInt16(wrap_guard);
- }
- }
- energy_ = 0xffffffff;
- return *this;
-}
-
-inline AudioFrame& AudioFrame::operator-=(const AudioFrame& rhs) {
- // Sanity check
- assert((num_channels_ > 0) && (num_channels_ < 3));
- assert(interleaved_ == rhs.interleaved_);
- if ((num_channels_ > 2) || (num_channels_ < 1)) return *this;
-
- if ((samples_per_channel_ != rhs.samples_per_channel_) ||
- (num_channels_ != rhs.num_channels_)) {
- return *this;
- }
- if ((vad_activity_ != kVadPassive) || rhs.vad_activity_ != kVadPassive) {
- vad_activity_ = kVadUnknown;
- }
- speech_type_ = kUndefined;
-
- for (size_t i = 0; i < samples_per_channel_ * num_channels_; i++) {
- int32_t wrap_guard =
- static_cast<int32_t>(data_[i]) - static_cast<int32_t>(rhs.data_[i]);
- data_[i] = ClampToInt16(wrap_guard);
- }
- energy_ = 0xffffffff;
- return *this;
-}
-
-inline bool IsNewerSequenceNumber(uint16_t sequence_number,
- uint16_t prev_sequence_number) {
- // Distinguish between elements that are exactly 0x8000 apart.
- // If s1>s2 and |s1-s2| = 0x8000: IsNewer(s1,s2)=true, IsNewer(s2,s1)=false
- // rather than having IsNewer(s1,s2) = IsNewer(s2,s1) = false.
- if (static_cast<uint16_t>(sequence_number - prev_sequence_number) == 0x8000) {
- return sequence_number > prev_sequence_number;
- }
- return sequence_number != prev_sequence_number &&
- static_cast<uint16_t>(sequence_number - prev_sequence_number) < 0x8000;
-}
-
-inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
- // Distinguish between elements that are exactly 0x80000000 apart.
- // If t1>t2 and |t1-t2| = 0x80000000: IsNewer(t1,t2)=true,
- // IsNewer(t2,t1)=false
- // rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
- if (static_cast<uint32_t>(timestamp - prev_timestamp) == 0x80000000) {
- return timestamp > prev_timestamp;
- }
- return timestamp != prev_timestamp &&
- static_cast<uint32_t>(timestamp - prev_timestamp) < 0x80000000;
-}
-
-inline uint16_t LatestSequenceNumber(uint16_t sequence_number1,
- uint16_t sequence_number2) {
- return IsNewerSequenceNumber(sequence_number1, sequence_number2)
- ? sequence_number1
- : sequence_number2;
-}
-
-inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
- return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
-}
-
-// Utility class to unwrap a sequence number to a larger type, for easier
-// handling large ranges. Note that sequence numbers will never be unwrapped
-// to a negative value.
-class SequenceNumberUnwrapper {
- public:
- SequenceNumberUnwrapper() : last_seq_(-1) {}
-
- // Get the unwrapped sequence, but don't update the internal state.
- int64_t UnwrapWithoutUpdate(uint16_t sequence_number) {
- if (last_seq_ == -1)
- return sequence_number;
-
- uint16_t cropped_last = static_cast<uint16_t>(last_seq_);
- int64_t delta = sequence_number - cropped_last;
- if (IsNewerSequenceNumber(sequence_number, cropped_last)) {
- if (delta < 0)
- delta += (1 << 16); // Wrap forwards.
- } else if (delta > 0 && (last_seq_ + delta - (1 << 16)) >= 0) {
- // If sequence_number is older but delta is positive, this is a backwards
- // wrap-around. However, don't wrap backwards past 0 (unwrapped).
- delta -= (1 << 16);
- }
-
- return last_seq_ + delta;
- }
-
- // Only update the internal state to the specified last (unwrapped) sequence.
- void UpdateLast(int64_t last_sequence) { last_seq_ = last_sequence; }
-
- // Unwrap the sequence number and update the internal state.
- int64_t Unwrap(uint16_t sequence_number) {
- int64_t unwrapped = UnwrapWithoutUpdate(sequence_number);
- UpdateLast(unwrapped);
- return unwrapped;
- }
-
- private:
- int64_t last_seq_;
-};
-
-} // namespace webrtc
-
-#endif // MODULE_COMMON_TYPES_H
diff --git a/webrtc/modules/meson.build b/webrtc/modules/meson.build
index 86800cd..0d73dd8 100644
--- a/webrtc/modules/meson.build
+++ b/webrtc/modules/meson.build
@@ -1,3 +1,3 @@
+subdir('third_party/fft')
subdir('audio_coding')
subdir('audio_processing')
-subdir('interface')
diff --git a/webrtc/modules/third_party/fft/BUILD.gn b/webrtc/modules/third_party/fft/BUILD.gn
new file mode 100644
index 0000000..49dbd6f
--- /dev/null
+++ b/webrtc/modules/third_party/fft/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the ../../../LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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_library("fft") {
+ sources = [
+ "fft.c",
+ "fft.h",
+ ]
+}
diff --git a/webrtc/modules/third_party/fft/LICENSE b/webrtc/modules/third_party/fft/LICENSE
new file mode 100644
index 0000000..c0a7805
--- /dev/null
+++ b/webrtc/modules/third_party/fft/LICENSE
@@ -0,0 +1,25 @@
+/*
+ * Copyright(c)1995,97 Mark Olesen <olesen@me.QueensU.CA>
+ * Queen's Univ at Kingston (Canada)
+ *
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose without fee is hereby granted, provided that this
+ * entire notice is included in all copies of any software which is
+ * or includes a copy or modification of this software and in all
+ * copies of the supporting documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S
+ * UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY
+ * KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * All of which is to say that you can do what you like with this
+ * source code provided you don't try to sell it as your own and you
+ * include an unaltered copy of this message (including the
+ * copyright).
+ *
+ * It is also implicitly understood that bug fixes and improvements
+ * should make their way back to the general Internet community so
+ * that everyone benefits.
+ */
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/fft.c b/webrtc/modules/third_party/fft/fft.c
index c854d8c..7260462 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/fft.c
+++ b/webrtc/modules/third_party/fft/fft.c
@@ -123,12 +123,11 @@
* following two constants should agree with the array dimensions.
*
*----------------------------------------------------------------------*/
-#include "fft.h"
#include <stdlib.h>
#include <math.h>
-
+#include "modules/third_party/fft/fft.h"
/* double precision routine */
static int
@@ -212,7 +211,7 @@ int WebRtcIsac_Fftns(unsigned int ndim, const int dims[],
{
max_factors = (int)nSpan;
}
- if ((int)nSpan > max_perm)
+ if ((int)nSpan > max_perm)
{
max_perm = (int)nSpan;
}
@@ -416,7 +415,7 @@ static int FFTRADIX (REAL Re[],
}
/* test that mfactors is in range */
- if (mfactor > NFACTOR)
+ if (mfactor > FFT_NFACTOR)
{
return -1;
}
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/fft.h b/webrtc/modules/third_party/fft/fft.h
index a42f57b..f8f8b6f 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/fft.h
+++ b/webrtc/modules/third_party/fft/fft.h
@@ -2,7 +2,7 @@
* 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
+ * that can be found in the ../../../LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
@@ -27,19 +27,32 @@
* See the comments in the code for correct usage!
*/
-#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_
-#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_
+#ifndef MODULES_THIRD_PARTY_FFT_FFT_H_
+#define MODULES_THIRD_PARTY_FFT_FFT_H_
+#define FFT_MAXFFTSIZE 2048
+#define FFT_NFACTOR 11
-#include "structs.h"
+typedef struct {
+ unsigned int SpaceAlloced;
+ unsigned int MaxPermAlloced;
+ double Tmp0[FFT_MAXFFTSIZE];
+ double Tmp1[FFT_MAXFFTSIZE];
+ double Tmp2[FFT_MAXFFTSIZE];
+ double Tmp3[FFT_MAXFFTSIZE];
+ int Perm[FFT_MAXFFTSIZE];
+ int factor[FFT_NFACTOR];
+} FFTstr;
/* double precision routine */
+int WebRtcIsac_Fftns(unsigned int ndim,
+ const int dims[],
+ double Re[],
+ double Im[],
+ int isign,
+ double scaling,
+ FFTstr* fftstate);
-int WebRtcIsac_Fftns (unsigned int ndim, const int dims[], double Re[], double Im[],
- int isign, double scaling, FFTstr *fftstate);
-
-
-
-#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ */
+#endif /* MODULES_THIRD_PARTY_FFT_FFT_H_ */
diff --git a/webrtc/modules/third_party/fft/meson.build b/webrtc/modules/third_party/fft/meson.build
new file mode 100644
index 0000000..1868796
--- /dev/null
+++ b/webrtc/modules/third_party/fft/meson.build
@@ -0,0 +1,13 @@
+fft_sources = ['fft.c']
+
+libfft = static_library('libfft',
+ fft_sources,
+ dependencies: common_deps,
+ include_directories: webrtc_inc,
+ cpp_args : common_cxxflags
+)
+
+fft_dep = declare_dependency(
+ link_with: libfft
+)
+
diff --git a/webrtc/modules/utility/interface/audio_frame_operations.h b/webrtc/modules/utility/interface/audio_frame_operations.h
deleted file mode 100644
index c2af68a..0000000
--- a/webrtc/modules/utility/interface/audio_frame_operations.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_VOICE_ENGINE_AUDIO_FRAME_OPERATIONS_H_
-#define WEBRTC_VOICE_ENGINE_AUDIO_FRAME_OPERATIONS_H_
-
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-class AudioFrame;
-
-// TODO(andrew): consolidate this with utility.h and audio_frame_manipulator.h.
-// Change reference parameters to pointers. Consider using a namespace rather
-// than a class.
-class AudioFrameOperations {
- public:
- // Upmixes mono |src_audio| to stereo |dst_audio|. This is an out-of-place
- // operation, meaning src_audio and dst_audio must point to different
- // buffers. It is the caller's responsibility to ensure that |dst_audio| is
- // sufficiently large.
- static void MonoToStereo(const int16_t* src_audio, size_t samples_per_channel,
- int16_t* dst_audio);
- // |frame.num_channels_| will be updated. This version checks for sufficient
- // buffer size and that |num_channels_| is mono.
- static int MonoToStereo(AudioFrame* frame);
-
- // Downmixes stereo |src_audio| to mono |dst_audio|. This is an in-place
- // operation, meaning |src_audio| and |dst_audio| may point to the same
- // buffer.
- static void StereoToMono(const int16_t* src_audio, size_t samples_per_channel,
- int16_t* dst_audio);
- // |frame.num_channels_| will be updated. This version checks that
- // |num_channels_| is stereo.
- static int StereoToMono(AudioFrame* frame);
-
- // Swap the left and right channels of |frame|. Fails silently if |frame| is
- // not stereo.
- static void SwapStereoChannels(AudioFrame* frame);
-
- // Zeros out the audio and sets |frame.energy| to zero.
- static void Mute(AudioFrame& frame);
-
- static int Scale(float left, float right, AudioFrame& frame);
-
- static int ScaleWithSat(float scale, AudioFrame& frame);
-};
-
-} // namespace webrtc
-
-#endif // #ifndef WEBRTC_VOICE_ENGINE_AUDIO_FRAME_OPERATIONS_H_
diff --git a/webrtc/rtc_base/BUILD.gn b/webrtc/rtc_base/BUILD.gn
new file mode 100644
index 0000000..3383580
--- /dev/null
+++ b/webrtc/rtc_base/BUILD.gn
@@ -0,0 +1,1482 @@
+# 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("//build/config/crypto.gni")
+import("//build/config/ui.gni")
+import("../webrtc.gni")
+
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+config("rtc_base_chromium_config") {
+ defines = [ "NO_MAIN_THREAD_WRAPPING" ]
+}
+
+if (!rtc_build_ssl) {
+ config("external_ssl_library") {
+ assert(rtc_ssl_root != "",
+ "You must specify rtc_ssl_root when rtc_build_ssl==0.")
+ include_dirs = [ rtc_ssl_root ]
+ }
+}
+
+rtc_source_set("protobuf_utils") {
+ sources = [ "protobuf_utils.h" ]
+ if (rtc_enable_protobuf) {
+ public_configs = [ "//third_party/protobuf:protobuf_config" ]
+ deps = [ "//third_party/protobuf:protobuf_lite" ]
+ }
+}
+
+rtc_source_set("compile_assert_c") {
+ sources = [ "compile_assert_c.h" ]
+}
+
+rtc_source_set("ignore_wundef") {
+ sources = [ "ignore_wundef.h" ]
+}
+
+rtc_source_set("untyped_function") {
+ sources = [ "untyped_function.h" ]
+ deps = [ "system:assume" ]
+}
+
+rtc_source_set("robo_caller") {
+ sources = [
+ "robo_caller.cc",
+ "robo_caller.h",
+ ]
+ deps = [
+ ":untyped_function",
+ "../api:function_view",
+ "system:assume",
+ "system:inline",
+ ]
+}
+
+# The subset of rtc_base approved for use outside of libjingle.
+# TODO(bugs.webrtc.org/9838): Create small and focused build targets and remove
+# the old concept of rtc_base and rtc_base_approved.
+rtc_library("rtc_base_approved") {
+ visibility = [ "*" ]
+ deps = [
+ ":checks",
+ ":rtc_task_queue",
+ ":safe_compare",
+ ":type_traits",
+ "../api:array_view",
+ "../api:scoped_refptr",
+ "synchronization:mutex",
+ "system:arch",
+ "system:rtc_export",
+ "system:unused",
+ "third_party/base64",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ public_deps = [] # no-presubmit-check TODO(webrtc:8603)
+
+ sources = [
+ "bind.h",
+ "bit_buffer.cc",
+ "bit_buffer.h",
+ "buffer.h",
+ "buffer_queue.cc",
+ "buffer_queue.h",
+ "byte_buffer.cc",
+ "byte_buffer.h",
+ "byte_order.h",
+ "copy_on_write_buffer.cc",
+ "copy_on_write_buffer.h",
+ "event_tracer.cc",
+ "event_tracer.h",
+ "location.cc",
+ "location.h",
+ "message_buffer_reader.h",
+ "numerics/histogram_percentile_counter.cc",
+ "numerics/histogram_percentile_counter.h",
+ "numerics/mod_ops.h",
+ "numerics/moving_max_counter.h",
+ "numerics/sample_counter.cc",
+ "numerics/sample_counter.h",
+ "one_time_event.h",
+ "race_checker.cc",
+ "race_checker.h",
+ "random.cc",
+ "random.h",
+ "rate_statistics.cc",
+ "rate_statistics.h",
+ "rate_tracker.cc",
+ "rate_tracker.h",
+ "swap_queue.h",
+ "timestamp_aligner.cc",
+ "timestamp_aligner.h",
+ "trace_event.h",
+ "zero_memory.cc",
+ "zero_memory.h",
+ ]
+
+ if (is_win) {
+ sources += [
+ "win/windows_version.cc",
+ "win/windows_version.h",
+ ]
+ data_deps = [ "//build/win:runtime_libs" ]
+ }
+
+ if (is_nacl) {
+ public_deps += # no-presubmit-check TODO(webrtc:8603)
+ [ "//native_client_sdk/src/libraries/nacl_io" ]
+ }
+
+ if (is_android) {
+ libs = [ "log" ]
+ }
+
+ public_deps += [ # no-presubmit-check TODO(webrtc:8603)
+ ":atomicops",
+ ":criticalsection",
+ ":logging",
+ ":macromagic",
+ ":platform_thread",
+ ":platform_thread_types",
+ ":refcount",
+ ":rtc_event",
+ ":safe_conversions",
+ ":stringutils",
+ ":thread_checker",
+ ":timeutils",
+ "synchronization:sequence_checker",
+ ]
+}
+
+rtc_source_set("macromagic") {
+ # TODO(bugs.webrtc.org/9606): This should not be public.
+ visibility = [ "*" ]
+ sources = [
+ "arraysize.h",
+ "constructor_magic.h",
+ "format_macros.h",
+ "thread_annotations.h",
+ ]
+ deps = [ "system:arch" ]
+}
+
+rtc_library("platform_thread_types") {
+ sources = [
+ "platform_thread_types.cc",
+ "platform_thread_types.h",
+ ]
+ deps = [ ":macromagic" ]
+}
+
+rtc_source_set("refcount") {
+ visibility = [ "*" ]
+ sources = [
+ "ref_count.h",
+ "ref_counted_object.h",
+ "ref_counter.h",
+ ]
+ deps = [ ":macromagic" ]
+}
+
+rtc_library("criticalsection") {
+ sources = [
+ "deprecated/recursive_critical_section.cc",
+ "deprecated/recursive_critical_section.h",
+ ]
+ deps = [
+ ":atomicops",
+ ":checks",
+ ":macromagic",
+ ":platform_thread_types",
+ "synchronization:yield",
+ "system:unused",
+ ]
+}
+
+rtc_library("platform_thread") {
+ visibility = [
+ ":rtc_base_approved",
+ ":rtc_task_queue_libevent",
+ ":rtc_task_queue_stdlib",
+ ":rtc_task_queue_win",
+ "synchronization:mutex",
+ "synchronization:sequence_checker",
+ ]
+ sources = [
+ "platform_thread.cc",
+ "platform_thread.h",
+ ]
+ deps = [
+ ":atomicops",
+ ":checks",
+ ":macromagic",
+ ":platform_thread_types",
+ ":rtc_event",
+ ":thread_checker",
+ ":timeutils",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_library("rtc_event") {
+ if (build_with_chromium) {
+ sources = [
+ "../../webrtc_overrides/rtc_base/event.cc",
+ "../../webrtc_overrides/rtc_base/event.h",
+ ]
+ deps = [
+ ":checks",
+ "system:rtc_export", # Only Chromium's rtc::Event use RTC_EXPORT.
+ "//base", # Dependency on chromium's waitable_event.
+ ]
+ } else {
+ sources = [
+ "event.cc",
+ "event.h",
+ ]
+ deps = [
+ ":checks",
+ "synchronization:yield_policy",
+ "system:warn_current_thread_is_deadlocked",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+ }
+}
+
+rtc_library("logging") {
+ visibility = [ "*" ]
+ libs = []
+ deps = [
+ ":checks",
+ ":criticalsection",
+ ":macromagic",
+ ":platform_thread_types",
+ ":stringutils",
+ ":timeutils",
+ "synchronization:mutex",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/base:core_headers",
+ "//third_party/abseil-cpp/absl/meta:type_traits",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+
+ if (build_with_chromium) {
+ # Dependency on chromium's logging (in //base).
+ deps += [ "//base" ]
+ sources = [
+ "../../webrtc_overrides/rtc_base/logging.cc",
+ "../../webrtc_overrides/rtc_base/logging.h",
+ ]
+ } else {
+ configs += [
+ "..:no_exit_time_destructors",
+ "..:no_global_constructors",
+ ]
+ sources = [
+ "logging.cc",
+ "logging.h",
+ ]
+ deps += [ "system:inline" ]
+
+ if (is_mac) {
+ frameworks = [ "Foundation.framework" ]
+ }
+
+ # logging.h needs the deprecation header while downstream projects are
+ # removing code that depends on logging implementation details.
+ deps += [ ":deprecation" ]
+
+ if (is_android) {
+ libs += [ "log" ]
+ }
+ }
+}
+
+rtc_source_set("thread_checker") {
+ sources = [ "thread_checker.h" ]
+ deps = [
+ ":deprecation",
+ "synchronization:sequence_checker",
+ ]
+}
+
+rtc_source_set("atomicops") {
+ sources = [ "atomic_ops.h" ]
+}
+
+rtc_library("checks") {
+ # TODO(bugs.webrtc.org/9607): This should not be public.
+ visibility = [ "*" ]
+ libs = []
+ sources = [
+ "checks.cc",
+ "checks.h",
+ ]
+ deps = [
+ ":safe_compare",
+ "system:inline",
+ "system:rtc_export",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/meta:type_traits",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+ if (is_android) {
+ libs += [ "log" ]
+ }
+}
+
+rtc_library("rate_limiter") {
+ sources = [
+ "rate_limiter.cc",
+ "rate_limiter.h",
+ ]
+ deps = [
+ ":rtc_base_approved",
+ "../system_wrappers",
+ "synchronization:mutex",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_source_set("sanitizer") {
+ sources = [ "sanitizer.h" ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/meta:type_traits" ]
+}
+
+rtc_source_set("bounded_inline_vector") {
+ public = [ "bounded_inline_vector.h" ]
+ sources = [ "bounded_inline_vector_impl.h" ]
+ deps = [ ":checks" ]
+}
+
+rtc_source_set("divide_round") {
+ sources = [ "numerics/divide_round.h" ]
+ deps = [
+ ":checks",
+ ":safe_compare",
+ ]
+}
+
+rtc_source_set("safe_compare") {
+ sources = [ "numerics/safe_compare.h" ]
+ deps = [ ":type_traits" ]
+}
+
+rtc_source_set("safe_minmax") {
+ sources = [ "numerics/safe_minmax.h" ]
+ deps = [
+ ":checks",
+ ":safe_compare",
+ ":type_traits",
+ ]
+}
+
+rtc_source_set("safe_conversions") {
+ sources = [
+ "numerics/safe_conversions.h",
+ "numerics/safe_conversions_impl.h",
+ ]
+ deps = [ ":checks" ]
+}
+
+rtc_library("timeutils") {
+ visibility = [ "*" ]
+ sources = [
+ "time_utils.cc",
+ "time_utils.h",
+ ]
+ deps = [
+ ":checks",
+ ":safe_conversions",
+ ":stringutils",
+ "system:rtc_export",
+ ]
+ libs = []
+ if (is_win) {
+ libs += [ "winmm.lib" ]
+ }
+}
+
+rtc_library("stringutils") {
+ sources = [
+ "string_encode.cc",
+ "string_encode.h",
+ "string_to_number.cc",
+ "string_to_number.h",
+ "string_utils.cc",
+ "string_utils.h",
+ "strings/string_builder.cc",
+ "strings/string_builder.h",
+ "strings/string_format.cc",
+ "strings/string_format.h",
+ ]
+ deps = [
+ ":checks",
+ ":macromagic",
+ ":safe_minmax",
+ "../api:array_view",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+rtc_library("audio_format_to_string") {
+ sources = [
+ "strings/audio_format_to_string.cc",
+ "strings/audio_format_to_string.h",
+ ]
+ deps = [
+ ":stringutils",
+ "../api/audio_codecs:audio_codecs_api",
+ ]
+}
+
+rtc_source_set("type_traits") {
+ sources = [ "type_traits.h" ]
+}
+
+rtc_source_set("deprecation") {
+ sources = [ "deprecation.h" ]
+}
+
+rtc_library("rtc_task_queue") {
+ visibility = [ "*" ]
+ sources = [
+ "task_queue.cc",
+ "task_queue.h",
+ ]
+ deps = [
+ ":macromagic",
+ "../api/task_queue",
+ "system:rtc_export",
+ "task_utils:to_queued_task",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/memory" ]
+}
+
+rtc_source_set("rtc_operations_chain") {
+ visibility = [ "*" ]
+ sources = [
+ "operations_chain.cc",
+ "operations_chain.h",
+ ]
+ deps = [
+ ":checks",
+ ":macromagic",
+ ":refcount",
+ "../api:scoped_refptr",
+ "synchronization:sequence_checker",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+if (rtc_enable_libevent) {
+ rtc_library("rtc_task_queue_libevent") {
+ visibility = [ "../api/task_queue:default_task_queue_factory" ]
+ sources = [
+ "task_queue_libevent.cc",
+ "task_queue_libevent.h",
+ ]
+ deps = [
+ ":checks",
+ ":criticalsection",
+ ":logging",
+ ":macromagic",
+ ":platform_thread",
+ ":platform_thread_types",
+ ":safe_conversions",
+ ":timeutils",
+ "../api/task_queue",
+ "synchronization:mutex",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/container:inlined_vector",
+ "//third_party/abseil-cpp/absl/strings",
+ ]
+ if (rtc_build_libevent) {
+ deps += [ "//base/third_party/libevent" ]
+ }
+ }
+}
+
+if (is_mac || is_ios) {
+ rtc_library("rtc_task_queue_gcd") {
+ visibility = [ "../api/task_queue:default_task_queue_factory" ]
+ sources = [
+ "task_queue_gcd.cc",
+ "task_queue_gcd.h",
+ ]
+ deps = [
+ ":checks",
+ ":logging",
+ "../api/task_queue",
+ "synchronization:mutex",
+ "system:gcd_helpers",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+ }
+}
+
+if (is_win) {
+ rtc_library("rtc_task_queue_win") {
+ visibility = [ "../api/task_queue:default_task_queue_factory" ]
+ sources = [
+ "task_queue_win.cc",
+ "task_queue_win.h",
+ ]
+ deps = [
+ ":checks",
+ ":criticalsection",
+ ":logging",
+ ":macromagic",
+ ":platform_thread",
+ ":rtc_event",
+ ":safe_conversions",
+ ":timeutils",
+ "../api/task_queue",
+ "synchronization:mutex",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+ }
+}
+
+rtc_library("rtc_task_queue_stdlib") {
+ sources = [
+ "task_queue_stdlib.cc",
+ "task_queue_stdlib.h",
+ ]
+ deps = [
+ ":checks",
+ ":criticalsection",
+ ":logging",
+ ":macromagic",
+ ":platform_thread",
+ ":rtc_event",
+ ":safe_conversions",
+ ":timeutils",
+ "../api/task_queue",
+ "synchronization:mutex",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_library("weak_ptr") {
+ sources = [
+ "weak_ptr.cc",
+ "weak_ptr.h",
+ ]
+ deps = [
+ ":refcount",
+ "../api:scoped_refptr",
+ "synchronization:sequence_checker",
+ ]
+}
+
+rtc_library("rtc_numerics") {
+ sources = [
+ "numerics/event_based_exponential_moving_average.cc",
+ "numerics/event_based_exponential_moving_average.h",
+ "numerics/exp_filter.cc",
+ "numerics/exp_filter.h",
+ "numerics/math_utils.h",
+ "numerics/moving_average.cc",
+ "numerics/moving_average.h",
+ "numerics/moving_median_filter.h",
+ "numerics/percentile_filter.h",
+ "numerics/running_statistics.h",
+ "numerics/sequence_number_util.h",
+ ]
+ deps = [
+ ":checks",
+ ":rtc_base_approved",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_library("rtc_stats_counters") {
+ sources = [
+ "numerics/event_rate_counter.cc",
+ "numerics/event_rate_counter.h",
+ "numerics/sample_stats.cc",
+ "numerics/sample_stats.h",
+ ]
+ deps = [
+ "../api/numerics",
+ "../api/units:data_rate",
+ "../api/units:time_delta",
+ "../api/units:timestamp",
+ ]
+ absl_deps = []
+}
+
+config("rtc_json_suppressions") {
+ if (!is_win || is_clang) {
+ cflags_cc = [
+ # TODO(bugs.webrtc.org/10770): Update jsoncpp API usage and remove
+ # -Wno-deprecated-declarations.
+ "-Wno-deprecated-declarations",
+
+ # TODO(bugs.webrtc.org/10814): Remove -Wno-undef as soon as it get
+ # removed upstream.
+ "-Wno-undef",
+ ]
+ }
+}
+
+rtc_library("rtc_json") {
+ public_configs = [ ":rtc_json_suppressions" ]
+ poisonous = [ "rtc_json" ]
+ defines = []
+ sources = [
+ "strings/json.cc",
+ "strings/json.h",
+ ]
+ deps = [ ":stringutils" ]
+ all_dependent_configs = [ "//third_party/jsoncpp:jsoncpp_config" ]
+ if (rtc_build_json) {
+ public_deps = # no-presubmit-check TODO(webrtc:8603)
+ [ "//third_party/jsoncpp" ]
+ } else {
+ include_dirs = [ "$rtc_jsoncpp_root" ]
+
+ # When defined changes the include path for json.h to where it is
+ # expected to be when building json outside of the standalone build.
+ defines += [ "WEBRTC_EXTERNAL_JSON" ]
+ }
+}
+
+rtc_source_set("net_helpers") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "net_helpers.cc",
+ # "net_helpers.h",
+ # ]
+}
+
+rtc_source_set("async_resolver_interface") {
+ visibility = [ "*" ]
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "async_resolver_interface.cc",
+ # "async_resolver_interface.h",
+ # ]
+}
+
+rtc_source_set("ip_address") {
+ visibility = [ "*" ]
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "ip_address.cc",
+ # "ip_address.h",
+ # ]
+}
+
+rtc_source_set("socket_address") {
+ visibility = [ "*" ]
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "socket_address.cc",
+ # "socket_address.h",
+ # ]
+}
+
+rtc_source_set("null_socket_server") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "null_socket_server.cc",
+ # "null_socket_server.h",
+ # ]
+}
+
+rtc_source_set("socket_server") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "socket_server.h",
+ # ]
+}
+
+rtc_source_set("threading") {
+ visibility = [ "*" ]
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "asyncresolver.cc",
+ # "asyncresolver.h",
+ # "defaultsocketserver.cc",
+ # "defaultsocketserver.h",
+ # "message_handler.cc",
+ # "message_handler.h",
+ # "network_monitor.cc",
+ # "network_monitor.h",
+ # "network_monitor_factory.cc",
+ # "network_monitor_factory.h",
+ # "physical_socket_server.cc",
+ # "physical_socket_server.h",
+ # "signal_thread.cc",
+ # "signal_thread.h",
+ # "thread.cc",
+ # "thread.h",
+ # ]
+}
+
+rtc_source_set("socket_factory") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "socket_factory.h",
+ # ]
+}
+
+rtc_source_set("async_socket") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "async_socket.cc",
+ # "async_socket.h",
+ # ]
+}
+
+rtc_source_set("socket") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "socket.cc",
+ # "socket.h",
+ # ]
+}
+
+rtc_source_set("network_constants") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "network_constants.h",
+ # ]
+}
+
+if (is_android) {
+ rtc_source_set("ifaddrs_android") {
+ # TODO(bugs.webrtc.org/9987): This build target will soon contain
+ # the following files:
+ # sources = [
+ # "ifaddrs_android.cc",
+ # "ifaddrs_android.h",
+ # ]
+ }
+}
+
+if (is_win) {
+ rtc_source_set("win32") {
+ sources = [
+ "win32.cc",
+ "win32.h",
+ "win32_window.cc",
+ "win32_window.h",
+ ]
+
+ deps = [
+ ":checks",
+ ":macromagic",
+ ":rtc_base_approved",
+ ]
+
+ libs = [
+ "crypt32.lib",
+ "iphlpapi.lib",
+ "secur32.lib",
+ ]
+
+ defines = [ "_CRT_NONSTDC_NO_DEPRECATE" ]
+ }
+}
+
+rtc_library("rtc_base") {
+ visibility = [ "*" ]
+ cflags = []
+ cflags_cc = []
+ libs = []
+ defines = []
+ deps = [
+ ":checks",
+ ":deprecation",
+ ":rtc_task_queue",
+ ":stringutils",
+ "../api:array_view",
+ "../api:function_view",
+ "../api:scoped_refptr",
+ "../api/numerics",
+ "../api/task_queue",
+ "../system_wrappers:field_trial",
+ "network:sent_packet",
+ "synchronization:mutex",
+ "synchronization:sequence_checker",
+ "system:file_wrapper",
+ "system:inline",
+ "system:rtc_export",
+ "task_utils:pending_task_safety_flag",
+ "task_utils:repeating_task",
+ "task_utils:to_queued_task",
+ "third_party/base64",
+ "third_party/sigslot",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/algorithm:container",
+ "//third_party/abseil-cpp/absl/container:flat_hash_map",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ public_deps = [ ":rtc_base_approved" ] # no-presubmit-check TODO(webrtc:8603)
+ public_configs = []
+
+ sources = [
+ "async_invoker.cc",
+ "async_invoker.h",
+ "async_invoker_inl.h",
+ "async_packet_socket.cc",
+ "async_packet_socket.h",
+ "async_resolver_interface.cc",
+ "async_resolver_interface.h",
+ "async_socket.cc",
+ "async_socket.h",
+ "async_tcp_socket.cc",
+ "async_tcp_socket.h",
+ "async_udp_socket.cc",
+ "async_udp_socket.h",
+ "crc32.cc",
+ "crc32.h",
+ "crypt_string.cc",
+ "crypt_string.h",
+ "data_rate_limiter.cc",
+ "data_rate_limiter.h",
+ "deprecated/signal_thread.cc",
+ "deprecated/signal_thread.h",
+ "dscp.h",
+ "file_rotating_stream.cc",
+ "file_rotating_stream.h",
+ "helpers.cc",
+ "helpers.h",
+ "http_common.cc",
+ "http_common.h",
+ "ip_address.cc",
+ "ip_address.h",
+ "keep_ref_until_done.h",
+ "mdns_responder_interface.h",
+ "message_digest.cc",
+ "message_digest.h",
+ "message_handler.cc",
+ "message_handler.h",
+ "net_helper.cc",
+ "net_helper.h",
+ "net_helpers.cc",
+ "net_helpers.h",
+ "network.cc",
+ "network.h",
+ "network_constants.cc",
+ "network_constants.h",
+ "network_monitor.cc",
+ "network_monitor.h",
+ "network_monitor_factory.cc",
+ "network_monitor_factory.h",
+ "network_route.cc",
+ "network_route.h",
+ "null_socket_server.cc",
+ "null_socket_server.h",
+ "openssl.h",
+ "openssl_adapter.cc",
+ "openssl_adapter.h",
+ "openssl_certificate.cc",
+ "openssl_certificate.h",
+ "openssl_digest.cc",
+ "openssl_digest.h",
+ "openssl_identity.cc",
+ "openssl_identity.h",
+ "openssl_session_cache.cc",
+ "openssl_session_cache.h",
+ "openssl_stream_adapter.cc",
+ "openssl_stream_adapter.h",
+ "openssl_utility.cc",
+ "openssl_utility.h",
+ "physical_socket_server.cc",
+ "physical_socket_server.h",
+ "proxy_info.cc",
+ "proxy_info.h",
+ "rtc_certificate.cc",
+ "rtc_certificate.h",
+ "rtc_certificate_generator.cc",
+ "rtc_certificate_generator.h",
+ "signal_thread.h",
+ "sigslot_repeater.h",
+ "socket.cc",
+ "socket.h",
+ "socket_adapters.cc",
+ "socket_adapters.h",
+ "socket_address.cc",
+ "socket_address.h",
+ "socket_address_pair.cc",
+ "socket_address_pair.h",
+ "socket_factory.h",
+ "socket_server.h",
+ "ssl_adapter.cc",
+ "ssl_adapter.h",
+ "ssl_certificate.cc",
+ "ssl_certificate.h",
+ "ssl_fingerprint.cc",
+ "ssl_fingerprint.h",
+ "ssl_identity.cc",
+ "ssl_identity.h",
+ "ssl_stream_adapter.cc",
+ "ssl_stream_adapter.h",
+ "stream.cc",
+ "stream.h",
+ "thread.cc",
+ "thread.h",
+ "thread_message.h",
+ "unique_id_generator.cc",
+ "unique_id_generator.h",
+ ]
+
+ if (build_with_chromium) {
+ include_dirs = [ "../../boringssl/src/include" ]
+ public_configs += [ ":rtc_base_chromium_config" ]
+ } else {
+ sources += [
+ "callback.h",
+ "log_sinks.cc",
+ "log_sinks.h",
+ "rolling_accumulator.h",
+ "ssl_roots.h",
+ ]
+
+ deps += [ ":rtc_numerics" ]
+
+ if (is_win) {
+ sources += [ "win32_socket_init.h" ]
+ if (current_os != "winuwp") {
+ sources += [
+ "win32_socket_server.cc",
+ "win32_socket_server.h",
+ ]
+ }
+ }
+ } # !build_with_chromium
+
+ if (rtc_build_ssl) {
+ deps += [ "//third_party/boringssl" ]
+ } else {
+ configs += [ ":external_ssl_library" ]
+ }
+
+ if (is_android) {
+ sources += [
+ "ifaddrs_android.cc",
+ "ifaddrs_android.h",
+ ]
+
+ libs += [
+ "log",
+ "GLESv2",
+ ]
+ }
+
+ if (is_ios || is_mac) {
+ sources += [ "mac_ifaddrs_converter.cc" ]
+ deps += [ "system:cocoa_threading" ]
+ }
+
+ if (is_linux || is_chromeos) {
+ libs += [
+ "dl",
+ "rt",
+ ]
+ }
+
+ if (is_ios) {
+ frameworks = [
+ "CFNetwork.framework",
+ "Foundation.framework",
+ "Security.framework",
+ "SystemConfiguration.framework",
+ "UIKit.framework",
+ ]
+ }
+
+ if (is_win) {
+ deps += [ ":win32" ]
+ }
+
+ if (is_posix || is_fuchsia) {
+ sources += [
+ "ifaddrs_converter.cc",
+ "ifaddrs_converter.h",
+ ]
+ }
+
+ if (is_nacl) {
+ public_deps += # no-presubmit-check TODO(webrtc:8603)
+ [ "//native_client_sdk/src/libraries/nacl_io" ]
+
+ defines += [ "timezone=_timezone" ]
+ sources -= [ "ifaddrs_converter.cc" ]
+ }
+}
+
+rtc_source_set("gtest_prod") {
+ sources = [ "gtest_prod_util.h" ]
+}
+
+rtc_library("gunit_helpers") {
+ testonly = true
+ sources = [
+ "gunit.cc",
+ "gunit.h",
+ ]
+ deps = [
+ ":logging",
+ ":rtc_base",
+ ":rtc_base_tests_utils",
+ ":stringutils",
+ "../test:test_support",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_library("testclient") {
+ testonly = true
+ sources = [
+ "test_client.cc",
+ "test_client.h",
+ ]
+ deps = [
+ ":criticalsection",
+ ":gunit_helpers",
+ ":rtc_base",
+ ":rtc_base_tests_utils",
+ ":timeutils",
+ "synchronization:mutex",
+ ]
+}
+
+rtc_library("robo_caller_unittests") {
+ testonly = true
+
+ sources = [ "robo_caller_unittest.cc" ]
+ deps = [
+ ":gunit_helpers",
+ ":robo_caller",
+ ":rtc_base",
+ "../api:function_view",
+ "../test:test_support",
+ ]
+}
+
+rtc_library("rtc_base_tests_utils") {
+ testonly = true
+ sources = [
+ "cpu_time.cc",
+ "cpu_time.h",
+ "fake_clock.cc",
+ "fake_clock.h",
+ "fake_mdns_responder.h",
+ "fake_network.h",
+ "fake_ssl_identity.cc",
+ "fake_ssl_identity.h",
+ "firewall_socket_server.cc",
+ "firewall_socket_server.h",
+ "memory_stream.cc",
+ "memory_stream.h",
+ "memory_usage.cc",
+ "memory_usage.h",
+ "nat_server.cc",
+ "nat_server.h",
+ "nat_socket_factory.cc",
+ "nat_socket_factory.h",
+ "nat_types.cc",
+ "nat_types.h",
+ "proxy_server.cc",
+ "proxy_server.h",
+ "server_socket_adapters.cc",
+ "server_socket_adapters.h",
+ "sigslot_tester.h",
+ "socket_stream.cc",
+ "socket_stream.h",
+ "test_base64.h",
+ "test_certificate_verifier.h",
+ "test_echo_server.cc",
+ "test_echo_server.h",
+ "test_utils.cc",
+ "test_utils.h",
+ "virtual_socket_server.cc",
+ "virtual_socket_server.h",
+ ]
+ deps = [
+ ":checks",
+ ":rtc_base",
+ "../api/units:time_delta",
+ "../api/units:timestamp",
+ "memory:fifo_buffer",
+ "synchronization:mutex",
+ "third_party/sigslot",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/algorithm:container",
+ "//third_party/abseil-cpp/absl/memory",
+ ]
+}
+
+rtc_library("task_queue_for_test") {
+ testonly = true
+
+ sources = [
+ "task_queue_for_test.cc",
+ "task_queue_for_test.h",
+ ]
+ deps = [
+ ":checks",
+ ":rtc_base_approved",
+ ":rtc_event",
+ ":rtc_task_queue",
+ "../api/task_queue",
+ "../api/task_queue:default_task_queue_factory",
+ "task_utils:to_queued_task",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("sigslot_unittest") {
+ testonly = true
+ sources = [ "sigslot_unittest.cc" ]
+ deps = [
+ ":gunit_helpers",
+ ":rtc_base",
+ ":rtc_base_tests_utils",
+ "../test:test_support",
+ "synchronization:mutex",
+ "third_party/sigslot",
+ ]
+ }
+
+ rtc_library("untyped_function_unittest") {
+ testonly = true
+ sources = [ "untyped_function_unittest.cc" ]
+ deps = [
+ ":untyped_function",
+ "../test:test_support",
+ ]
+ }
+
+ rtc_library("rtc_base_nonparallel_tests") {
+ testonly = true
+
+ sources = [
+ "cpu_time_unittest.cc",
+ "file_rotating_stream_unittest.cc",
+ "null_socket_server_unittest.cc",
+ "physical_socket_server_unittest.cc",
+ "socket_address_unittest.cc",
+ "socket_unittest.cc",
+ "socket_unittest.h",
+ ]
+ deps = [
+ ":checks",
+ ":gunit_helpers",
+ ":rtc_base",
+ ":rtc_base_tests_utils",
+ ":testclient",
+ "../system_wrappers",
+ "../test:fileutils",
+ "../test:test_main",
+ "../test:test_support",
+ "third_party/sigslot",
+ "//testing/gtest",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/memory" ]
+ if (is_win) {
+ sources += [ "win32_socket_server_unittest.cc" ]
+ }
+ }
+
+ rtc_library("rtc_base_approved_unittests") {
+ testonly = true
+ sources = [
+ "atomic_ops_unittest.cc",
+ "base64_unittest.cc",
+ "bind_unittest.cc",
+ "bit_buffer_unittest.cc",
+ "bounded_inline_vector_unittest.cc",
+ "buffer_queue_unittest.cc",
+ "buffer_unittest.cc",
+ "byte_buffer_unittest.cc",
+ "byte_order_unittest.cc",
+ "checks_unittest.cc",
+ "copy_on_write_buffer_unittest.cc",
+ "deprecated/recursive_critical_section_unittest.cc",
+ "event_tracer_unittest.cc",
+ "event_unittest.cc",
+ "logging_unittest.cc",
+ "numerics/divide_round_unittest.cc",
+ "numerics/histogram_percentile_counter_unittest.cc",
+ "numerics/mod_ops_unittest.cc",
+ "numerics/moving_max_counter_unittest.cc",
+ "numerics/safe_compare_unittest.cc",
+ "numerics/safe_minmax_unittest.cc",
+ "numerics/sample_counter_unittest.cc",
+ "one_time_event_unittest.cc",
+ "platform_thread_unittest.cc",
+ "random_unittest.cc",
+ "rate_limiter_unittest.cc",
+ "rate_statistics_unittest.cc",
+ "rate_tracker_unittest.cc",
+ "ref_counted_object_unittest.cc",
+ "sanitizer_unittest.cc",
+ "string_encode_unittest.cc",
+ "string_to_number_unittest.cc",
+ "string_utils_unittest.cc",
+ "strings/string_builder_unittest.cc",
+ "strings/string_format_unittest.cc",
+ "swap_queue_unittest.cc",
+ "thread_annotations_unittest.cc",
+ "thread_checker_unittest.cc",
+ "time_utils_unittest.cc",
+ "timestamp_aligner_unittest.cc",
+ "virtual_socket_unittest.cc",
+ "zero_memory_unittest.cc",
+ ]
+ if (is_win) {
+ sources += [ "win/windows_version_unittest.cc" ]
+ }
+ deps = [
+ ":bounded_inline_vector",
+ ":checks",
+ ":divide_round",
+ ":gunit_helpers",
+ ":rate_limiter",
+ ":rtc_base",
+ ":rtc_base_approved",
+ ":rtc_base_tests_utils",
+ ":rtc_numerics",
+ ":rtc_task_queue",
+ ":safe_compare",
+ ":safe_minmax",
+ ":sanitizer",
+ ":stringutils",
+ ":testclient",
+ "../api:array_view",
+ "../api:scoped_refptr",
+ "../api/numerics",
+ "../api/units:time_delta",
+ "../system_wrappers",
+ "../test:fileutils",
+ "../test:test_main",
+ "../test:test_support",
+ "memory:unittests",
+ "synchronization:mutex",
+ "task_utils:to_queued_task",
+ "third_party/base64",
+ "third_party/sigslot",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/base:core_headers",
+ "//third_party/abseil-cpp/absl/memory",
+ ]
+ }
+
+ rtc_library("rtc_task_queue_unittests") {
+ testonly = true
+
+ sources = [ "task_queue_unittest.cc" ]
+ deps = [
+ ":gunit_helpers",
+ ":rtc_base_approved",
+ ":rtc_base_tests_utils",
+ ":rtc_task_queue",
+ ":task_queue_for_test",
+ "../test:test_main",
+ "../test:test_support",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/memory" ]
+ }
+
+ rtc_library("rtc_operations_chain_unittests") {
+ testonly = true
+
+ sources = [ "operations_chain_unittest.cc" ]
+ deps = [
+ ":gunit_helpers",
+ ":rtc_base",
+ ":rtc_base_approved",
+ ":rtc_event",
+ ":rtc_operations_chain",
+ "../test:test_support",
+ ]
+ }
+
+ rtc_library("weak_ptr_unittests") {
+ testonly = true
+
+ sources = [ "weak_ptr_unittest.cc" ]
+ deps = [
+ ":gunit_helpers",
+ ":rtc_base_approved",
+ ":rtc_base_tests_utils",
+ ":rtc_event",
+ ":task_queue_for_test",
+ ":weak_ptr",
+ "../test:test_main",
+ "../test:test_support",
+ ]
+ }
+
+ rtc_library("rtc_numerics_unittests") {
+ testonly = true
+
+ sources = [
+ "numerics/event_based_exponential_moving_average_unittest.cc",
+ "numerics/exp_filter_unittest.cc",
+ "numerics/moving_average_unittest.cc",
+ "numerics/moving_median_filter_unittest.cc",
+ "numerics/percentile_filter_unittest.cc",
+ "numerics/running_statistics_unittest.cc",
+ "numerics/sequence_number_util_unittest.cc",
+ ]
+ deps = [
+ ":rtc_base_approved",
+ ":rtc_numerics",
+ "../test:test_main",
+ "../test:test_support",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ]
+ }
+
+ rtc_library("rtc_json_unittests") {
+ testonly = true
+
+ sources = [ "strings/json_unittest.cc" ]
+ deps = [
+ ":gunit_helpers",
+ ":rtc_base_tests_utils",
+ ":rtc_json",
+ "../test:test_main",
+ "../test:test_support",
+ ]
+ }
+
+ rtc_library("rtc_base_unittests") {
+ testonly = true
+ defines = []
+
+ sources = [
+ "callback_unittest.cc",
+ "crc32_unittest.cc",
+ "data_rate_limiter_unittest.cc",
+ "deprecated/signal_thread_unittest.cc",
+ "fake_clock_unittest.cc",
+ "helpers_unittest.cc",
+ "ip_address_unittest.cc",
+ "memory_usage_unittest.cc",
+ "message_digest_unittest.cc",
+ "nat_unittest.cc",
+ "network_route_unittest.cc",
+ "network_unittest.cc",
+ "proxy_unittest.cc",
+ "rolling_accumulator_unittest.cc",
+ "rtc_certificate_generator_unittest.cc",
+ "rtc_certificate_unittest.cc",
+ "sigslot_tester_unittest.cc",
+ "test_client_unittest.cc",
+ "thread_unittest.cc",
+ "unique_id_generator_unittest.cc",
+ ]
+ deps = [
+ ":checks",
+ ":gunit_helpers",
+ ":rtc_base_tests_utils",
+ ":stringutils",
+ ":testclient",
+ "../api:array_view",
+ "../api/task_queue",
+ "../api/task_queue:task_queue_test",
+ "../test:field_trial",
+ "../test:fileutils",
+ "../test:rtc_expect_death",
+ "../test:test_main",
+ "../test:test_support",
+ "memory:fifo_buffer",
+ "synchronization:mutex",
+ "synchronization:synchronization_unittests",
+ "task_utils:pending_task_safety_flag",
+ "task_utils:to_queued_task",
+ "third_party/sigslot",
+ ]
+ if (is_win) {
+ sources += [
+ "win32_unittest.cc",
+ "win32_window_unittest.cc",
+ ]
+ deps += [ ":win32" ]
+ }
+ if (is_posix || is_fuchsia) {
+ sources += [
+ "openssl_adapter_unittest.cc",
+ "openssl_session_cache_unittest.cc",
+ "openssl_utility_unittest.cc",
+ "ssl_adapter_unittest.cc",
+ "ssl_identity_unittest.cc",
+ "ssl_stream_adapter_unittest.cc",
+ ]
+ }
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/algorithm:container",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ public_deps = [ ":rtc_base" ] # no-presubmit-check TODO(webrtc:8603)
+ if (build_with_chromium) {
+ include_dirs = [ "../../boringssl/src/include" ]
+ }
+ if (rtc_build_ssl) {
+ deps += [ "//third_party/boringssl" ]
+ } else {
+ configs += [ ":external_ssl_library" ]
+ }
+ }
+}
+
+if (is_android) {
+ rtc_android_library("base_java") {
+ visibility = [ "*" ]
+ sources = [
+ "java/src/org/webrtc/ContextUtils.java",
+ "java/src/org/webrtc/Loggable.java",
+ "java/src/org/webrtc/Logging.java",
+ "java/src/org/webrtc/Size.java",
+ "java/src/org/webrtc/ThreadUtils.java",
+ ]
+ deps = [
+ "//third_party/android_deps:com_android_support_support_annotations_java",
+ ]
+ }
+ java_cpp_enum("network_monitor_enums") {
+ sources = [ "network_monitor.h" ]
+ visibility = [ "*" ]
+ }
+}
diff --git a/webrtc/base/arraysize.h b/webrtc/rtc_base/arraysize.h
index 56a1039..bf8e6d8 100644
--- a/webrtc/base/arraysize.h
+++ b/webrtc/rtc_base/arraysize.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_BASE_ARRAYSIZE_H_
-#define WEBRTC_BASE_ARRAYSIZE_H_
+#ifndef RTC_BASE_ARRAYSIZE_H_
+#define RTC_BASE_ARRAYSIZE_H_
#include <stddef.h>
@@ -24,8 +24,9 @@
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
-template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
-#endif // WEBRTC_BASE_ARRAYSIZE_H_
+#endif // RTC_BASE_ARRAYSIZE_H_
diff --git a/webrtc/base/atomicops.h b/webrtc/rtc_base/atomic_ops.h
index a863566..18a24a8 100644
--- a/webrtc/base/atomicops.h
+++ b/webrtc/rtc_base/atomic_ops.h
@@ -8,16 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_BASE_ATOMICOPS_H_
-#define WEBRTC_BASE_ATOMICOPS_H_
+#ifndef RTC_BASE_ATOMIC_OPS_H_
+#define RTC_BASE_ATOMIC_OPS_H_
#if defined(WEBRTC_WIN)
+// clang-format off
+// clang formating would change include order.
+
// Include winsock2.h before including <windows.h> to maintain consistency with
-// win32.h. We can't include win32.h directly here since it pulls in
-// headers such as basictypes.h which causes problems in Chromium where webrtc
-// exists as two separate projects, webrtc and libjingle.
+// win32.h. To include win32.h directly, it must be broken out into its own
+// build target.
#include <winsock2.h>
#include <windows.h>
+// clang-format on
#endif // defined(WEBRTC_WIN)
namespace rtc {
@@ -31,24 +34,25 @@ class AtomicOps {
static int Decrement(volatile int* i) {
return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
}
- static int AcquireLoad(volatile const int* i) {
- return *i;
- }
- static void ReleaseStore(volatile int* i, int value) {
- *i = value;
- }
+ static int AcquireLoad(volatile const int* i) { return *i; }
+ static void ReleaseStore(volatile int* i, int value) { *i = value; }
static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
return ::InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(i),
- new_value,
- old_value);
+ new_value, old_value);
}
-#else
- static int Increment(volatile int* i) {
- return __sync_add_and_fetch(i, 1);
+ // Pointer variants.
+ template <typename T>
+ static T* AcquireLoadPtr(T* volatile* ptr) {
+ return *ptr;
}
- static int Decrement(volatile int* i) {
- return __sync_sub_and_fetch(i, 1);
+ template <typename T>
+ static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) {
+ return static_cast<T*>(::InterlockedCompareExchangePointer(
+ reinterpret_cast<PVOID volatile*>(ptr), new_value, old_value));
}
+#else
+ static int Increment(volatile int* i) { return __sync_add_and_fetch(i, 1); }
+ static int Decrement(volatile int* i) { return __sync_sub_and_fetch(i, 1); }
static int AcquireLoad(volatile const int* i) {
return __atomic_load_n(i, __ATOMIC_ACQUIRE);
}
@@ -58,11 +62,18 @@ class AtomicOps {
static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
return __sync_val_compare_and_swap(i, old_value, new_value);
}
+ // Pointer variants.
+ template <typename T>
+ static T* AcquireLoadPtr(T* volatile* ptr) {
+ return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
+ }
+ template <typename T>
+ static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) {
+ return __sync_val_compare_and_swap(ptr, old_value, new_value);
+ }
#endif
};
+} // namespace rtc
-
-}
-
-#endif // WEBRTC_BASE_ATOMICOPS_H_
+#endif // RTC_BASE_ATOMIC_OPS_H_
diff --git a/webrtc/rtc_base/buffer.h b/webrtc/rtc_base/buffer.h
new file mode 100644
index 0000000..d1639e2
--- /dev/null
+++ b/webrtc/rtc_base/buffer.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_BUFFER_H_
+#define RTC_BASE_BUFFER_H_
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <cstring>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "api/array_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/type_traits.h"
+#include "rtc_base/zero_memory.h"
+
+namespace rtc {
+
+namespace internal {
+
+// (Internal; please don't use outside this file.) Determines if elements of
+// type U are compatible with a BufferT<T>. For most types, we just ignore
+// top-level const and forbid top-level volatile and require T and U to be
+// otherwise equal, but all byte-sized integers (notably char, int8_t, and
+// uint8_t) are compatible with each other. (Note: We aim to get rid of this
+// behavior, and treat all types the same.)
+template <typename T, typename U>
+struct BufferCompat {
+ static constexpr bool value =
+ !std::is_volatile<U>::value &&
+ ((std::is_integral<T>::value && sizeof(T) == 1)
+ ? (std::is_integral<U>::value && sizeof(U) == 1)
+ : (std::is_same<T, typename std::remove_const<U>::type>::value));
+};
+
+} // namespace internal
+
+// Basic buffer class, can be grown and shrunk dynamically.
+// Unlike std::string/vector, does not initialize data when increasing size.
+// If "ZeroOnFree" is true, any memory is explicitly cleared before releasing.
+// The type alias "ZeroOnFreeBuffer" below should be used instead of setting
+// "ZeroOnFree" in the template manually to "true".
+template <typename T, bool ZeroOnFree = false>
+class BufferT {
+ // We want T's destructor and default constructor to be trivial, i.e. perform
+ // no action, so that we don't have to touch the memory we allocate and
+ // deallocate. And we want T to be trivially copyable, so that we can copy T
+ // instances with std::memcpy. This is precisely the definition of a trivial
+ // type.
+ static_assert(std::is_trivial<T>::value, "T must be a trivial type.");
+
+ // This class relies heavily on being able to mutate its data.
+ static_assert(!std::is_const<T>::value, "T may not be const");
+
+ public:
+ using value_type = T;
+ using const_iterator = const T*;
+
+ // An empty BufferT.
+ BufferT() : size_(0), capacity_(0), data_(nullptr) {
+ RTC_DCHECK(IsConsistent());
+ }
+
+ // Disable copy construction and copy assignment, since copying a buffer is
+ // expensive enough that we want to force the user to be explicit about it.
+ BufferT(const BufferT&) = delete;
+ BufferT& operator=(const BufferT&) = delete;
+
+ BufferT(BufferT&& buf)
+ : size_(buf.size()),
+ capacity_(buf.capacity()),
+ data_(std::move(buf.data_)) {
+ RTC_DCHECK(IsConsistent());
+ buf.OnMovedFrom();
+ }
+
+ // Construct a buffer with the specified number of uninitialized elements.
+ explicit BufferT(size_t size) : BufferT(size, size) {}
+
+ BufferT(size_t size, size_t capacity)
+ : size_(size),
+ capacity_(std::max(size, capacity)),
+ data_(capacity_ > 0 ? new T[capacity_] : nullptr) {
+ RTC_DCHECK(IsConsistent());
+ }
+
+ // Construct a buffer and copy the specified number of elements into it.
+ template <typename U,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ BufferT(const U* data, size_t size) : BufferT(data, size, size) {}
+
+ template <typename U,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ BufferT(U* data, size_t size, size_t capacity) : BufferT(size, capacity) {
+ static_assert(sizeof(T) == sizeof(U), "");
+ std::memcpy(data_.get(), data, size * sizeof(U));
+ }
+
+ // Construct a buffer from the contents of an array.
+ template <typename U,
+ size_t N,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ BufferT(U (&array)[N]) : BufferT(array, N) {}
+
+ ~BufferT() { MaybeZeroCompleteBuffer(); }
+
+ // Get a pointer to the data. Just .data() will give you a (const) T*, but if
+ // T is a byte-sized integer, you may also use .data<U>() for any other
+ // byte-sized integer U.
+ template <typename U = T,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ const U* data() const {
+ RTC_DCHECK(IsConsistent());
+ return reinterpret_cast<U*>(data_.get());
+ }
+
+ template <typename U = T,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ U* data() {
+ RTC_DCHECK(IsConsistent());
+ return reinterpret_cast<U*>(data_.get());
+ }
+
+ bool empty() const {
+ RTC_DCHECK(IsConsistent());
+ return size_ == 0;
+ }
+
+ size_t size() const {
+ RTC_DCHECK(IsConsistent());
+ return size_;
+ }
+
+ size_t capacity() const {
+ RTC_DCHECK(IsConsistent());
+ return capacity_;
+ }
+
+ BufferT& operator=(BufferT&& buf) {
+ RTC_DCHECK(buf.IsConsistent());
+ MaybeZeroCompleteBuffer();
+ size_ = buf.size_;
+ capacity_ = buf.capacity_;
+ using std::swap;
+ swap(data_, buf.data_);
+ buf.data_.reset();
+ buf.OnMovedFrom();
+ return *this;
+ }
+
+ bool operator==(const BufferT& buf) const {
+ RTC_DCHECK(IsConsistent());
+ if (size_ != buf.size_) {
+ return false;
+ }
+ if (std::is_integral<T>::value) {
+ // Optimization.
+ return std::memcmp(data_.get(), buf.data_.get(), size_ * sizeof(T)) == 0;
+ }
+ for (size_t i = 0; i < size_; ++i) {
+ if (data_[i] != buf.data_[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool operator!=(const BufferT& buf) const { return !(*this == buf); }
+
+ T& operator[](size_t index) {
+ RTC_DCHECK_LT(index, size_);
+ return data()[index];
+ }
+
+ T operator[](size_t index) const {
+ RTC_DCHECK_LT(index, size_);
+ return data()[index];
+ }
+
+ T* begin() { return data(); }
+ T* end() { return data() + size(); }
+ const T* begin() const { return data(); }
+ const T* end() const { return data() + size(); }
+ const T* cbegin() const { return data(); }
+ const T* cend() const { return data() + size(); }
+
+ // The SetData functions replace the contents of the buffer. They accept the
+ // same input types as the constructors.
+ template <typename U,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ void SetData(const U* data, size_t size) {
+ RTC_DCHECK(IsConsistent());
+ const size_t old_size = size_;
+ size_ = 0;
+ AppendData(data, size);
+ if (ZeroOnFree && size_ < old_size) {
+ ZeroTrailingData(old_size - size_);
+ }
+ }
+
+ template <typename U,
+ size_t N,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ void SetData(const U (&array)[N]) {
+ SetData(array, N);
+ }
+
+ template <typename W,
+ typename std::enable_if<
+ HasDataAndSize<const W, const T>::value>::type* = nullptr>
+ void SetData(const W& w) {
+ SetData(w.data(), w.size());
+ }
+
+ // Replaces the data in the buffer with at most |max_elements| of data, using
+ // the function |setter|, which should have the following signature:
+ //
+ // size_t setter(ArrayView<U> view)
+ //
+ // |setter| is given an appropriately typed ArrayView of length exactly
+ // |max_elements| that describes the area where it should write the data; it
+ // should return the number of elements actually written. (If it doesn't fill
+ // the whole ArrayView, it should leave the unused space at the end.)
+ template <typename U = T,
+ typename F,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ size_t SetData(size_t max_elements, F&& setter) {
+ RTC_DCHECK(IsConsistent());
+ const size_t old_size = size_;
+ size_ = 0;
+ const size_t written = AppendData<U>(max_elements, std::forward<F>(setter));
+ if (ZeroOnFree && size_ < old_size) {
+ ZeroTrailingData(old_size - size_);
+ }
+ return written;
+ }
+
+ // The AppendData functions add data to the end of the buffer. They accept
+ // the same input types as the constructors.
+ template <typename U,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ void AppendData(const U* data, size_t size) {
+ RTC_DCHECK(IsConsistent());
+ const size_t new_size = size_ + size;
+ EnsureCapacityWithHeadroom(new_size, true);
+ static_assert(sizeof(T) == sizeof(U), "");
+ std::memcpy(data_.get() + size_, data, size * sizeof(U));
+ size_ = new_size;
+ RTC_DCHECK(IsConsistent());
+ }
+
+ template <typename U,
+ size_t N,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ void AppendData(const U (&array)[N]) {
+ AppendData(array, N);
+ }
+
+ template <typename W,
+ typename std::enable_if<
+ HasDataAndSize<const W, const T>::value>::type* = nullptr>
+ void AppendData(const W& w) {
+ AppendData(w.data(), w.size());
+ }
+
+ template <typename U,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ void AppendData(const U& item) {
+ AppendData(&item, 1);
+ }
+
+ // Appends at most |max_elements| to the end of the buffer, using the function
+ // |setter|, which should have the following signature:
+ //
+ // size_t setter(ArrayView<U> view)
+ //
+ // |setter| is given an appropriately typed ArrayView of length exactly
+ // |max_elements| that describes the area where it should write the data; it
+ // should return the number of elements actually written. (If it doesn't fill
+ // the whole ArrayView, it should leave the unused space at the end.)
+ template <typename U = T,
+ typename F,
+ typename std::enable_if<
+ internal::BufferCompat<T, U>::value>::type* = nullptr>
+ size_t AppendData(size_t max_elements, F&& setter) {
+ RTC_DCHECK(IsConsistent());
+ const size_t old_size = size_;
+ SetSize(old_size + max_elements);
+ U* base_ptr = data<U>() + old_size;
+ size_t written_elements = setter(rtc::ArrayView<U>(base_ptr, max_elements));
+
+ RTC_CHECK_LE(written_elements, max_elements);
+ size_ = old_size + written_elements;
+ RTC_DCHECK(IsConsistent());
+ return written_elements;
+ }
+
+ // Sets the size of the buffer. If the new size is smaller than the old, the
+ // buffer contents will be kept but truncated; if the new size is greater,
+ // the existing contents will be kept and the new space will be
+ // uninitialized.
+ void SetSize(size_t size) {
+ const size_t old_size = size_;
+ EnsureCapacityWithHeadroom(size, true);
+ size_ = size;
+ if (ZeroOnFree && size_ < old_size) {
+ ZeroTrailingData(old_size - size_);
+ }
+ }
+
+ // Ensure that the buffer size can be increased to at least capacity without
+ // further reallocation. (Of course, this operation might need to reallocate
+ // the buffer.)
+ void EnsureCapacity(size_t capacity) {
+ // Don't allocate extra headroom, since the user is asking for a specific
+ // capacity.
+ EnsureCapacityWithHeadroom(capacity, false);
+ }
+
+ // Resets the buffer to zero size without altering capacity. Works even if the
+ // buffer has been moved from.
+ void Clear() {
+ MaybeZeroCompleteBuffer();
+ size_ = 0;
+ RTC_DCHECK(IsConsistent());
+ }
+
+ // Swaps two buffers. Also works for buffers that have been moved from.
+ friend void swap(BufferT& a, BufferT& b) {
+ using std::swap;
+ swap(a.size_, b.size_);
+ swap(a.capacity_, b.capacity_);
+ swap(a.data_, b.data_);
+ }
+
+ private:
+ void EnsureCapacityWithHeadroom(size_t capacity, bool extra_headroom) {
+ RTC_DCHECK(IsConsistent());
+ if (capacity <= capacity_)
+ return;
+
+ // If the caller asks for extra headroom, ensure that the new capacity is
+ // >= 1.5 times the old capacity. Any constant > 1 is sufficient to prevent
+ // quadratic behavior; as to why we pick 1.5 in particular, see
+ // https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md and
+ // http://www.gahcep.com/cpp-internals-stl-vector-part-1/.
+ const size_t new_capacity =
+ extra_headroom ? std::max(capacity, capacity_ + capacity_ / 2)
+ : capacity;
+
+ std::unique_ptr<T[]> new_data(new T[new_capacity]);
+ if (data_ != nullptr) {
+ std::memcpy(new_data.get(), data_.get(), size_ * sizeof(T));
+ }
+ MaybeZeroCompleteBuffer();
+ data_ = std::move(new_data);
+ capacity_ = new_capacity;
+ RTC_DCHECK(IsConsistent());
+ }
+
+ // Zero the complete buffer if template argument "ZeroOnFree" is true.
+ void MaybeZeroCompleteBuffer() {
+ if (ZeroOnFree && capacity_ > 0) {
+ // It would be sufficient to only zero "size_" elements, as all other
+ // methods already ensure that the unused capacity contains no sensitive
+ // data---but better safe than sorry.
+ ExplicitZeroMemory(data_.get(), capacity_ * sizeof(T));
+ }
+ }
+
+ // Zero the first "count" elements of unused capacity.
+ void ZeroTrailingData(size_t count) {
+ RTC_DCHECK(IsConsistent());
+ RTC_DCHECK_LE(count, capacity_ - size_);
+ ExplicitZeroMemory(data_.get() + size_, count * sizeof(T));
+ }
+
+ // Precondition for all methods except Clear, operator= and the destructor.
+ // Postcondition for all methods except move construction and move
+ // assignment, which leave the moved-from object in a possibly inconsistent
+ // state.
+ bool IsConsistent() const {
+ return (data_ || capacity_ == 0) && capacity_ >= size_;
+ }
+
+ // Called when *this has been moved from. Conceptually it's a no-op, but we
+ // can mutate the state slightly to help subsequent sanity checks catch bugs.
+ void OnMovedFrom() {
+ RTC_DCHECK(!data_); // Our heap block should have been stolen.
+#if RTC_DCHECK_IS_ON
+ // Ensure that *this is always inconsistent, to provoke bugs.
+ size_ = 1;
+ capacity_ = 0;
+#else
+ // Make *this consistent and empty. Shouldn't be necessary, but better safe
+ // than sorry.
+ size_ = 0;
+ capacity_ = 0;
+#endif
+ }
+
+ size_t size_;
+ size_t capacity_;
+ std::unique_ptr<T[]> data_;
+};
+
+// By far the most common sort of buffer.
+using Buffer = BufferT<uint8_t>;
+
+// A buffer that zeros memory before releasing it.
+template <typename T>
+using ZeroOnFreeBuffer = BufferT<T, true>;
+
+} // namespace rtc
+
+#endif // RTC_BASE_BUFFER_H_
diff --git a/webrtc/rtc_base/checks.cc b/webrtc/rtc_base/checks.cc
new file mode 100644
index 0000000..e5fc2ed
--- /dev/null
+++ b/webrtc/rtc_base/checks.cc
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2006 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// Most of this was borrowed (with minor modifications) from V8's and Chromium's
+// src/base/logging.cc.
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+#if defined(WEBRTC_ANDROID)
+#define RTC_LOG_TAG_ANDROID "rtc"
+#include <android/log.h> // NOLINT
+#endif
+
+#if defined(WEBRTC_WIN)
+#include <windows.h>
+#endif
+
+#if defined(WEBRTC_WIN)
+#define LAST_SYSTEM_ERROR (::GetLastError())
+#elif defined(__native_client__) && __native_client__
+#define LAST_SYSTEM_ERROR (0)
+#elif defined(WEBRTC_POSIX)
+#include <errno.h>
+#define LAST_SYSTEM_ERROR (errno)
+#endif // WEBRTC_WIN
+
+#include "rtc_base/checks.h"
+
+namespace {
+#if defined(__GNUC__)
+__attribute__((__format__(__printf__, 2, 3)))
+#endif
+void AppendFormat(std::string* s, const char* fmt, ...) {
+ va_list args, copy;
+ va_start(args, fmt);
+ va_copy(copy, args);
+ const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
+ va_end(copy);
+
+ if (predicted_length > 0) {
+ const size_t size = s->size();
+ s->resize(size + predicted_length);
+ // Pass "+ 1" to vsnprintf to include space for the '\0'.
+ std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args);
+ }
+ va_end(args);
+}
+} // namespace
+
+namespace rtc {
+namespace webrtc_checks_impl {
+
+#if RTC_CHECK_MSG_ENABLED
+// Reads one argument from args, appends it to s and advances fmt.
+// Returns true iff an argument was sucessfully parsed.
+bool ParseArg(va_list* args, const CheckArgType** fmt, std::string* s) {
+ if (**fmt == CheckArgType::kEnd)
+ return false;
+
+ switch (**fmt) {
+ case CheckArgType::kInt:
+ AppendFormat(s, "%d", va_arg(*args, int));
+ break;
+ case CheckArgType::kLong:
+ AppendFormat(s, "%ld", va_arg(*args, long));
+ break;
+ case CheckArgType::kLongLong:
+ AppendFormat(s, "%lld", va_arg(*args, long long));
+ break;
+ case CheckArgType::kUInt:
+ AppendFormat(s, "%u", va_arg(*args, unsigned));
+ break;
+ case CheckArgType::kULong:
+ AppendFormat(s, "%lu", va_arg(*args, unsigned long));
+ break;
+ case CheckArgType::kULongLong:
+ AppendFormat(s, "%llu", va_arg(*args, unsigned long long));
+ break;
+ case CheckArgType::kDouble:
+ AppendFormat(s, "%g", va_arg(*args, double));
+ break;
+ case CheckArgType::kLongDouble:
+ AppendFormat(s, "%Lg", va_arg(*args, long double));
+ break;
+ case CheckArgType::kCharP:
+ s->append(va_arg(*args, const char*));
+ break;
+ case CheckArgType::kStdString:
+ s->append(*va_arg(*args, const std::string*));
+ break;
+ case CheckArgType::kStringView: {
+ const absl::string_view sv = *va_arg(*args, const absl::string_view*);
+ s->append(sv.data(), sv.size());
+ break;
+ }
+ case CheckArgType::kVoidP:
+ AppendFormat(s, "%p", va_arg(*args, const void*));
+ break;
+ default:
+ s->append("[Invalid CheckArgType]");
+ return false;
+ }
+ (*fmt)++;
+ return true;
+}
+
+RTC_NORETURN void FatalLog(const char* file,
+ int line,
+ const char* message,
+ const CheckArgType* fmt,
+ ...) {
+ va_list args;
+ va_start(args, fmt);
+
+ std::string s;
+ AppendFormat(&s,
+ "\n\n"
+ "#\n"
+ "# Fatal error in: %s, line %d\n"
+ "# last system error: %u\n"
+ "# Check failed: %s",
+ file, line, LAST_SYSTEM_ERROR, message);
+
+ if (*fmt == CheckArgType::kCheckOp) {
+ // This log message was generated by RTC_CHECK_OP, so we have to complete
+ // the error message using the operands that have been passed as the first
+ // two arguments.
+ fmt++;
+
+ std::string s1, s2;
+ if (ParseArg(&args, &fmt, &s1) && ParseArg(&args, &fmt, &s2))
+ AppendFormat(&s, " (%s vs. %s)\n# ", s1.c_str(), s2.c_str());
+ } else {
+ s.append("\n# ");
+ }
+
+ // Append all the user-supplied arguments to the message.
+ while (ParseArg(&args, &fmt, &s))
+ ;
+
+ va_end(args);
+
+ const char* output = s.c_str();
+
+#if defined(WEBRTC_ANDROID)
+ __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output);
+#endif
+
+ fflush(stdout);
+ fprintf(stderr, "%s", output);
+ fflush(stderr);
+#if defined(WEBRTC_WIN)
+ DebugBreak();
+#endif
+ abort();
+}
+#else // RTC_CHECK_MSG_ENABLED
+RTC_NORETURN void FatalLog(const char* file, int line) {
+ std::string s;
+ AppendFormat(&s,
+ "\n\n"
+ "#\n"
+ "# Fatal error in: %s, line %d\n"
+ "# last system error: %u\n"
+ "# Check failed.\n"
+ "# ",
+ file, line, LAST_SYSTEM_ERROR);
+ const char* output = s.c_str();
+
+#if defined(WEBRTC_ANDROID)
+ __android_log_print(ANDROID_LOG_ERROR, RTC_LOG_TAG_ANDROID, "%s\n", output);
+#endif
+
+ fflush(stdout);
+ fprintf(stderr, "%s", output);
+ fflush(stderr);
+#if defined(WEBRTC_WIN)
+ DebugBreak();
+#endif
+ abort();
+}
+#endif // RTC_CHECK_MSG_ENABLED
+
+} // namespace webrtc_checks_impl
+} // namespace rtc
+
+// Function to call from the C version of the RTC_CHECK and RTC_DCHECK macros.
+RTC_NORETURN void rtc_FatalMessage(const char* file,
+ int line,
+ const char* msg) {
+#if RTC_CHECK_MSG_ENABLED
+ static constexpr rtc::webrtc_checks_impl::CheckArgType t[] = {
+ rtc::webrtc_checks_impl::CheckArgType::kEnd};
+ rtc::webrtc_checks_impl::FatalLog(file, line, msg, t);
+#else
+ rtc::webrtc_checks_impl::FatalLog(file, line);
+#endif
+}
diff --git a/webrtc/rtc_base/checks.h b/webrtc/rtc_base/checks.h
new file mode 100644
index 0000000..61c074a
--- /dev/null
+++ b/webrtc/rtc_base/checks.h
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2006 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_CHECKS_H_
+#define RTC_BASE_CHECKS_H_
+
+// If you for some reson need to know if DCHECKs are on, test the value of
+// RTC_DCHECK_IS_ON. (Test its value, not if it's defined; it'll always be
+// defined, to either a true or a false value.)
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define RTC_DCHECK_IS_ON 1
+#else
+#define RTC_DCHECK_IS_ON 0
+#endif
+
+// Annotate a function that will not return control flow to the caller.
+#if defined(_MSC_VER)
+#define RTC_NORETURN __declspec(noreturn)
+#elif defined(__GNUC__)
+#define RTC_NORETURN __attribute__((__noreturn__))
+#else
+#define RTC_NORETURN
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+RTC_NORETURN void rtc_FatalMessage(const char* file, int line, const char* msg);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#ifdef RTC_DISABLE_CHECK_MSG
+#define RTC_CHECK_MSG_ENABLED 0
+#else
+#define RTC_CHECK_MSG_ENABLED 1
+#endif
+
+#if RTC_CHECK_MSG_ENABLED
+#define RTC_CHECK_EVAL_MESSAGE(message) message
+#else
+#define RTC_CHECK_EVAL_MESSAGE(message) ""
+#endif
+
+#ifdef __cplusplus
+// C++ version.
+
+#include <string>
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+#include "rtc_base/numerics/safe_compare.h"
+#include "rtc_base/system/inline.h"
+#include "rtc_base/system/rtc_export.h"
+
+// The macros here print a message to stderr and abort under various
+// conditions. All will accept additional stream messages. For example:
+// RTC_DCHECK_EQ(foo, bar) << "I'm printed when foo != bar.";
+//
+// - RTC_CHECK(x) is an assertion that x is always true, and that if it isn't,
+// it's better to terminate the process than to continue. During development,
+// the reason that it's better to terminate might simply be that the error
+// handling code isn't in place yet; in production, the reason might be that
+// the author of the code truly believes that x will always be true, but that
+// they recognizes that if they are wrong, abrupt and unpleasant process
+// termination is still better than carrying on with the assumption violated.
+//
+// RTC_CHECK always evaluates its argument, so it's OK for x to have side
+// effects.
+//
+// - RTC_DCHECK(x) is the same as RTC_CHECK(x)---an assertion that x is always
+// true---except that x will only be evaluated in debug builds; in production
+// builds, x is simply assumed to be true. This is useful if evaluating x is
+// expensive and the expected cost of failing to detect the violated
+// assumption is acceptable. You should not handle cases where a production
+// build fails to spot a violated condition, even those that would result in
+// crashes. If the code needs to cope with the error, make it cope, but don't
+// call RTC_DCHECK; if the condition really can't occur, but you'd sleep
+// better at night knowing that the process will suicide instead of carrying
+// on in case you were wrong, use RTC_CHECK instead of RTC_DCHECK.
+//
+// RTC_DCHECK only evaluates its argument in debug builds, so if x has visible
+// side effects, you need to write e.g.
+// bool w = x; RTC_DCHECK(w);
+//
+// - RTC_CHECK_EQ, _NE, _GT, ..., and RTC_DCHECK_EQ, _NE, _GT, ... are
+// specialized variants of RTC_CHECK and RTC_DCHECK that print prettier
+// messages if the condition doesn't hold. Prefer them to raw RTC_CHECK and
+// RTC_DCHECK.
+//
+// - FATAL() aborts unconditionally.
+
+namespace rtc {
+namespace webrtc_checks_impl {
+enum class CheckArgType : int8_t {
+ kEnd = 0,
+ kInt,
+ kLong,
+ kLongLong,
+ kUInt,
+ kULong,
+ kULongLong,
+ kDouble,
+ kLongDouble,
+ kCharP,
+ kStdString,
+ kStringView,
+ kVoidP,
+
+ // kCheckOp doesn't represent an argument type. Instead, it is sent as the
+ // first argument from RTC_CHECK_OP to make FatalLog use the next two
+ // arguments to build the special CHECK_OP error message
+ // (the "a == b (1 vs. 2)" bit).
+ kCheckOp,
+};
+
+#if RTC_CHECK_MSG_ENABLED
+RTC_NORETURN RTC_EXPORT void FatalLog(const char* file,
+ int line,
+ const char* message,
+ const CheckArgType* fmt,
+ ...);
+#else
+RTC_NORETURN RTC_EXPORT void FatalLog(const char* file, int line);
+#endif
+
+// Wrapper for log arguments. Only ever make values of this type with the
+// MakeVal() functions.
+template <CheckArgType N, typename T>
+struct Val {
+ static constexpr CheckArgType Type() { return N; }
+ T GetVal() const { return val; }
+ T val;
+};
+
+// Case for when we need to construct a temp string and then print that.
+// (We can't use Val<CheckArgType::kStdString, const std::string*>
+// because we need somewhere to store the temp string.)
+struct ToStringVal {
+ static constexpr CheckArgType Type() { return CheckArgType::kStdString; }
+ const std::string* GetVal() const { return &val; }
+ std::string val;
+};
+
+inline Val<CheckArgType::kInt, int> MakeVal(int x) {
+ return {x};
+}
+inline Val<CheckArgType::kLong, long> MakeVal(long x) {
+ return {x};
+}
+inline Val<CheckArgType::kLongLong, long long> MakeVal(long long x) {
+ return {x};
+}
+inline Val<CheckArgType::kUInt, unsigned int> MakeVal(unsigned int x) {
+ return {x};
+}
+inline Val<CheckArgType::kULong, unsigned long> MakeVal(unsigned long x) {
+ return {x};
+}
+inline Val<CheckArgType::kULongLong, unsigned long long> MakeVal(
+ unsigned long long x) {
+ return {x};
+}
+
+inline Val<CheckArgType::kDouble, double> MakeVal(double x) {
+ return {x};
+}
+inline Val<CheckArgType::kLongDouble, long double> MakeVal(long double x) {
+ return {x};
+}
+
+inline Val<CheckArgType::kCharP, const char*> MakeVal(const char* x) {
+ return {x};
+}
+inline Val<CheckArgType::kStdString, const std::string*> MakeVal(
+ const std::string& x) {
+ return {&x};
+}
+inline Val<CheckArgType::kStringView, const absl::string_view*> MakeVal(
+ const absl::string_view& x) {
+ return {&x};
+}
+
+inline Val<CheckArgType::kVoidP, const void*> MakeVal(const void* x) {
+ return {x};
+}
+
+// The enum class types are not implicitly convertible to arithmetic types.
+template <typename T,
+ absl::enable_if_t<std::is_enum<T>::value &&
+ !std::is_arithmetic<T>::value>* = nullptr>
+inline decltype(MakeVal(std::declval<absl::underlying_type_t<T>>())) MakeVal(
+ T x) {
+ return {static_cast<absl::underlying_type_t<T>>(x)};
+}
+
+template <typename T, decltype(ToLogString(std::declval<T>()))* = nullptr>
+ToStringVal MakeVal(const T& x) {
+ return {ToLogString(x)};
+}
+
+// Ephemeral type that represents the result of the logging << operator.
+template <typename... Ts>
+class LogStreamer;
+
+// Base case: Before the first << argument.
+template <>
+class LogStreamer<> final {
+ public:
+ template <typename U,
+ typename V = decltype(MakeVal(std::declval<U>())),
+ absl::enable_if_t<std::is_arithmetic<U>::value ||
+ std::is_enum<U>::value>* = nullptr>
+ RTC_FORCE_INLINE LogStreamer<V> operator<<(U arg) const {
+ return LogStreamer<V>(MakeVal(arg), this);
+ }
+
+ template <typename U,
+ typename V = decltype(MakeVal(std::declval<U>())),
+ absl::enable_if_t<!std::is_arithmetic<U>::value &&
+ !std::is_enum<U>::value>* = nullptr>
+ RTC_FORCE_INLINE LogStreamer<V> operator<<(const U& arg) const {
+ return LogStreamer<V>(MakeVal(arg), this);
+ }
+
+#if RTC_CHECK_MSG_ENABLED
+ template <typename... Us>
+ RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file,
+ const int line,
+ const char* message,
+ const Us&... args) {
+ static constexpr CheckArgType t[] = {Us::Type()..., CheckArgType::kEnd};
+ FatalLog(file, line, message, t, args.GetVal()...);
+ }
+
+ template <typename... Us>
+ RTC_NORETURN RTC_FORCE_INLINE static void CallCheckOp(const char* file,
+ const int line,
+ const char* message,
+ const Us&... args) {
+ static constexpr CheckArgType t[] = {CheckArgType::kCheckOp, Us::Type()...,
+ CheckArgType::kEnd};
+ FatalLog(file, line, message, t, args.GetVal()...);
+ }
+#else
+ template <typename... Us>
+ RTC_NORETURN RTC_FORCE_INLINE static void Call(const char* file,
+ const int line) {
+ FatalLog(file, line);
+ }
+#endif
+};
+
+// Inductive case: We've already seen at least one << argument. The most recent
+// one had type `T`, and the earlier ones had types `Ts`.
+template <typename T, typename... Ts>
+class LogStreamer<T, Ts...> final {
+ public:
+ RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
+ : arg_(arg), prior_(prior) {}
+
+ template <typename U,
+ typename V = decltype(MakeVal(std::declval<U>())),
+ absl::enable_if_t<std::is_arithmetic<U>::value ||
+ std::is_enum<U>::value>* = nullptr>
+ RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(U arg) const {
+ return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
+ }
+
+ template <typename U,
+ typename V = decltype(MakeVal(std::declval<U>())),
+ absl::enable_if_t<!std::is_arithmetic<U>::value &&
+ !std::is_enum<U>::value>* = nullptr>
+ RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(const U& arg) const {
+ return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
+ }
+
+#if RTC_CHECK_MSG_ENABLED
+ template <typename... Us>
+ RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file,
+ const int line,
+ const char* message,
+ const Us&... args) const {
+ prior_->Call(file, line, message, arg_, args...);
+ }
+
+ template <typename... Us>
+ RTC_NORETURN RTC_FORCE_INLINE void CallCheckOp(const char* file,
+ const int line,
+ const char* message,
+ const Us&... args) const {
+ prior_->CallCheckOp(file, line, message, arg_, args...);
+ }
+#else
+ template <typename... Us>
+ RTC_NORETURN RTC_FORCE_INLINE void Call(const char* file,
+ const int line) const {
+ prior_->Call(file, line);
+ }
+#endif
+
+ private:
+ // The most recent argument.
+ T arg_;
+
+ // Earlier arguments.
+ const LogStreamer<Ts...>* prior_;
+};
+
+template <bool isCheckOp>
+class FatalLogCall final {
+ public:
+ FatalLogCall(const char* file, int line, const char* message)
+ : file_(file), line_(line), message_(message) {}
+
+ // This can be any binary operator with precedence lower than <<.
+ template <typename... Ts>
+ RTC_NORETURN RTC_FORCE_INLINE void operator&(
+ const LogStreamer<Ts...>& streamer) {
+#if RTC_CHECK_MSG_ENABLED
+ isCheckOp ? streamer.CallCheckOp(file_, line_, message_)
+ : streamer.Call(file_, line_, message_);
+#else
+ streamer.Call(file_, line_);
+#endif
+ }
+
+ private:
+ const char* file_;
+ int line_;
+ const char* message_;
+};
+
+} // namespace webrtc_checks_impl
+
+// The actual stream used isn't important. We reference |ignored| in the code
+// but don't evaluate it; this is to avoid "unused variable" warnings (we do so
+// in a particularly convoluted way with an extra ?: because that appears to be
+// the simplest construct that keeps Visual Studio from complaining about
+// condition being unused).
+#define RTC_EAT_STREAM_PARAMETERS(ignored) \
+ (true ? true : ((void)(ignored), true)) \
+ ? static_cast<void>(0) \
+ : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
+ ::rtc::webrtc_checks_impl::LogStreamer<>()
+
+// Call RTC_EAT_STREAM_PARAMETERS with an argument that fails to compile if
+// values of the same types as |a| and |b| can't be compared with the given
+// operation, and that would evaluate |a| and |b| if evaluated.
+#define RTC_EAT_STREAM_PARAMETERS_OP(op, a, b) \
+ RTC_EAT_STREAM_PARAMETERS(((void)::rtc::Safe##op(a, b)))
+
+// RTC_CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG or anything else, so the check will be executed
+// regardless of compilation mode.
+//
+// We make sure RTC_CHECK et al. always evaluates |condition|, as
+// doing RTC_CHECK(FunctionWithSideEffect()) is a common idiom.
+//
+// RTC_CHECK_OP is a helper macro for binary operators.
+// Don't use this macro directly in your code, use RTC_CHECK_EQ et al below.
+#if RTC_CHECK_MSG_ENABLED
+#define RTC_CHECK(condition) \
+ (condition) ? static_cast<void>(0) \
+ : ::rtc::webrtc_checks_impl::FatalLogCall<false>( \
+ __FILE__, __LINE__, #condition) & \
+ ::rtc::webrtc_checks_impl::LogStreamer<>()
+
+#define RTC_CHECK_OP(name, op, val1, val2) \
+ ::rtc::Safe##name((val1), (val2)) \
+ ? static_cast<void>(0) \
+ : ::rtc::webrtc_checks_impl::FatalLogCall<true>( \
+ __FILE__, __LINE__, #val1 " " #op " " #val2) & \
+ ::rtc::webrtc_checks_impl::LogStreamer<>() << (val1) << (val2)
+#else
+#define RTC_CHECK(condition) \
+ (condition) \
+ ? static_cast<void>(0) \
+ : true ? ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, \
+ __LINE__, "") & \
+ ::rtc::webrtc_checks_impl::LogStreamer<>() \
+ : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
+ ::rtc::webrtc_checks_impl::LogStreamer<>()
+
+#define RTC_CHECK_OP(name, op, val1, val2) \
+ ::rtc::Safe##name((val1), (val2)) \
+ ? static_cast<void>(0) \
+ : true ? ::rtc::webrtc_checks_impl::FatalLogCall<true>(__FILE__, \
+ __LINE__, "") & \
+ ::rtc::webrtc_checks_impl::LogStreamer<>() \
+ : ::rtc::webrtc_checks_impl::FatalLogCall<false>("", 0, "") & \
+ ::rtc::webrtc_checks_impl::LogStreamer<>()
+#endif
+
+#define RTC_CHECK_EQ(val1, val2) RTC_CHECK_OP(Eq, ==, val1, val2)
+#define RTC_CHECK_NE(val1, val2) RTC_CHECK_OP(Ne, !=, val1, val2)
+#define RTC_CHECK_LE(val1, val2) RTC_CHECK_OP(Le, <=, val1, val2)
+#define RTC_CHECK_LT(val1, val2) RTC_CHECK_OP(Lt, <, val1, val2)
+#define RTC_CHECK_GE(val1, val2) RTC_CHECK_OP(Ge, >=, val1, val2)
+#define RTC_CHECK_GT(val1, val2) RTC_CHECK_OP(Gt, >, val1, val2)
+
+// The RTC_DCHECK macro is equivalent to RTC_CHECK except that it only generates
+// code in debug builds. It does reference the condition parameter in all cases,
+// though, so callers won't risk getting warnings about unused variables.
+#if RTC_DCHECK_IS_ON
+#define RTC_DCHECK(condition) RTC_CHECK(condition)
+#define RTC_DCHECK_EQ(v1, v2) RTC_CHECK_EQ(v1, v2)
+#define RTC_DCHECK_NE(v1, v2) RTC_CHECK_NE(v1, v2)
+#define RTC_DCHECK_LE(v1, v2) RTC_CHECK_LE(v1, v2)
+#define RTC_DCHECK_LT(v1, v2) RTC_CHECK_LT(v1, v2)
+#define RTC_DCHECK_GE(v1, v2) RTC_CHECK_GE(v1, v2)
+#define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2)
+#else
+#define RTC_DCHECK(condition) RTC_EAT_STREAM_PARAMETERS(condition)
+#define RTC_DCHECK_EQ(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Eq, v1, v2)
+#define RTC_DCHECK_NE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ne, v1, v2)
+#define RTC_DCHECK_LE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Le, v1, v2)
+#define RTC_DCHECK_LT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Lt, v1, v2)
+#define RTC_DCHECK_GE(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Ge, v1, v2)
+#define RTC_DCHECK_GT(v1, v2) RTC_EAT_STREAM_PARAMETERS_OP(Gt, v1, v2)
+#endif
+
+#define RTC_UNREACHABLE_CODE_HIT false
+#define RTC_NOTREACHED() RTC_DCHECK(RTC_UNREACHABLE_CODE_HIT)
+
+// TODO(bugs.webrtc.org/8454): Add an RTC_ prefix or rename differently.
+#define FATAL() \
+ ::rtc::webrtc_checks_impl::FatalLogCall<false>(__FILE__, __LINE__, \
+ "FATAL()") & \
+ ::rtc::webrtc_checks_impl::LogStreamer<>()
+
+// Performs the integer division a/b and returns the result. CHECKs that the
+// remainder is zero.
+template <typename T>
+inline T CheckedDivExact(T a, T b) {
+ RTC_CHECK_EQ(a % b, 0) << a << " is not evenly divisible by " << b;
+ return a / b;
+}
+
+} // namespace rtc
+
+#else // __cplusplus not defined
+// C version. Lacks many features compared to the C++ version, but usage
+// guidelines are the same.
+
+#define RTC_CHECK(condition) \
+ do { \
+ if (!(condition)) { \
+ rtc_FatalMessage(__FILE__, __LINE__, \
+ RTC_CHECK_EVAL_MESSAGE("CHECK failed: " #condition)); \
+ } \
+ } while (0)
+
+#define RTC_CHECK_EQ(a, b) RTC_CHECK((a) == (b))
+#define RTC_CHECK_NE(a, b) RTC_CHECK((a) != (b))
+#define RTC_CHECK_LE(a, b) RTC_CHECK((a) <= (b))
+#define RTC_CHECK_LT(a, b) RTC_CHECK((a) < (b))
+#define RTC_CHECK_GE(a, b) RTC_CHECK((a) >= (b))
+#define RTC_CHECK_GT(a, b) RTC_CHECK((a) > (b))
+
+#define RTC_DCHECK(condition) \
+ do { \
+ if (RTC_DCHECK_IS_ON && !(condition)) { \
+ rtc_FatalMessage(__FILE__, __LINE__, \
+ RTC_CHECK_EVAL_MESSAGE("DCHECK failed: " #condition)); \
+ } \
+ } while (0)
+
+#define RTC_DCHECK_EQ(a, b) RTC_DCHECK((a) == (b))
+#define RTC_DCHECK_NE(a, b) RTC_DCHECK((a) != (b))
+#define RTC_DCHECK_LE(a, b) RTC_DCHECK((a) <= (b))
+#define RTC_DCHECK_LT(a, b) RTC_DCHECK((a) < (b))
+#define RTC_DCHECK_GE(a, b) RTC_DCHECK((a) >= (b))
+#define RTC_DCHECK_GT(a, b) RTC_DCHECK((a) > (b))
+
+#endif // __cplusplus
+
+#endif // RTC_BASE_CHECKS_H_
diff --git a/webrtc/system_wrappers/include/compile_assert_c.h b/webrtc/rtc_base/compile_assert_c.h
index b402d71..db2e4a8 100644
--- a/webrtc/system_wrappers/include/compile_assert_c.h
+++ b/webrtc/rtc_base/compile_assert_c.h
@@ -8,17 +8,18 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_COMPILE_ASSERT_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_COMPILE_ASSERT_H_
-
-#ifdef __cplusplus
-#error "Only use this for C files. For C++, use static_assert."
-#endif
+#ifndef RTC_BASE_COMPILE_ASSERT_C_H_
+#define RTC_BASE_COMPILE_ASSERT_C_H_
// Use this macro to verify at compile time that certain restrictions are met.
// The argument is the boolean expression to evaluate.
// Example:
-// COMPILE_ASSERT(sizeof(foo) < 128);
-#define COMPILE_ASSERT(expression) switch (0) {case 0: case expression:;}
+// RTC_COMPILE_ASSERT(sizeof(foo) < 128);
+// Note: In C++, use static_assert instead!
+#define RTC_COMPILE_ASSERT(expression) \
+ switch (0) { \
+ case 0: \
+ case expression:; \
+ }
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_COMPILE_ASSERT_H_
+#endif // RTC_BASE_COMPILE_ASSERT_C_H_
diff --git a/webrtc/rtc_base/constructor_magic.h b/webrtc/rtc_base/constructor_magic.h
new file mode 100644
index 0000000..8d12a7b
--- /dev/null
+++ b/webrtc/rtc_base/constructor_magic.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_CONSTRUCTOR_MAGIC_H_
+#define RTC_BASE_CONSTRUCTOR_MAGIC_H_
+
+// A macro to disallow the copy constructor and operator= functions. This should
+// be used in the declarations for a class.
+#define RTC_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ TypeName& operator=(const TypeName&) = delete
+
+#endif // RTC_BASE_CONSTRUCTOR_MAGIC_H_
diff --git a/webrtc/rtc_base/deprecation.h b/webrtc/rtc_base/deprecation.h
new file mode 100644
index 0000000..f285ab0
--- /dev/null
+++ b/webrtc/rtc_base/deprecation.h
@@ -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.
+ */
+
+#ifndef RTC_BASE_DEPRECATION_H_
+#define RTC_BASE_DEPRECATION_H_
+
+// Annotate the declarations of deprecated functions with this to cause a
+// compiler warning when they're used. Like so:
+//
+// RTC_DEPRECATED std::pony PonyPlz(const std::pony_spec& ps);
+//
+// NOTE 1: The annotation goes on the declaration in the .h file, not the
+// definition in the .cc file!
+//
+// NOTE 2: In order to keep unit testing the deprecated function without
+// getting warnings, do something like this:
+//
+// std::pony DEPRECATED_PonyPlz(const std::pony_spec& ps);
+// RTC_DEPRECATED inline std::pony PonyPlz(const std::pony_spec& ps) {
+// return DEPRECATED_PonyPlz(ps);
+// }
+//
+// In other words, rename the existing function, and provide an inline wrapper
+// using the original name that calls it. That way, callers who are willing to
+// call it using the DEPRECATED_-prefixed name don't get the warning.
+//
+// TODO(kwiberg): Remove this when we can use [[deprecated]] from C++14.
+#if defined(_MSC_VER)
+// Note: Deprecation warnings seem to fail to trigger on Windows
+// (https://bugs.chromium.org/p/webrtc/issues/detail?id=5368).
+#define RTC_DEPRECATED __declspec(deprecated)
+#elif defined(__GNUC__)
+#define RTC_DEPRECATED __attribute__((__deprecated__))
+#else
+#define RTC_DEPRECATED
+#endif
+
+#endif // RTC_BASE_DEPRECATION_H_
diff --git a/webrtc/rtc_base/event.cc b/webrtc/rtc_base/event.cc
new file mode 100644
index 0000000..67c8746
--- /dev/null
+++ b/webrtc/rtc_base/event.cc
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/event.h"
+
+#if defined(WEBRTC_WIN)
+#include <windows.h>
+#elif defined(WEBRTC_POSIX)
+#include <errno.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <time.h>
+#else
+#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
+#endif
+
+#include "absl/types/optional.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/synchronization/yield_policy.h"
+#include "rtc_base/system/warn_current_thread_is_deadlocked.h"
+
+namespace rtc {
+
+Event::Event() : Event(false, false) {}
+
+#if defined(WEBRTC_WIN)
+
+Event::Event(bool manual_reset, bool initially_signaled) {
+ event_handle_ = ::CreateEvent(nullptr, // Security attributes.
+ manual_reset, initially_signaled,
+ nullptr); // Name.
+ RTC_CHECK(event_handle_);
+}
+
+Event::~Event() {
+ CloseHandle(event_handle_);
+}
+
+void Event::Set() {
+ SetEvent(event_handle_);
+}
+
+void Event::Reset() {
+ ResetEvent(event_handle_);
+}
+
+bool Event::Wait(const int give_up_after_ms, int /*warn_after_ms*/) {
+ ScopedYieldPolicy::YieldExecution();
+ const DWORD ms = give_up_after_ms == kForever ? INFINITE : give_up_after_ms;
+ return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
+}
+
+#elif defined(WEBRTC_POSIX)
+
+// On MacOS, clock_gettime is available from version 10.12, and on
+// iOS, from version 10.0. So we can't use it yet.
+#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
+#define USE_CLOCK_GETTIME 0
+#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
+// On Android, pthread_condattr_setclock is available from version 21. By
+// default, we target a new enough version for 64-bit platforms but not for
+// 32-bit platforms. For older versions, use
+// pthread_cond_timedwait_monotonic_np.
+#elif defined(WEBRTC_ANDROID) && (__ANDROID_API__ < 21)
+#define USE_CLOCK_GETTIME 1
+#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 1
+#else
+#define USE_CLOCK_GETTIME 1
+#define USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP 0
+#endif
+
+Event::Event(bool manual_reset, bool initially_signaled)
+ : is_manual_reset_(manual_reset), event_status_(initially_signaled) {
+ RTC_CHECK(pthread_mutex_init(&event_mutex_, nullptr) == 0);
+ pthread_condattr_t cond_attr;
+ RTC_CHECK(pthread_condattr_init(&cond_attr) == 0);
+#if USE_CLOCK_GETTIME && !USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
+ RTC_CHECK(pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC) == 0);
+#endif
+ RTC_CHECK(pthread_cond_init(&event_cond_, &cond_attr) == 0);
+ pthread_condattr_destroy(&cond_attr);
+}
+
+Event::~Event() {
+ pthread_mutex_destroy(&event_mutex_);
+ pthread_cond_destroy(&event_cond_);
+}
+
+void Event::Set() {
+ pthread_mutex_lock(&event_mutex_);
+ event_status_ = true;
+ pthread_cond_broadcast(&event_cond_);
+ pthread_mutex_unlock(&event_mutex_);
+}
+
+void Event::Reset() {
+ pthread_mutex_lock(&event_mutex_);
+ event_status_ = false;
+ pthread_mutex_unlock(&event_mutex_);
+}
+
+namespace {
+
+timespec GetTimespec(const int milliseconds_from_now) {
+ timespec ts;
+
+ // Get the current time.
+#if USE_CLOCK_GETTIME
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+#else
+ timeval tv;
+ gettimeofday(&tv, nullptr);
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+#endif
+
+ // Add the specified number of milliseconds to it.
+ ts.tv_sec += (milliseconds_from_now / 1000);
+ ts.tv_nsec += (milliseconds_from_now % 1000) * 1000000;
+
+ // Normalize.
+ if (ts.tv_nsec >= 1000000000) {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000;
+ }
+
+ return ts;
+}
+
+} // namespace
+
+bool Event::Wait(const int give_up_after_ms, const int warn_after_ms) {
+ // Instant when we'll log a warning message (because we've been waiting so
+ // long it might be a bug), but not yet give up waiting. nullopt if we
+ // shouldn't log a warning.
+ const absl::optional<timespec> warn_ts =
+ warn_after_ms == kForever ||
+ (give_up_after_ms != kForever && warn_after_ms > give_up_after_ms)
+ ? absl::nullopt
+ : absl::make_optional(GetTimespec(warn_after_ms));
+
+ // Instant when we'll stop waiting and return an error. nullopt if we should
+ // never give up.
+ const absl::optional<timespec> give_up_ts =
+ give_up_after_ms == kForever
+ ? absl::nullopt
+ : absl::make_optional(GetTimespec(give_up_after_ms));
+
+ ScopedYieldPolicy::YieldExecution();
+ pthread_mutex_lock(&event_mutex_);
+
+ // Wait for `event_cond_` to trigger and `event_status_` to be set, with the
+ // given timeout (or without a timeout if none is given).
+ const auto wait = [&](const absl::optional<timespec> timeout_ts) {
+ int error = 0;
+ while (!event_status_ && error == 0) {
+ if (timeout_ts == absl::nullopt) {
+ error = pthread_cond_wait(&event_cond_, &event_mutex_);
+ } else {
+#if USE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
+ error = pthread_cond_timedwait_monotonic_np(&event_cond_, &event_mutex_,
+ &*timeout_ts);
+#else
+ error =
+ pthread_cond_timedwait(&event_cond_, &event_mutex_, &*timeout_ts);
+#endif
+ }
+ }
+ return error;
+ };
+
+ int error;
+ if (warn_ts == absl::nullopt) {
+ error = wait(give_up_ts);
+ } else {
+ error = wait(warn_ts);
+ if (error == ETIMEDOUT) {
+ webrtc::WarnThatTheCurrentThreadIsProbablyDeadlocked();
+ error = wait(give_up_ts);
+ }
+ }
+
+ // NOTE(liulk): Exactly one thread will auto-reset this event. All
+ // the other threads will think it's unsignaled. This seems to be
+ // consistent with auto-reset events in WEBRTC_WIN
+ if (error == 0 && !is_manual_reset_)
+ event_status_ = false;
+
+ pthread_mutex_unlock(&event_mutex_);
+
+ return (error == 0);
+}
+
+#endif
+
+} // namespace rtc
diff --git a/webrtc/rtc_base/event.h b/webrtc/rtc_base/event.h
new file mode 100644
index 0000000..584ad5d
--- /dev/null
+++ b/webrtc/rtc_base/event.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_EVENT_H_
+#define RTC_BASE_EVENT_H_
+
+#if defined(WEBRTC_WIN)
+#include <windows.h>
+#elif defined(WEBRTC_POSIX)
+#include <pthread.h>
+#else
+#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
+#endif
+
+namespace rtc {
+
+class Event {
+ public:
+ static const int kForever = -1;
+
+ Event();
+ Event(bool manual_reset, bool initially_signaled);
+ Event(const Event&) = delete;
+ Event& operator=(const Event&) = delete;
+ ~Event();
+
+ void Set();
+ void Reset();
+
+ // Waits for the event to become signaled, but logs a warning if it takes more
+ // than `warn_after_ms` milliseconds, and gives up completely if it takes more
+ // than `give_up_after_ms` milliseconds. (If `warn_after_ms >=
+ // give_up_after_ms`, no warning will be logged.) Either or both may be
+ // `kForever`, which means wait indefinitely.
+ //
+ // Returns true if the event was signaled, false if there was a timeout or
+ // some other error.
+ bool Wait(int give_up_after_ms, int warn_after_ms);
+
+ // Waits with the given timeout and a reasonable default warning timeout.
+ bool Wait(int give_up_after_ms) {
+ return Wait(give_up_after_ms,
+ give_up_after_ms == kForever ? 3000 : kForever);
+ }
+
+ private:
+#if defined(WEBRTC_WIN)
+ HANDLE event_handle_;
+#elif defined(WEBRTC_POSIX)
+ pthread_mutex_t event_mutex_;
+ pthread_cond_t event_cond_;
+ const bool is_manual_reset_;
+ bool event_status_;
+#endif
+};
+
+// These classes are provided for compatibility with Chromium.
+// The rtc::Event implementation is overriden inside of Chromium for the
+// purposes of detecting when threads are blocked that shouldn't be as well as
+// to use the more accurate event implementation that's there than is provided
+// by default on some platforms (e.g. Windows).
+// When building with standalone WebRTC, this class is a noop.
+// For further information, please see the
+// ScopedAllowBaseSyncPrimitives(ForTesting) classes in Chromium.
+class ScopedAllowBaseSyncPrimitives {
+ public:
+ ScopedAllowBaseSyncPrimitives() {}
+ ~ScopedAllowBaseSyncPrimitives() {}
+};
+
+class ScopedAllowBaseSyncPrimitivesForTesting {
+ public:
+ ScopedAllowBaseSyncPrimitivesForTesting() {}
+ ~ScopedAllowBaseSyncPrimitivesForTesting() {}
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_EVENT_H_
diff --git a/webrtc/rtc_base/event_tracer.cc b/webrtc/rtc_base/event_tracer.cc
new file mode 100644
index 0000000..3af8183
--- /dev/null
+++ b/webrtc/rtc_base/event_tracer.cc
@@ -0,0 +1,412 @@
+/*
+ * 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 "rtc_base/event_tracer.h"
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/event.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/platform_thread.h"
+#include "rtc_base/platform_thread_types.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
+#include "rtc_base/thread_checker.h"
+#include "rtc_base/time_utils.h"
+#include "rtc_base/trace_event.h"
+
+// This is a guesstimate that should be enough in most cases.
+static const size_t kEventLoggerArgsStrBufferInitialSize = 256;
+static const size_t kTraceArgBufferLength = 32;
+
+namespace webrtc {
+
+namespace {
+
+GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr;
+AddTraceEventPtr g_add_trace_event_ptr = nullptr;
+
+} // namespace
+
+void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
+ AddTraceEventPtr add_trace_event_ptr) {
+ g_get_category_enabled_ptr = get_category_enabled_ptr;
+ g_add_trace_event_ptr = add_trace_event_ptr;
+}
+
+const unsigned char* EventTracer::GetCategoryEnabled(const char* name) {
+ if (g_get_category_enabled_ptr)
+ return g_get_category_enabled_ptr(name);
+
+ // A string with null terminator means category is disabled.
+ return reinterpret_cast<const unsigned char*>("\0");
+}
+
+// Arguments to this function (phase, etc.) are as defined in
+// webrtc/rtc_base/trace_event.h.
+void EventTracer::AddTraceEvent(char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ unsigned char flags) {
+ if (g_add_trace_event_ptr) {
+ g_add_trace_event_ptr(phase, category_enabled, name, id, num_args,
+ arg_names, arg_types, arg_values, flags);
+ }
+}
+
+} // namespace webrtc
+
+namespace rtc {
+namespace tracing {
+namespace {
+
+static void EventTracingThreadFunc(void* params);
+
+// Atomic-int fast path for avoiding logging when disabled.
+static volatile int g_event_logging_active = 0;
+
+// TODO(pbos): Log metadata for all threads, etc.
+class EventLogger final {
+ public:
+ EventLogger()
+ : logging_thread_(EventTracingThreadFunc,
+ this,
+ "EventTracingThread",
+ kLowPriority) {}
+ ~EventLogger() { RTC_DCHECK(thread_checker_.IsCurrent()); }
+
+ void AddTraceEvent(const char* name,
+ const unsigned char* category_enabled,
+ char phase,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ uint64_t timestamp,
+ int pid,
+ rtc::PlatformThreadId thread_id) {
+ std::vector<TraceArg> args(num_args);
+ for (int i = 0; i < num_args; ++i) {
+ TraceArg& arg = args[i];
+ arg.name = arg_names[i];
+ arg.type = arg_types[i];
+ arg.value.as_uint = arg_values[i];
+
+ // Value is a pointer to a temporary string, so we have to make a copy.
+ if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
+ // Space for the string and for the terminating null character.
+ size_t str_length = strlen(arg.value.as_string) + 1;
+ char* str_copy = new char[str_length];
+ memcpy(str_copy, arg.value.as_string, str_length);
+ arg.value.as_string = str_copy;
+ }
+ }
+ webrtc::MutexLock lock(&mutex_);
+ trace_events_.push_back(
+ {name, category_enabled, phase, args, timestamp, 1, thread_id});
+ }
+
+ // The TraceEvent format is documented here:
+ // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+ void Log() {
+ RTC_DCHECK(output_file_);
+ static const int kLoggingIntervalMs = 100;
+ fprintf(output_file_, "{ \"traceEvents\": [\n");
+ bool has_logged_event = false;
+ while (true) {
+ bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs);
+ std::vector<TraceEvent> events;
+ {
+ webrtc::MutexLock lock(&mutex_);
+ trace_events_.swap(events);
+ }
+ std::string args_str;
+ args_str.reserve(kEventLoggerArgsStrBufferInitialSize);
+ for (TraceEvent& e : events) {
+ args_str.clear();
+ if (!e.args.empty()) {
+ args_str += ", \"args\": {";
+ bool is_first_argument = true;
+ for (TraceArg& arg : e.args) {
+ if (!is_first_argument)
+ args_str += ",";
+ is_first_argument = false;
+ args_str += " \"";
+ args_str += arg.name;
+ args_str += "\": ";
+ args_str += TraceArgValueAsString(arg);
+
+ // Delete our copy of the string.
+ if (arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
+ delete[] arg.value.as_string;
+ arg.value.as_string = nullptr;
+ }
+ }
+ args_str += " }";
+ }
+ fprintf(output_file_,
+ "%s{ \"name\": \"%s\""
+ ", \"cat\": \"%s\""
+ ", \"ph\": \"%c\""
+ ", \"ts\": %" PRIu64
+ ", \"pid\": %d"
+#if defined(WEBRTC_WIN)
+ ", \"tid\": %lu"
+#else
+ ", \"tid\": %d"
+#endif // defined(WEBRTC_WIN)
+ "%s"
+ "}\n",
+ has_logged_event ? "," : " ", e.name, e.category_enabled,
+ e.phase, e.timestamp, e.pid, e.tid, args_str.c_str());
+ has_logged_event = true;
+ }
+ if (shutting_down)
+ break;
+ }
+ fprintf(output_file_, "]}\n");
+ if (output_file_owned_)
+ fclose(output_file_);
+ output_file_ = nullptr;
+ }
+
+ void Start(FILE* file, bool owned) {
+ RTC_DCHECK(thread_checker_.IsCurrent());
+ RTC_DCHECK(file);
+ RTC_DCHECK(!output_file_);
+ output_file_ = file;
+ output_file_owned_ = owned;
+ {
+ webrtc::MutexLock lock(&mutex_);
+ // Since the atomic fast-path for adding events to the queue can be
+ // bypassed while the logging thread is shutting down there may be some
+ // stale events in the queue, hence the vector needs to be cleared to not
+ // log events from a previous logging session (which may be days old).
+ trace_events_.clear();
+ }
+ // Enable event logging (fast-path). This should be disabled since starting
+ // shouldn't be done twice.
+ RTC_CHECK_EQ(0,
+ rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 0, 1));
+
+ // Finally start, everything should be set up now.
+ logging_thread_.Start();
+ TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Start");
+ }
+
+ void Stop() {
+ RTC_DCHECK(thread_checker_.IsCurrent());
+ TRACE_EVENT_INSTANT0("webrtc", "EventLogger::Stop");
+ // Try to stop. Abort if we're not currently logging.
+ if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0)
+ return;
+
+ // Wake up logging thread to finish writing.
+ shutdown_event_.Set();
+ // Join the logging thread.
+ logging_thread_.Stop();
+ }
+
+ private:
+ struct TraceArg {
+ const char* name;
+ unsigned char type;
+ // Copied from webrtc/rtc_base/trace_event.h TraceValueUnion.
+ union TraceArgValue {
+ bool as_bool;
+ unsigned long long as_uint;
+ long long as_int;
+ double as_double;
+ const void* as_pointer;
+ const char* as_string;
+ } value;
+
+ // Assert that the size of the union is equal to the size of the as_uint
+ // field since we are assigning to arbitrary types using it.
+ static_assert(sizeof(TraceArgValue) == sizeof(unsigned long long),
+ "Size of TraceArg value union is not equal to the size of "
+ "the uint field of that union.");
+ };
+
+ struct TraceEvent {
+ const char* name;
+ const unsigned char* category_enabled;
+ char phase;
+ std::vector<TraceArg> args;
+ uint64_t timestamp;
+ int pid;
+ rtc::PlatformThreadId tid;
+ };
+
+ static std::string TraceArgValueAsString(TraceArg arg) {
+ std::string output;
+
+ if (arg.type == TRACE_VALUE_TYPE_STRING ||
+ arg.type == TRACE_VALUE_TYPE_COPY_STRING) {
+ // Space for every character to be an espaced character + two for
+ // quatation marks.
+ output.reserve(strlen(arg.value.as_string) * 2 + 2);
+ output += '\"';
+ const char* c = arg.value.as_string;
+ do {
+ if (*c == '"' || *c == '\\') {
+ output += '\\';
+ output += *c;
+ } else {
+ output += *c;
+ }
+ } while (*++c);
+ output += '\"';
+ } else {
+ output.resize(kTraceArgBufferLength);
+ size_t print_length = 0;
+ switch (arg.type) {
+ case TRACE_VALUE_TYPE_BOOL:
+ if (arg.value.as_bool) {
+ strcpy(&output[0], "true");
+ print_length = 4;
+ } else {
+ strcpy(&output[0], "false");
+ print_length = 5;
+ }
+ break;
+ case TRACE_VALUE_TYPE_UINT:
+ print_length = snprintf(&output[0], kTraceArgBufferLength, "%llu",
+ arg.value.as_uint);
+ break;
+ case TRACE_VALUE_TYPE_INT:
+ print_length = snprintf(&output[0], kTraceArgBufferLength, "%lld",
+ arg.value.as_int);
+ break;
+ case TRACE_VALUE_TYPE_DOUBLE:
+ print_length = snprintf(&output[0], kTraceArgBufferLength, "%f",
+ arg.value.as_double);
+ break;
+ case TRACE_VALUE_TYPE_POINTER:
+ print_length = snprintf(&output[0], kTraceArgBufferLength, "\"%p\"",
+ arg.value.as_pointer);
+ break;
+ }
+ size_t output_length = print_length < kTraceArgBufferLength
+ ? print_length
+ : kTraceArgBufferLength - 1;
+ // This will hopefully be very close to nop. On most implementations, it
+ // just writes null byte and sets the length field of the string.
+ output.resize(output_length);
+ }
+
+ return output;
+ }
+
+ webrtc::Mutex mutex_;
+ std::vector<TraceEvent> trace_events_ RTC_GUARDED_BY(mutex_);
+ rtc::PlatformThread logging_thread_;
+ rtc::Event shutdown_event_;
+ rtc::ThreadChecker thread_checker_;
+ FILE* output_file_ = nullptr;
+ bool output_file_owned_ = false;
+};
+
+static void EventTracingThreadFunc(void* params) {
+ static_cast<EventLogger*>(params)->Log();
+}
+
+static EventLogger* volatile g_event_logger = nullptr;
+static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT("");
+const unsigned char* InternalGetCategoryEnabled(const char* name) {
+ const char* prefix_ptr = &kDisabledTracePrefix[0];
+ const char* name_ptr = name;
+ // Check whether name contains the default-disabled prefix.
+ while (*prefix_ptr == *name_ptr && *prefix_ptr != '\0') {
+ ++prefix_ptr;
+ ++name_ptr;
+ }
+ return reinterpret_cast<const unsigned char*>(*prefix_ptr == '\0' ? ""
+ : name);
+}
+
+void InternalAddTraceEvent(char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ unsigned char flags) {
+ // Fast path for when event tracing is inactive.
+ if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0)
+ return;
+
+ g_event_logger->AddTraceEvent(name, category_enabled, phase, num_args,
+ arg_names, arg_types, arg_values,
+ rtc::TimeMicros(), 1, rtc::CurrentThreadId());
+}
+
+} // namespace
+
+void SetupInternalTracer() {
+ RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
+ &g_event_logger, static_cast<EventLogger*>(nullptr),
+ new EventLogger()) == nullptr);
+ webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent);
+}
+
+void StartInternalCaptureToFile(FILE* file) {
+ if (g_event_logger) {
+ g_event_logger->Start(file, false);
+ }
+}
+
+bool StartInternalCapture(const char* filename) {
+ if (!g_event_logger)
+ return false;
+
+ FILE* file = fopen(filename, "w");
+ if (!file) {
+ RTC_LOG(LS_ERROR) << "Failed to open trace file '" << filename
+ << "' for writing.";
+ return false;
+ }
+ g_event_logger->Start(file, true);
+ return true;
+}
+
+void StopInternalCapture() {
+ if (g_event_logger) {
+ g_event_logger->Stop();
+ }
+}
+
+void ShutdownInternalTracer() {
+ StopInternalCapture();
+ EventLogger* old_logger = rtc::AtomicOps::AcquireLoadPtr(&g_event_logger);
+ RTC_DCHECK(old_logger);
+ RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
+ &g_event_logger, old_logger,
+ static_cast<EventLogger*>(nullptr)) == old_logger);
+ delete old_logger;
+ webrtc::SetupEventTracer(nullptr, nullptr);
+}
+
+} // namespace tracing
+} // namespace rtc
diff --git a/webrtc/rtc_base/event_tracer.h b/webrtc/rtc_base/event_tracer.h
new file mode 100644
index 0000000..4bbda57
--- /dev/null
+++ b/webrtc/rtc_base/event_tracer.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+// This file defines the interface for event tracing in WebRTC.
+//
+// Event log handlers are set through SetupEventTracer(). User of this API will
+// provide two function pointers to handle event tracing calls.
+//
+// * GetCategoryEnabledPtr
+// Event tracing system calls this function to determine if a particular
+// event category is enabled.
+//
+// * AddTraceEventPtr
+// Adds a tracing event. It is the user's responsibility to log the data
+// provided.
+//
+// Parameters for the above two functions are described in trace_event.h.
+
+#ifndef RTC_BASE_EVENT_TRACER_H_
+#define RTC_BASE_EVENT_TRACER_H_
+
+#include <stdio.h>
+
+namespace webrtc {
+
+typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name);
+typedef void (*AddTraceEventPtr)(char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ unsigned char flags);
+
+// User of WebRTC can call this method to setup event tracing.
+//
+// This method must be called before any WebRTC methods. Functions
+// provided should be thread-safe.
+void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
+ AddTraceEventPtr add_trace_event_ptr);
+
+// This class defines interface for the event tracing system to call
+// internally. Do not call these methods directly.
+class EventTracer {
+ public:
+ static const unsigned char* GetCategoryEnabled(const char* name);
+
+ static void AddTraceEvent(char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ unsigned char flags);
+};
+
+} // namespace webrtc
+
+namespace rtc {
+namespace tracing {
+// Set up internal event tracer.
+void SetupInternalTracer();
+bool StartInternalCapture(const char* filename);
+void StartInternalCaptureToFile(FILE* file);
+void StopInternalCapture();
+// Make sure we run this, this will tear down the internal tracing.
+void ShutdownInternalTracer();
+} // namespace tracing
+} // namespace rtc
+
+#endif // RTC_BASE_EVENT_TRACER_H_
diff --git a/webrtc/rtc_base/experiments/field_trial_parser.cc b/webrtc/rtc_base/experiments/field_trial_parser.cc
new file mode 100644
index 0000000..b88d0f9
--- /dev/null
+++ b/webrtc/rtc_base/experiments/field_trial_parser.cc
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "rtc_base/experiments/field_trial_parser.h"
+
+#include <inttypes.h>
+
+#include <algorithm>
+#include <map>
+#include <type_traits>
+#include <utility>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace {
+
+int FindOrEnd(std::string str, size_t start, char delimiter) {
+ size_t pos = str.find(delimiter, start);
+ pos = (pos == std::string::npos) ? str.length() : pos;
+ return static_cast<int>(pos);
+}
+} // namespace
+
+FieldTrialParameterInterface::FieldTrialParameterInterface(std::string key)
+ : key_(key) {}
+FieldTrialParameterInterface::~FieldTrialParameterInterface() {
+ RTC_DCHECK(used_) << "Field trial parameter with key: '" << key_
+ << "' never used.";
+}
+
+void ParseFieldTrial(
+ std::initializer_list<FieldTrialParameterInterface*> fields,
+ std::string trial_string) {
+ std::map<std::string, FieldTrialParameterInterface*> field_map;
+ FieldTrialParameterInterface* keyless_field = nullptr;
+ for (FieldTrialParameterInterface* field : fields) {
+ field->MarkAsUsed();
+ if (!field->sub_parameters_.empty()) {
+ for (FieldTrialParameterInterface* sub_field : field->sub_parameters_) {
+ RTC_DCHECK(!sub_field->key_.empty());
+ sub_field->MarkAsUsed();
+ field_map[sub_field->key_] = sub_field;
+ }
+ continue;
+ }
+
+ if (field->key_.empty()) {
+ RTC_DCHECK(!keyless_field);
+ keyless_field = field;
+ } else {
+ field_map[field->key_] = field;
+ }
+ }
+
+ size_t i = 0;
+ while (i < trial_string.length()) {
+ int val_end = FindOrEnd(trial_string, i, ',');
+ int colon_pos = FindOrEnd(trial_string, i, ':');
+ int key_end = std::min(val_end, colon_pos);
+ int val_begin = key_end + 1;
+ std::string key = trial_string.substr(i, key_end - i);
+ absl::optional<std::string> opt_value;
+ if (val_end >= val_begin)
+ opt_value = trial_string.substr(val_begin, val_end - val_begin);
+ i = val_end + 1;
+ auto field = field_map.find(key);
+ if (field != field_map.end()) {
+ if (!field->second->Parse(std::move(opt_value))) {
+ RTC_LOG(LS_WARNING) << "Failed to read field with key: '" << key
+ << "' in trial: \"" << trial_string << "\"";
+ }
+ } else if (!opt_value && keyless_field && !key.empty()) {
+ if (!keyless_field->Parse(key)) {
+ RTC_LOG(LS_WARNING) << "Failed to read empty key field with value '"
+ << key << "' in trial: \"" << trial_string << "\"";
+ }
+ } else {
+ RTC_LOG(LS_INFO) << "No field with key: '" << key
+ << "' (found in trial: \"" << trial_string << "\")";
+ std::string valid_keys;
+ for (const auto& f : field_map) {
+ valid_keys += f.first;
+ valid_keys += ", ";
+ }
+ RTC_LOG(LS_INFO) << "Valid keys are: " << valid_keys;
+ }
+ }
+
+ for (FieldTrialParameterInterface* field : fields) {
+ field->ParseDone();
+ }
+}
+
+template <>
+absl::optional<bool> ParseTypedParameter<bool>(std::string str) {
+ if (str == "true" || str == "1") {
+ return true;
+ } else if (str == "false" || str == "0") {
+ return false;
+ }
+ return absl::nullopt;
+}
+
+template <>
+absl::optional<double> ParseTypedParameter<double>(std::string str) {
+ double value;
+ char unit[2]{0, 0};
+ if (sscanf(str.c_str(), "%lf%1s", &value, unit) >= 1) {
+ if (unit[0] == '%')
+ return value / 100;
+ return value;
+ } else {
+ return absl::nullopt;
+ }
+}
+
+template <>
+absl::optional<int> ParseTypedParameter<int>(std::string str) {
+ int64_t value;
+ if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) {
+ if (rtc::IsValueInRangeForNumericType<int, int64_t>(value)) {
+ return static_cast<int>(value);
+ }
+ }
+ return absl::nullopt;
+}
+
+template <>
+absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str) {
+ int64_t value;
+ if (sscanf(str.c_str(), "%" SCNd64, &value) == 1) {
+ if (rtc::IsValueInRangeForNumericType<unsigned, int64_t>(value)) {
+ return static_cast<unsigned>(value);
+ }
+ }
+ return absl::nullopt;
+}
+
+template <>
+absl::optional<std::string> ParseTypedParameter<std::string>(std::string str) {
+ return std::move(str);
+}
+
+template <>
+absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
+ std::string str) {
+ return ParseOptionalParameter<bool>(str);
+}
+template <>
+absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
+ std::string str) {
+ return ParseOptionalParameter<int>(str);
+}
+template <>
+absl::optional<absl::optional<unsigned>>
+ParseTypedParameter<absl::optional<unsigned>>(std::string str) {
+ return ParseOptionalParameter<unsigned>(str);
+}
+template <>
+absl::optional<absl::optional<double>>
+ParseTypedParameter<absl::optional<double>>(std::string str) {
+ return ParseOptionalParameter<double>(str);
+}
+
+FieldTrialFlag::FieldTrialFlag(std::string key) : FieldTrialFlag(key, false) {}
+
+FieldTrialFlag::FieldTrialFlag(std::string key, bool default_value)
+ : FieldTrialParameterInterface(key), value_(default_value) {}
+
+bool FieldTrialFlag::Get() const {
+ return value_;
+}
+
+webrtc::FieldTrialFlag::operator bool() const {
+ return value_;
+}
+
+bool FieldTrialFlag::Parse(absl::optional<std::string> str_value) {
+ // Only set the flag if there is no argument provided.
+ if (str_value) {
+ absl::optional<bool> opt_value = ParseTypedParameter<bool>(*str_value);
+ if (!opt_value)
+ return false;
+ value_ = *opt_value;
+ } else {
+ value_ = true;
+ }
+ return true;
+}
+
+AbstractFieldTrialEnum::AbstractFieldTrialEnum(
+ std::string key,
+ int default_value,
+ std::map<std::string, int> mapping)
+ : FieldTrialParameterInterface(key),
+ value_(default_value),
+ enum_mapping_(mapping) {
+ for (auto& key_val : enum_mapping_)
+ valid_values_.insert(key_val.second);
+}
+AbstractFieldTrialEnum::AbstractFieldTrialEnum(const AbstractFieldTrialEnum&) =
+ default;
+AbstractFieldTrialEnum::~AbstractFieldTrialEnum() = default;
+
+bool AbstractFieldTrialEnum::Parse(absl::optional<std::string> str_value) {
+ if (str_value) {
+ auto it = enum_mapping_.find(*str_value);
+ if (it != enum_mapping_.end()) {
+ value_ = it->second;
+ return true;
+ }
+ absl::optional<int> value = ParseTypedParameter<int>(*str_value);
+ if (value.has_value() &&
+ (valid_values_.find(*value) != valid_values_.end())) {
+ value_ = *value;
+ return true;
+ }
+ }
+ return false;
+}
+
+template class FieldTrialParameter<bool>;
+template class FieldTrialParameter<double>;
+template class FieldTrialParameter<int>;
+template class FieldTrialParameter<unsigned>;
+template class FieldTrialParameter<std::string>;
+
+template class FieldTrialConstrained<double>;
+template class FieldTrialConstrained<int>;
+template class FieldTrialConstrained<unsigned>;
+
+template class FieldTrialOptional<double>;
+template class FieldTrialOptional<int>;
+template class FieldTrialOptional<unsigned>;
+template class FieldTrialOptional<bool>;
+template class FieldTrialOptional<std::string>;
+
+} // namespace webrtc
diff --git a/webrtc/rtc_base/experiments/field_trial_parser.h b/webrtc/rtc_base/experiments/field_trial_parser.h
new file mode 100644
index 0000000..42535ed
--- /dev/null
+++ b/webrtc/rtc_base/experiments/field_trial_parser.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
+#define RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
+
+#include <stdint.h>
+
+#include <initializer_list>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+
+// Field trial parser functionality. Provides funcitonality to parse field trial
+// argument strings in key:value format. Each parameter is described using
+// key:value, parameters are separated with a ,. Values can't include the comma
+// character, since there's no quote facility. For most types, white space is
+// ignored. Parameters are declared with a given type for which an
+// implementation of ParseTypedParameter should be provided. The
+// ParseTypedParameter implementation is given whatever is between the : and the
+// ,. If the key is provided without : a FieldTrialOptional will use nullopt.
+
+// Example string: "my_optional,my_int:3,my_string:hello"
+
+// For further description of usage and behavior, see the examples in the unit
+// tests.
+
+namespace webrtc {
+class FieldTrialParameterInterface {
+ public:
+ virtual ~FieldTrialParameterInterface();
+ std::string key() const { return key_; }
+
+ protected:
+ // Protected to allow implementations to provide assignment and copy.
+ FieldTrialParameterInterface(const FieldTrialParameterInterface&) = default;
+ FieldTrialParameterInterface& operator=(const FieldTrialParameterInterface&) =
+ default;
+ explicit FieldTrialParameterInterface(std::string key);
+ friend void ParseFieldTrial(
+ std::initializer_list<FieldTrialParameterInterface*> fields,
+ std::string raw_string);
+ void MarkAsUsed() { used_ = true; }
+ virtual bool Parse(absl::optional<std::string> str_value) = 0;
+
+ virtual void ParseDone() {}
+
+ std::vector<FieldTrialParameterInterface*> sub_parameters_;
+
+ private:
+ std::string key_;
+ bool used_ = false;
+};
+
+// ParseFieldTrial function parses the given string and fills the given fields
+// with extracted values if available.
+void ParseFieldTrial(
+ std::initializer_list<FieldTrialParameterInterface*> fields,
+ std::string raw_string);
+
+// Specialize this in code file for custom types. Should return absl::nullopt if
+// the given string cannot be properly parsed.
+template <typename T>
+absl::optional<T> ParseTypedParameter(std::string);
+
+// This class uses the ParseTypedParameter function to implement a parameter
+// implementation with an enforced default value.
+template <typename T>
+class FieldTrialParameter : public FieldTrialParameterInterface {
+ public:
+ FieldTrialParameter(std::string key, T default_value)
+ : FieldTrialParameterInterface(key), value_(default_value) {}
+ T Get() const { return value_; }
+ operator T() const { return Get(); }
+ const T* operator->() const { return &value_; }
+
+ void SetForTest(T value) { value_ = value; }
+
+ protected:
+ bool Parse(absl::optional<std::string> str_value) override {
+ if (str_value) {
+ absl::optional<T> value = ParseTypedParameter<T>(*str_value);
+ if (value.has_value()) {
+ value_ = value.value();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private:
+ T value_;
+};
+
+// This class uses the ParseTypedParameter function to implement a parameter
+// implementation with an enforced default value and a range constraint. Values
+// outside the configured range will be ignored.
+template <typename T>
+class FieldTrialConstrained : public FieldTrialParameterInterface {
+ public:
+ FieldTrialConstrained(std::string key,
+ T default_value,
+ absl::optional<T> lower_limit,
+ absl::optional<T> upper_limit)
+ : FieldTrialParameterInterface(key),
+ value_(default_value),
+ lower_limit_(lower_limit),
+ upper_limit_(upper_limit) {}
+ T Get() const { return value_; }
+ operator T() const { return Get(); }
+ const T* operator->() const { return &value_; }
+
+ protected:
+ bool Parse(absl::optional<std::string> str_value) override {
+ if (str_value) {
+ absl::optional<T> value = ParseTypedParameter<T>(*str_value);
+ if (value && (!lower_limit_ || *value >= *lower_limit_) &&
+ (!upper_limit_ || *value <= *upper_limit_)) {
+ value_ = *value;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private:
+ T value_;
+ absl::optional<T> lower_limit_;
+ absl::optional<T> upper_limit_;
+};
+
+class AbstractFieldTrialEnum : public FieldTrialParameterInterface {
+ public:
+ AbstractFieldTrialEnum(std::string key,
+ int default_value,
+ std::map<std::string, int> mapping);
+ ~AbstractFieldTrialEnum() override;
+ AbstractFieldTrialEnum(const AbstractFieldTrialEnum&);
+
+ protected:
+ bool Parse(absl::optional<std::string> str_value) override;
+
+ protected:
+ int value_;
+ std::map<std::string, int> enum_mapping_;
+ std::set<int> valid_values_;
+};
+
+// The FieldTrialEnum class can be used to quickly define a parser for a
+// specific enum. It handles values provided as integers and as strings if a
+// mapping is provided.
+template <typename T>
+class FieldTrialEnum : public AbstractFieldTrialEnum {
+ public:
+ FieldTrialEnum(std::string key,
+ T default_value,
+ std::map<std::string, T> mapping)
+ : AbstractFieldTrialEnum(key,
+ static_cast<int>(default_value),
+ ToIntMap(mapping)) {}
+ T Get() const { return static_cast<T>(value_); }
+ operator T() const { return Get(); }
+
+ private:
+ static std::map<std::string, int> ToIntMap(std::map<std::string, T> mapping) {
+ std::map<std::string, int> res;
+ for (const auto& it : mapping)
+ res[it.first] = static_cast<int>(it.second);
+ return res;
+ }
+};
+
+// This class uses the ParseTypedParameter function to implement an optional
+// parameter implementation that can default to absl::nullopt.
+template <typename T>
+class FieldTrialOptional : public FieldTrialParameterInterface {
+ public:
+ explicit FieldTrialOptional(std::string key)
+ : FieldTrialParameterInterface(key) {}
+ FieldTrialOptional(std::string key, absl::optional<T> default_value)
+ : FieldTrialParameterInterface(key), value_(default_value) {}
+ absl::optional<T> GetOptional() const { return value_; }
+ const T& Value() const { return value_.value(); }
+ const T& operator*() const { return value_.value(); }
+ const T* operator->() const { return &value_.value(); }
+ explicit operator bool() const { return value_.has_value(); }
+
+ protected:
+ bool Parse(absl::optional<std::string> str_value) override {
+ if (str_value) {
+ absl::optional<T> value = ParseTypedParameter<T>(*str_value);
+ if (!value.has_value())
+ return false;
+ value_ = value.value();
+ } else {
+ value_ = absl::nullopt;
+ }
+ return true;
+ }
+
+ private:
+ absl::optional<T> value_;
+};
+
+// Equivalent to a FieldTrialParameter<bool> in the case that both key and value
+// are present. If key is missing, evaluates to false. If key is present, but no
+// explicit value is provided, the flag evaluates to true.
+class FieldTrialFlag : public FieldTrialParameterInterface {
+ public:
+ explicit FieldTrialFlag(std::string key);
+ FieldTrialFlag(std::string key, bool default_value);
+ bool Get() const;
+ operator bool() const;
+
+ protected:
+ bool Parse(absl::optional<std::string> str_value) override;
+
+ private:
+ bool value_;
+};
+
+template <typename T>
+absl::optional<absl::optional<T>> ParseOptionalParameter(std::string str) {
+ if (str.empty())
+ return absl::optional<T>();
+ auto parsed = ParseTypedParameter<T>(str);
+ if (parsed.has_value())
+ return parsed;
+ return absl::nullopt;
+}
+
+template <>
+absl::optional<bool> ParseTypedParameter<bool>(std::string str);
+template <>
+absl::optional<double> ParseTypedParameter<double>(std::string str);
+template <>
+absl::optional<int> ParseTypedParameter<int>(std::string str);
+template <>
+absl::optional<unsigned> ParseTypedParameter<unsigned>(std::string str);
+template <>
+absl::optional<std::string> ParseTypedParameter<std::string>(std::string str);
+
+template <>
+absl::optional<absl::optional<bool>> ParseTypedParameter<absl::optional<bool>>(
+ std::string str);
+template <>
+absl::optional<absl::optional<int>> ParseTypedParameter<absl::optional<int>>(
+ std::string str);
+template <>
+absl::optional<absl::optional<unsigned>>
+ParseTypedParameter<absl::optional<unsigned>>(std::string str);
+template <>
+absl::optional<absl::optional<double>>
+ParseTypedParameter<absl::optional<double>>(std::string str);
+
+// Accepts true, false, else parsed with sscanf %i, true if != 0.
+extern template class FieldTrialParameter<bool>;
+// Interpreted using sscanf %lf.
+extern template class FieldTrialParameter<double>;
+// Interpreted using sscanf %i.
+extern template class FieldTrialParameter<int>;
+// Interpreted using sscanf %u.
+extern template class FieldTrialParameter<unsigned>;
+// Using the given value as is.
+extern template class FieldTrialParameter<std::string>;
+
+extern template class FieldTrialConstrained<double>;
+extern template class FieldTrialConstrained<int>;
+extern template class FieldTrialConstrained<unsigned>;
+
+extern template class FieldTrialOptional<double>;
+extern template class FieldTrialOptional<int>;
+extern template class FieldTrialOptional<unsigned>;
+extern template class FieldTrialOptional<bool>;
+extern template class FieldTrialOptional<std::string>;
+
+} // namespace webrtc
+
+#endif // RTC_BASE_EXPERIMENTS_FIELD_TRIAL_PARSER_H_
diff --git a/webrtc/rtc_base/gtest_prod_util.h b/webrtc/rtc_base/gtest_prod_util.h
new file mode 100644
index 0000000..0661cd7
--- /dev/null
+++ b/webrtc/rtc_base/gtest_prod_util.h
@@ -0,0 +1,38 @@
+/*
+ * 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 RTC_BASE_GTEST_PROD_UTIL_H_
+#define RTC_BASE_GTEST_PROD_UTIL_H_
+
+// Define our own version of FRIEND_TEST here rather than including
+// gtest_prod.h to avoid depending on any part of GTest in production code.
+#define FRIEND_TEST_WEBRTC(test_case_name, test_name) \
+ friend class test_case_name##_##test_name##_Test
+
+// This file is a plain copy of Chromium's base/gtest_prod_util.h.
+//
+// This is a wrapper for gtest's FRIEND_TEST macro that friends
+// test with all possible prefixes. This is very helpful when changing the test
+// prefix, because the friend declarations don't need to be updated.
+//
+// Example usage:
+//
+// class MyClass {
+// private:
+// void MyMethod();
+// FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod);
+// };
+#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
+ FRIEND_TEST_WEBRTC(test_case_name, test_name); \
+ FRIEND_TEST_WEBRTC(test_case_name, DISABLED_##test_name); \
+ FRIEND_TEST_WEBRTC(test_case_name, FLAKY_##test_name); \
+ FRIEND_TEST_WEBRTC(test_case_name, FAILS_##test_name)
+
+#endif // RTC_BASE_GTEST_PROD_UTIL_H_
diff --git a/webrtc/rtc_base/ignore_wundef.h b/webrtc/rtc_base/ignore_wundef.h
new file mode 100644
index 0000000..1564096
--- /dev/null
+++ b/webrtc/rtc_base/ignore_wundef.h
@@ -0,0 +1,33 @@
+/*
+ * 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 RTC_BASE_IGNORE_WUNDEF_H_
+#define RTC_BASE_IGNORE_WUNDEF_H_
+
+// If a header file uses #if on possibly undefined macros (and it's for some
+// reason not possible to just fix the header file), include it like this:
+//
+// RTC_PUSH_IGNORING_WUNDEF()
+// #include "misbehaving_header.h"
+// RTC_POP_IGNORING_WUNDEF()
+//
+// This will cause the compiler to not emit -Wundef warnings for that file.
+
+#ifdef __clang__
+#define RTC_PUSH_IGNORING_WUNDEF() \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wundef\"")
+#define RTC_POP_IGNORING_WUNDEF() _Pragma("clang diagnostic pop")
+#else
+#define RTC_PUSH_IGNORING_WUNDEF()
+#define RTC_POP_IGNORING_WUNDEF()
+#endif // __clang__
+
+#endif // RTC_BASE_IGNORE_WUNDEF_H_
diff --git a/webrtc/rtc_base/logging.cc b/webrtc/rtc_base/logging.cc
new file mode 100644
index 0000000..13a5f02
--- /dev/null
+++ b/webrtc/rtc_base/logging.cc
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/logging.h"
+
+#include <string.h>
+
+#if RTC_LOG_ENABLED()
+
+#if defined(WEBRTC_WIN)
+#include <windows.h>
+#if _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+#undef ERROR // wingdi.h
+#endif
+
+#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+#include <CoreServices/CoreServices.h>
+#elif defined(WEBRTC_ANDROID)
+#include <android/log.h>
+
+// Android has a 1024 limit on log inputs. We use 60 chars as an
+// approx for the header/tag portion.
+// See android/system/core/liblog/logd_write.c
+static const int kMaxLogLineSize = 1024 - 60;
+#endif // WEBRTC_MAC && !defined(WEBRTC_IOS) || WEBRTC_ANDROID
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <algorithm>
+#include <cstdarg>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/platform_thread_types.h"
+#include "rtc_base/string_encode.h"
+#include "rtc_base/string_utils.h"
+#include "rtc_base/strings/string_builder.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
+#include "rtc_base/time_utils.h"
+
+namespace rtc {
+namespace {
+// By default, release builds don't log, debug builds at info level
+#if !defined(NDEBUG)
+static LoggingSeverity g_min_sev = LS_INFO;
+static LoggingSeverity g_dbg_sev = LS_INFO;
+#else
+static LoggingSeverity g_min_sev = LS_NONE;
+static LoggingSeverity g_dbg_sev = LS_NONE;
+#endif
+
+// Return the filename portion of the string (that following the last slash).
+const char* FilenameFromPath(const char* file) {
+ const char* end1 = ::strrchr(file, '/');
+ const char* end2 = ::strrchr(file, '\\');
+ if (!end1 && !end2)
+ return file;
+ else
+ return (end1 > end2) ? end1 + 1 : end2 + 1;
+}
+
+// Global lock for log subsystem, only needed to serialize access to streams_.
+// TODO(bugs.webrtc.org/11665): this is not currently constant initialized and
+// trivially destructible.
+webrtc::Mutex g_log_mutex_;
+} // namespace
+
+/////////////////////////////////////////////////////////////////////////////
+// LogMessage
+/////////////////////////////////////////////////////////////////////////////
+
+bool LogMessage::log_to_stderr_ = true;
+
+// The list of logging streams currently configured.
+// Note: we explicitly do not clean this up, because of the uncertain ordering
+// of destructors at program exit. Let the person who sets the stream trigger
+// cleanup by setting to null, or let it leak (safe at program exit).
+ABSL_CONST_INIT LogSink* LogMessage::streams_ RTC_GUARDED_BY(g_log_mutex_) =
+ nullptr;
+ABSL_CONST_INIT std::atomic<bool> LogMessage::streams_empty_ = {true};
+
+// Boolean options default to false (0)
+bool LogMessage::thread_, LogMessage::timestamp_;
+
+LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
+ : LogMessage(file, line, sev, ERRCTX_NONE, 0) {}
+
+LogMessage::LogMessage(const char* file,
+ int line,
+ LoggingSeverity sev,
+ LogErrorContext err_ctx,
+ int err)
+ : severity_(sev) {
+ if (timestamp_) {
+ // Use SystemTimeMillis so that even if tests use fake clocks, the timestamp
+ // in log messages represents the real system time.
+ int64_t time = TimeDiff(SystemTimeMillis(), LogStartTime());
+ // Also ensure WallClockStartTime is initialized, so that it matches
+ // LogStartTime.
+ WallClockStartTime();
+ // TODO(kwiberg): Switch to absl::StrFormat, if binary size is ok.
+ char timestamp[50]; // Maximum string length of an int64_t is 20.
+ int len =
+ snprintf(timestamp, sizeof(timestamp), "[%03" PRId64 ":%03" PRId64 "]",
+ time / 1000, time % 1000);
+ RTC_DCHECK_LT(len, sizeof(timestamp));
+ print_stream_ << timestamp;
+ }
+
+ if (thread_) {
+ PlatformThreadId id = CurrentThreadId();
+ print_stream_ << "[" << id << "] ";
+ }
+
+ if (file != nullptr) {
+#if defined(WEBRTC_ANDROID)
+ tag_ = FilenameFromPath(file);
+ print_stream_ << "(line " << line << "): ";
+#else
+ print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
+#endif
+ }
+
+ if (err_ctx != ERRCTX_NONE) {
+ char tmp_buf[1024];
+ SimpleStringBuilder tmp(tmp_buf);
+ tmp.AppendFormat("[0x%08X]", err);
+ switch (err_ctx) {
+ case ERRCTX_ERRNO:
+ tmp << " " << strerror(err);
+ break;
+#ifdef WEBRTC_WIN
+ case ERRCTX_HRESULT: {
+ char msgbuf[256];
+ DWORD flags =
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+ if (DWORD len = FormatMessageA(
+ flags, nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ msgbuf, sizeof(msgbuf) / sizeof(msgbuf[0]), nullptr)) {
+ while ((len > 0) &&
+ isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
+ msgbuf[--len] = 0;
+ }
+ tmp << " " << msgbuf;
+ }
+ break;
+ }
+#endif // WEBRTC_WIN
+ default:
+ break;
+ }
+ extra_ = tmp.str();
+ }
+}
+
+#if defined(WEBRTC_ANDROID)
+LogMessage::LogMessage(const char* file,
+ int line,
+ LoggingSeverity sev,
+ const char* tag)
+ : LogMessage(file, line, sev, ERRCTX_NONE, 0 /* err */) {
+ tag_ = tag;
+ print_stream_ << tag << ": ";
+}
+#endif
+
+// DEPRECATED. Currently only used by downstream projects that use
+// implementation details of logging.h. Work is ongoing to remove those
+// dependencies.
+LogMessage::LogMessage(const char* file,
+ int line,
+ LoggingSeverity sev,
+ const std::string& tag)
+ : LogMessage(file, line, sev) {
+ print_stream_ << tag << ": ";
+}
+
+LogMessage::~LogMessage() {
+ FinishPrintStream();
+
+ const std::string str = print_stream_.Release();
+
+ if (severity_ >= g_dbg_sev) {
+#if defined(WEBRTC_ANDROID)
+ OutputToDebug(str, severity_, tag_);
+#else
+ OutputToDebug(str, severity_);
+#endif
+ }
+
+ webrtc::MutexLock lock(&g_log_mutex_);
+ for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
+ if (severity_ >= entry->min_severity_) {
+#if defined(WEBRTC_ANDROID)
+ entry->OnLogMessage(str, severity_, tag_);
+#else
+ entry->OnLogMessage(str, severity_);
+#endif
+ }
+ }
+}
+
+void LogMessage::AddTag(const char* tag) {
+#ifdef WEBRTC_ANDROID
+ tag_ = tag;
+#endif
+}
+
+rtc::StringBuilder& LogMessage::stream() {
+ return print_stream_;
+}
+
+int LogMessage::GetMinLogSeverity() {
+ return g_min_sev;
+}
+
+LoggingSeverity LogMessage::GetLogToDebug() {
+ return g_dbg_sev;
+}
+int64_t LogMessage::LogStartTime() {
+ static const int64_t g_start = SystemTimeMillis();
+ return g_start;
+}
+
+uint32_t LogMessage::WallClockStartTime() {
+ static const uint32_t g_start_wallclock = time(nullptr);
+ return g_start_wallclock;
+}
+
+void LogMessage::LogThreads(bool on) {
+ thread_ = on;
+}
+
+void LogMessage::LogTimestamps(bool on) {
+ timestamp_ = on;
+}
+
+void LogMessage::LogToDebug(LoggingSeverity min_sev) {
+ g_dbg_sev = min_sev;
+ webrtc::MutexLock lock(&g_log_mutex_);
+ UpdateMinLogSeverity();
+}
+
+void LogMessage::SetLogToStderr(bool log_to_stderr) {
+ log_to_stderr_ = log_to_stderr;
+}
+
+int LogMessage::GetLogToStream(LogSink* stream) {
+ webrtc::MutexLock lock(&g_log_mutex_);
+ LoggingSeverity sev = LS_NONE;
+ for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
+ if (stream == nullptr || stream == entry) {
+ sev = std::min(sev, entry->min_severity_);
+ }
+ }
+ return sev;
+}
+
+void LogMessage::AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {
+ webrtc::MutexLock lock(&g_log_mutex_);
+ stream->min_severity_ = min_sev;
+ stream->next_ = streams_;
+ streams_ = stream;
+ streams_empty_.store(false, std::memory_order_relaxed);
+ UpdateMinLogSeverity();
+}
+
+void LogMessage::RemoveLogToStream(LogSink* stream) {
+ webrtc::MutexLock lock(&g_log_mutex_);
+ for (LogSink** entry = &streams_; *entry != nullptr;
+ entry = &(*entry)->next_) {
+ if (*entry == stream) {
+ *entry = (*entry)->next_;
+ break;
+ }
+ }
+ streams_empty_.store(streams_ == nullptr, std::memory_order_relaxed);
+ UpdateMinLogSeverity();
+}
+
+void LogMessage::ConfigureLogging(const char* params) {
+ LoggingSeverity current_level = LS_VERBOSE;
+ LoggingSeverity debug_level = GetLogToDebug();
+
+ std::vector<std::string> tokens;
+ tokenize(params, ' ', &tokens);
+
+ for (const std::string& token : tokens) {
+ if (token.empty())
+ continue;
+
+ // Logging features
+ if (token == "tstamp") {
+ LogTimestamps();
+ } else if (token == "thread") {
+ LogThreads();
+
+ // Logging levels
+ } else if (token == "verbose") {
+ current_level = LS_VERBOSE;
+ } else if (token == "info") {
+ current_level = LS_INFO;
+ } else if (token == "warning") {
+ current_level = LS_WARNING;
+ } else if (token == "error") {
+ current_level = LS_ERROR;
+ } else if (token == "none") {
+ current_level = LS_NONE;
+
+ // Logging targets
+ } else if (token == "debug") {
+ debug_level = current_level;
+ }
+ }
+
+#if defined(WEBRTC_WIN) && !defined(WINUWP)
+ if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
+ // First, attempt to attach to our parent's console... so if you invoke
+ // from the command line, we'll see the output there. Otherwise, create
+ // our own console window.
+ // Note: These methods fail if a console already exists, which is fine.
+ if (!AttachConsole(ATTACH_PARENT_PROCESS))
+ ::AllocConsole();
+ }
+#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
+
+ LogToDebug(debug_level);
+}
+
+void LogMessage::UpdateMinLogSeverity()
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(g_log_mutex_) {
+ LoggingSeverity min_sev = g_dbg_sev;
+ for (LogSink* entry = streams_; entry != nullptr; entry = entry->next_) {
+ min_sev = std::min(min_sev, entry->min_severity_);
+ }
+ g_min_sev = min_sev;
+}
+
+#if defined(WEBRTC_ANDROID)
+void LogMessage::OutputToDebug(const std::string& str,
+ LoggingSeverity severity,
+ const char* tag) {
+#else
+void LogMessage::OutputToDebug(const std::string& str,
+ LoggingSeverity severity) {
+#endif
+ bool log_to_stderr = log_to_stderr_;
+#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
+ // On the Mac, all stderr output goes to the Console log and causes clutter.
+ // So in opt builds, don't log to stderr unless the user specifically sets
+ // a preference to do so.
+ CFStringRef key = CFStringCreateWithCString(
+ kCFAllocatorDefault, "logToStdErr", kCFStringEncodingUTF8);
+ CFStringRef domain = CFBundleGetIdentifier(CFBundleGetMainBundle());
+ if (key != nullptr && domain != nullptr) {
+ Boolean exists_and_is_valid;
+ Boolean should_log =
+ CFPreferencesGetAppBooleanValue(key, domain, &exists_and_is_valid);
+ // If the key doesn't exist or is invalid or is false, we will not log to
+ // stderr.
+ log_to_stderr = exists_and_is_valid && should_log;
+ }
+ if (key != nullptr) {
+ CFRelease(key);
+ }
+#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) && defined(NDEBUG)
+
+#if defined(WEBRTC_WIN)
+ // Always log to the debugger.
+ // Perhaps stderr should be controlled by a preference, as on Mac?
+ OutputDebugStringA(str.c_str());
+ if (log_to_stderr) {
+ // This handles dynamically allocated consoles, too.
+ if (HANDLE error_handle = ::GetStdHandle(STD_ERROR_HANDLE)) {
+ log_to_stderr = false;
+ DWORD written = 0;
+ ::WriteFile(error_handle, str.data(), static_cast<DWORD>(str.size()),
+ &written, 0);
+ }
+ }
+#endif // WEBRTC_WIN
+
+#if defined(WEBRTC_ANDROID)
+ // Android's logging facility uses severity to log messages but we
+ // need to map libjingle's severity levels to Android ones first.
+ // Also write to stderr which maybe available to executable started
+ // from the shell.
+ int prio;
+ switch (severity) {
+ case LS_VERBOSE:
+ prio = ANDROID_LOG_VERBOSE;
+ break;
+ case LS_INFO:
+ prio = ANDROID_LOG_INFO;
+ break;
+ case LS_WARNING:
+ prio = ANDROID_LOG_WARN;
+ break;
+ case LS_ERROR:
+ prio = ANDROID_LOG_ERROR;
+ break;
+ default:
+ prio = ANDROID_LOG_UNKNOWN;
+ }
+
+ int size = str.size();
+ int line = 0;
+ int idx = 0;
+ const int max_lines = size / kMaxLogLineSize + 1;
+ if (max_lines == 1) {
+ __android_log_print(prio, tag, "%.*s", size, str.c_str());
+ } else {
+ while (size > 0) {
+ const int len = std::min(size, kMaxLogLineSize);
+ // Use the size of the string in the format (str may have \0 in the
+ // middle).
+ __android_log_print(prio, tag, "[%d/%d] %.*s", line + 1, max_lines, len,
+ str.c_str() + idx);
+ idx += len;
+ size -= len;
+ ++line;
+ }
+ }
+#endif // WEBRTC_ANDROID
+ if (log_to_stderr) {
+ fprintf(stderr, "%s", str.c_str());
+ fflush(stderr);
+ }
+}
+
+// static
+bool LogMessage::IsNoop(LoggingSeverity severity) {
+ if (severity >= g_dbg_sev || severity >= g_min_sev)
+ return false;
+ return streams_empty_.load(std::memory_order_relaxed);
+}
+
+void LogMessage::FinishPrintStream() {
+ if (!extra_.empty())
+ print_stream_ << " : " << extra_;
+ print_stream_ << "\n";
+}
+
+namespace webrtc_logging_impl {
+
+void Log(const LogArgType* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+ LogMetadataErr meta;
+ const char* tag = nullptr;
+ switch (*fmt) {
+ case LogArgType::kLogMetadata: {
+ meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
+ break;
+ }
+ case LogArgType::kLogMetadataErr: {
+ meta = va_arg(args, LogMetadataErr);
+ break;
+ }
+#ifdef WEBRTC_ANDROID
+ case LogArgType::kLogMetadataTag: {
+ const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
+ meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
+ tag = tag_meta.tag;
+ break;
+ }
+#endif
+ default: {
+ RTC_NOTREACHED();
+ va_end(args);
+ return;
+ }
+ }
+
+ LogMessage log_message(meta.meta.File(), meta.meta.Line(),
+ meta.meta.Severity(), meta.err_ctx, meta.err);
+ if (tag) {
+ log_message.AddTag(tag);
+ }
+
+ for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
+ switch (*fmt) {
+ case LogArgType::kInt:
+ log_message.stream() << va_arg(args, int);
+ break;
+ case LogArgType::kLong:
+ log_message.stream() << va_arg(args, long);
+ break;
+ case LogArgType::kLongLong:
+ log_message.stream() << va_arg(args, long long);
+ break;
+ case LogArgType::kUInt:
+ log_message.stream() << va_arg(args, unsigned);
+ break;
+ case LogArgType::kULong:
+ log_message.stream() << va_arg(args, unsigned long);
+ break;
+ case LogArgType::kULongLong:
+ log_message.stream() << va_arg(args, unsigned long long);
+ break;
+ case LogArgType::kDouble:
+ log_message.stream() << va_arg(args, double);
+ break;
+ case LogArgType::kLongDouble:
+ log_message.stream() << va_arg(args, long double);
+ break;
+ case LogArgType::kCharP: {
+ const char* s = va_arg(args, const char*);
+ log_message.stream() << (s ? s : "(null)");
+ break;
+ }
+ case LogArgType::kStdString:
+ log_message.stream() << *va_arg(args, const std::string*);
+ break;
+ case LogArgType::kStringView:
+ log_message.stream() << *va_arg(args, const absl::string_view*);
+ break;
+ case LogArgType::kVoidP:
+ log_message.stream() << rtc::ToHex(
+ reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
+ break;
+ default:
+ RTC_NOTREACHED();
+ va_end(args);
+ return;
+ }
+ }
+
+ va_end(args);
+}
+
+} // namespace webrtc_logging_impl
+} // namespace rtc
+#endif
+
+namespace rtc {
+// Inefficient default implementation, override is recommended.
+void LogSink::OnLogMessage(const std::string& msg,
+ LoggingSeverity severity,
+ const char* tag) {
+ OnLogMessage(tag + (": " + msg), severity);
+}
+
+void LogSink::OnLogMessage(const std::string& msg,
+ LoggingSeverity /* severity */) {
+ OnLogMessage(msg);
+}
+} // namespace rtc
diff --git a/webrtc/rtc_base/logging.h b/webrtc/rtc_base/logging.h
new file mode 100644
index 0000000..d2607c2
--- /dev/null
+++ b/webrtc/rtc_base/logging.h
@@ -0,0 +1,712 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// RTC_LOG(...) an ostream target that can be used to send formatted
+// output to a variety of logging targets, such as debugger console, stderr,
+// or any LogSink.
+// The severity level passed as the first argument to the logging
+// functions is used as a filter, to limit the verbosity of the logging.
+// Static members of LogMessage documented below are used to control the
+// verbosity and target of the output.
+// There are several variations on the RTC_LOG macro which facilitate logging
+// of common error conditions, detailed below.
+
+// RTC_LOG(sev) logs the given stream at severity "sev", which must be a
+// compile-time constant of the LoggingSeverity type, without the namespace
+// prefix.
+// RTC_LOG_V(sev) Like RTC_LOG(), but sev is a run-time variable of the
+// LoggingSeverity type (basically, it just doesn't prepend the namespace).
+// RTC_LOG_F(sev) Like RTC_LOG(), but includes the name of the current function.
+// RTC_LOG_T(sev) Like RTC_LOG(), but includes the this pointer.
+// RTC_LOG_T_F(sev) Like RTC_LOG_F(), but includes the this pointer.
+// RTC_LOG_GLE(sev [, mod]) attempt to add a string description of the
+// HRESULT returned by GetLastError.
+// RTC_LOG_ERRNO(sev) attempts to add a string description of an errno-derived
+// error. errno and associated facilities exist on both Windows and POSIX,
+// but on Windows they only apply to the C/C++ runtime.
+// RTC_LOG_ERR(sev) is an alias for the platform's normal error system, i.e.
+// _GLE on Windows and _ERRNO on POSIX.
+// (The above three also all have _EX versions that let you specify the error
+// code, rather than using the last one.)
+// RTC_LOG_E(sev, ctx, err, ...) logs a detailed error interpreted using the
+// specified context.
+// RTC_LOG_CHECK_LEVEL(sev) (and RTC_LOG_CHECK_LEVEL_V(sev)) can be used as a
+// test before performing expensive or sensitive operations whose sole
+// purpose is to output logging data at the desired level.
+
+#ifndef RTC_BASE_LOGGING_H_
+#define RTC_BASE_LOGGING_H_
+
+#include <errno.h>
+
+#include <atomic>
+#include <sstream> // no-presubmit-check TODO(webrtc:8982)
+#include <string>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/deprecation.h"
+#include "rtc_base/strings/string_builder.h"
+#include "rtc_base/system/inline.h"
+
+#if !defined(NDEBUG) || defined(DLOG_ALWAYS_ON)
+#define RTC_DLOG_IS_ON 1
+#else
+#define RTC_DLOG_IS_ON 0
+#endif
+
+#if defined(RTC_DISABLE_LOGGING)
+#define RTC_LOG_ENABLED() 0
+#else
+#define RTC_LOG_ENABLED() 1
+#endif
+
+namespace rtc {
+
+//////////////////////////////////////////////////////////////////////
+
+// Note that the non-standard LoggingSeverity aliases exist because they are
+// still in broad use. The meanings of the levels are:
+// LS_VERBOSE: This level is for data which we do not want to appear in the
+// normal debug log, but should appear in diagnostic logs.
+// LS_INFO: Chatty level used in debugging for all sorts of things, the default
+// in debug builds.
+// LS_WARNING: Something that may warrant investigation.
+// LS_ERROR: Something that should not have occurred.
+// LS_NONE: Don't log.
+enum LoggingSeverity {
+ LS_VERBOSE,
+ LS_INFO,
+ LS_WARNING,
+ LS_ERROR,
+ LS_NONE,
+ INFO = LS_INFO,
+ WARNING = LS_WARNING,
+ LERROR = LS_ERROR
+};
+
+// LogErrorContext assists in interpreting the meaning of an error value.
+enum LogErrorContext {
+ ERRCTX_NONE,
+ ERRCTX_ERRNO, // System-local errno
+ ERRCTX_HRESULT, // Windows HRESULT
+
+ // Abbreviations for LOG_E macro
+ ERRCTX_EN = ERRCTX_ERRNO, // LOG_E(sev, EN, x)
+ ERRCTX_HR = ERRCTX_HRESULT, // LOG_E(sev, HR, x)
+};
+
+class LogMessage;
+// Virtual sink interface that can receive log messages.
+class LogSink {
+ public:
+ LogSink() {}
+ virtual ~LogSink() {}
+ virtual void OnLogMessage(const std::string& msg,
+ LoggingSeverity severity,
+ const char* tag);
+ virtual void OnLogMessage(const std::string& message,
+ LoggingSeverity severity);
+ virtual void OnLogMessage(const std::string& message) = 0;
+
+ private:
+ friend class ::rtc::LogMessage;
+#if RTC_LOG_ENABLED()
+ // Members for LogMessage class to keep linked list of the registered sinks.
+ LogSink* next_ = nullptr;
+ LoggingSeverity min_severity_;
+#endif
+};
+
+namespace webrtc_logging_impl {
+
+class LogMetadata {
+ public:
+ LogMetadata(const char* file, int line, LoggingSeverity severity)
+ : file_(file),
+ line_and_sev_(static_cast<uint32_t>(line) << 3 | severity) {}
+ LogMetadata() = default;
+
+ const char* File() const { return file_; }
+ int Line() const { return line_and_sev_ >> 3; }
+ LoggingSeverity Severity() const {
+ return static_cast<LoggingSeverity>(line_and_sev_ & 0x7);
+ }
+
+ private:
+ const char* file_;
+
+ // Line number and severity, the former in the most significant 29 bits, the
+ // latter in the least significant 3 bits. (This is an optimization; since
+ // both numbers are usually compile-time constants, this way we can load them
+ // both with a single instruction.)
+ uint32_t line_and_sev_;
+};
+static_assert(std::is_trivial<LogMetadata>::value, "");
+
+struct LogMetadataErr {
+ LogMetadata meta;
+ LogErrorContext err_ctx;
+ int err;
+};
+
+#ifdef WEBRTC_ANDROID
+struct LogMetadataTag {
+ LoggingSeverity severity;
+ const char* tag;
+};
+#endif
+
+enum class LogArgType : int8_t {
+ kEnd = 0,
+ kInt,
+ kLong,
+ kLongLong,
+ kUInt,
+ kULong,
+ kULongLong,
+ kDouble,
+ kLongDouble,
+ kCharP,
+ kStdString,
+ kStringView,
+ kVoidP,
+ kLogMetadata,
+ kLogMetadataErr,
+#ifdef WEBRTC_ANDROID
+ kLogMetadataTag,
+#endif
+};
+
+// Wrapper for log arguments. Only ever make values of this type with the
+// MakeVal() functions.
+template <LogArgType N, typename T>
+struct Val {
+ static constexpr LogArgType Type() { return N; }
+ T GetVal() const { return val; }
+ T val;
+};
+
+// Case for when we need to construct a temp string and then print that.
+// (We can't use Val<CheckArgType::kStdString, const std::string*>
+// because we need somewhere to store the temp string.)
+struct ToStringVal {
+ static constexpr LogArgType Type() { return LogArgType::kStdString; }
+ const std::string* GetVal() const { return &val; }
+ std::string val;
+};
+
+inline Val<LogArgType::kInt, int> MakeVal(int x) {
+ return {x};
+}
+inline Val<LogArgType::kLong, long> MakeVal(long x) {
+ return {x};
+}
+inline Val<LogArgType::kLongLong, long long> MakeVal(long long x) {
+ return {x};
+}
+inline Val<LogArgType::kUInt, unsigned int> MakeVal(unsigned int x) {
+ return {x};
+}
+inline Val<LogArgType::kULong, unsigned long> MakeVal(unsigned long x) {
+ return {x};
+}
+inline Val<LogArgType::kULongLong, unsigned long long> MakeVal(
+ unsigned long long x) {
+ return {x};
+}
+
+inline Val<LogArgType::kDouble, double> MakeVal(double x) {
+ return {x};
+}
+inline Val<LogArgType::kLongDouble, long double> MakeVal(long double x) {
+ return {x};
+}
+
+inline Val<LogArgType::kCharP, const char*> MakeVal(const char* x) {
+ return {x};
+}
+inline Val<LogArgType::kStdString, const std::string*> MakeVal(
+ const std::string& x) {
+ return {&x};
+}
+inline Val<LogArgType::kStringView, const absl::string_view*> MakeVal(
+ const absl::string_view& x) {
+ return {&x};
+}
+
+inline Val<LogArgType::kVoidP, const void*> MakeVal(const void* x) {
+ return {x};
+}
+
+inline Val<LogArgType::kLogMetadata, LogMetadata> MakeVal(
+ const LogMetadata& x) {
+ return {x};
+}
+inline Val<LogArgType::kLogMetadataErr, LogMetadataErr> MakeVal(
+ const LogMetadataErr& x) {
+ return {x};
+}
+
+// The enum class types are not implicitly convertible to arithmetic types.
+template <typename T,
+ absl::enable_if_t<std::is_enum<T>::value &&
+ !std::is_arithmetic<T>::value>* = nullptr>
+inline decltype(MakeVal(std::declval<absl::underlying_type_t<T>>())) MakeVal(
+ T x) {
+ return {static_cast<absl::underlying_type_t<T>>(x)};
+}
+
+#ifdef WEBRTC_ANDROID
+inline Val<LogArgType::kLogMetadataTag, LogMetadataTag> MakeVal(
+ const LogMetadataTag& x) {
+ return {x};
+}
+#endif
+
+template <typename T, class = void>
+struct has_to_log_string : std::false_type {};
+template <typename T>
+struct has_to_log_string<T, decltype(ToLogString(std::declval<T>()))>
+ : std::true_type {};
+
+// Handle arbitrary types other than the above by falling back to stringstream.
+// TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need
+// it anymore. No in-tree caller does, but some external callers still do.
+template <
+ typename T,
+ typename T1 = absl::decay_t<T>,
+ absl::enable_if_t<std::is_class<T1>::value &&
+ !std::is_same<T1, std::string>::value &&
+ !std::is_same<T1, LogMetadata>::value &&
+ !has_to_log_string<T1>::value &&
+#ifdef WEBRTC_ANDROID
+ !std::is_same<T1, LogMetadataTag>::value &&
+#endif
+ !std::is_same<T1, LogMetadataErr>::value>* = nullptr>
+ToStringVal MakeVal(const T& x) {
+ std::ostringstream os; // no-presubmit-check TODO(webrtc:8982)
+ os << x;
+ return {os.str()};
+}
+
+template <typename T, absl::enable_if_t<has_to_log_string<T>::value>* = nullptr>
+ToStringVal MakeVal(const T& x) {
+ return {ToLogString(x)};
+}
+
+#if RTC_LOG_ENABLED()
+void Log(const LogArgType* fmt, ...);
+#else
+inline void Log(const LogArgType* fmt, ...) {
+ // Do nothing, shouldn't be invoked
+}
+#endif
+
+// Ephemeral type that represents the result of the logging << operator.
+template <typename... Ts>
+class LogStreamer;
+
+// Base case: Before the first << argument.
+template <>
+class LogStreamer<> final {
+ public:
+ template <typename U,
+ typename V = decltype(MakeVal(std::declval<U>())),
+ absl::enable_if_t<std::is_arithmetic<U>::value ||
+ std::is_enum<U>::value>* = nullptr>
+ RTC_FORCE_INLINE LogStreamer<V> operator<<(U arg) const {
+ return LogStreamer<V>(MakeVal(arg), this);
+ }
+
+ template <typename U,
+ typename V = decltype(MakeVal(std::declval<U>())),
+ absl::enable_if_t<!std::is_arithmetic<U>::value &&
+ !std::is_enum<U>::value>* = nullptr>
+ RTC_FORCE_INLINE LogStreamer<V> operator<<(const U& arg) const {
+ return LogStreamer<V>(MakeVal(arg), this);
+ }
+
+ template <typename... Us>
+ RTC_FORCE_INLINE static void Call(const Us&... args) {
+ static constexpr LogArgType t[] = {Us::Type()..., LogArgType::kEnd};
+ Log(t, args.GetVal()...);
+ }
+};
+
+// Inductive case: We've already seen at least one << argument. The most recent
+// one had type `T`, and the earlier ones had types `Ts`.
+template <typename T, typename... Ts>
+class LogStreamer<T, Ts...> final {
+ public:
+ RTC_FORCE_INLINE LogStreamer(T arg, const LogStreamer<Ts...>* prior)
+ : arg_(arg), prior_(prior) {}
+
+ template <typename U,
+ typename V = decltype(MakeVal(std::declval<U>())),
+ absl::enable_if_t<std::is_arithmetic<U>::value ||
+ std::is_enum<U>::value>* = nullptr>
+ RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(U arg) const {
+ return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
+ }
+
+ template <typename U,
+ typename V = decltype(MakeVal(std::declval<U>())),
+ absl::enable_if_t<!std::is_arithmetic<U>::value &&
+ !std::is_enum<U>::value>* = nullptr>
+ RTC_FORCE_INLINE LogStreamer<V, T, Ts...> operator<<(const U& arg) const {
+ return LogStreamer<V, T, Ts...>(MakeVal(arg), this);
+ }
+
+ template <typename... Us>
+ RTC_FORCE_INLINE void Call(const Us&... args) const {
+ prior_->Call(arg_, args...);
+ }
+
+ private:
+ // The most recent argument.
+ T arg_;
+
+ // Earlier arguments.
+ const LogStreamer<Ts...>* prior_;
+};
+
+class LogCall final {
+ public:
+ // This can be any binary operator with precedence lower than <<.
+ // We return bool here to be able properly remove logging if
+ // RTC_DISABLE_LOGGING is defined.
+ template <typename... Ts>
+ RTC_FORCE_INLINE bool operator&(const LogStreamer<Ts...>& streamer) {
+ streamer.Call();
+ return true;
+ }
+};
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class LogMessageVoidify {
+ public:
+ LogMessageVoidify() = default;
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ template <typename... Ts>
+ void operator&(LogStreamer<Ts...>&& streamer) {}
+};
+
+} // namespace webrtc_logging_impl
+
+// Direct use of this class is deprecated; please use the logging macros
+// instead.
+// TODO(bugs.webrtc.org/9278): Move this class to an unnamed namespace in the
+// .cc file.
+class LogMessage {
+ public:
+ // Same as the above, but using a compile-time constant for the logging
+ // severity. This saves space at the call site, since passing an empty struct
+ // is generally the same as not passing an argument at all.
+ template <LoggingSeverity S>
+ RTC_NO_INLINE LogMessage(const char* file,
+ int line,
+ std::integral_constant<LoggingSeverity, S>)
+ : LogMessage(file, line, S) {}
+
+#if RTC_LOG_ENABLED()
+ LogMessage(const char* file, int line, LoggingSeverity sev);
+ LogMessage(const char* file,
+ int line,
+ LoggingSeverity sev,
+ LogErrorContext err_ctx,
+ int err);
+#if defined(WEBRTC_ANDROID)
+ LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag);
+#endif
+ // DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS.
+ // Android code should use the 'const char*' version since tags are static
+ // and we want to avoid allocating a std::string copy per log line.
+ RTC_DEPRECATED
+ LogMessage(const char* file,
+ int line,
+ LoggingSeverity sev,
+ const std::string& tag);
+ ~LogMessage();
+
+ void AddTag(const char* tag);
+ rtc::StringBuilder& stream();
+ // Returns the time at which this function was called for the first time.
+ // The time will be used as the logging start time.
+ // If this is not called externally, the LogMessage ctor also calls it, in
+ // which case the logging start time will be the time of the first LogMessage
+ // instance is created.
+ static int64_t LogStartTime();
+ // Returns the wall clock equivalent of |LogStartTime|, in seconds from the
+ // epoch.
+ static uint32_t WallClockStartTime();
+ // LogThreads: Display the thread identifier of the current thread
+ static void LogThreads(bool on = true);
+ // LogTimestamps: Display the elapsed time of the program
+ static void LogTimestamps(bool on = true);
+ // These are the available logging channels
+ // Debug: Debug console on Windows, otherwise stderr
+ static void LogToDebug(LoggingSeverity min_sev);
+ static LoggingSeverity GetLogToDebug();
+ // Sets whether logs will be directed to stderr in debug mode.
+ static void SetLogToStderr(bool log_to_stderr);
+ // Stream: Any non-blocking stream interface.
+ // Installs the |stream| to collect logs with severtiy |min_sev| or higher.
+ // |stream| must live until deinstalled by RemoveLogToStream.
+ // If |stream| is the first stream added to the system, we might miss some
+ // early concurrent log statement happening from another thread happening near
+ // this instant.
+ static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev);
+ // Removes the specified stream, without destroying it. When the method
+ // has completed, it's guaranteed that |stream| will receive no more logging
+ // calls.
+ static void RemoveLogToStream(LogSink* stream);
+ // Returns the severity for the specified stream, of if none is specified,
+ // the minimum stream severity.
+ static int GetLogToStream(LogSink* stream = nullptr);
+ // Testing against MinLogSeverity allows code to avoid potentially expensive
+ // logging operations by pre-checking the logging level.
+ static int GetMinLogSeverity();
+ // Parses the provided parameter stream to configure the options above.
+ // Useful for configuring logging from the command line.
+ static void ConfigureLogging(const char* params);
+ // Checks the current global debug severity and if the |streams_| collection
+ // is empty. If |severity| is smaller than the global severity and if the
+ // |streams_| collection is empty, the LogMessage will be considered a noop
+ // LogMessage.
+ static bool IsNoop(LoggingSeverity severity);
+ // Version of IsNoop that uses fewer instructions at the call site, since the
+ // caller doesn't have to pass an argument.
+ template <LoggingSeverity S>
+ RTC_NO_INLINE static bool IsNoop() {
+ return IsNoop(S);
+ }
+#else
+ // Next methods do nothing; no one will call these functions.
+ LogMessage(const char* file, int line, LoggingSeverity sev) {}
+ LogMessage(const char* file,
+ int line,
+ LoggingSeverity sev,
+ LogErrorContext err_ctx,
+ int err) {}
+#if defined(WEBRTC_ANDROID)
+ LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag) {
+ }
+#endif
+ // DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS.
+ // Android code should use the 'const char*' version since tags are static
+ // and we want to avoid allocating a std::string copy per log line.
+ RTC_DEPRECATED
+ LogMessage(const char* file,
+ int line,
+ LoggingSeverity sev,
+ const std::string& tag) {}
+ ~LogMessage() = default;
+
+ inline void AddTag(const char* tag) {}
+ inline rtc::StringBuilder& stream() { return print_stream_; }
+ inline static int64_t LogStartTime() { return 0; }
+ inline static uint32_t WallClockStartTime() { return 0; }
+ inline static void LogThreads(bool on = true) {}
+ inline static void LogTimestamps(bool on = true) {}
+ inline static void LogToDebug(LoggingSeverity min_sev) {}
+ inline static LoggingSeverity GetLogToDebug() {
+ return LoggingSeverity::LS_INFO;
+ }
+ inline static void SetLogToStderr(bool log_to_stderr) {}
+ inline static void AddLogToStream(LogSink* stream, LoggingSeverity min_sev) {}
+ inline static void RemoveLogToStream(LogSink* stream) {}
+ inline static int GetLogToStream(LogSink* stream = nullptr) { return 0; }
+ inline static int GetMinLogSeverity() { return 0; }
+ inline static void ConfigureLogging(const char* params) {}
+ static constexpr bool IsNoop(LoggingSeverity severity) { return true; }
+ template <LoggingSeverity S>
+ static constexpr bool IsNoop() {
+ return IsNoop(S);
+ }
+#endif // RTC_LOG_ENABLED()
+
+ private:
+ friend class LogMessageForTesting;
+
+#if RTC_LOG_ENABLED()
+ // Updates min_sev_ appropriately when debug sinks change.
+ static void UpdateMinLogSeverity();
+
+// These write out the actual log messages.
+#if defined(WEBRTC_ANDROID)
+ static void OutputToDebug(const std::string& msg,
+ LoggingSeverity severity,
+ const char* tag);
+#else
+ static void OutputToDebug(const std::string& msg, LoggingSeverity severity);
+#endif // defined(WEBRTC_ANDROID)
+
+ // Called from the dtor (or from a test) to append optional extra error
+ // information to the log stream and a newline character.
+ void FinishPrintStream();
+
+ // The severity level of this message
+ LoggingSeverity severity_;
+
+#if defined(WEBRTC_ANDROID)
+ // The default Android debug output tag.
+ const char* tag_ = "libjingle";
+#endif
+
+ // String data generated in the constructor, that should be appended to
+ // the message before output.
+ std::string extra_;
+
+ // The output streams and their associated severities
+ static LogSink* streams_;
+
+ // Holds true with high probability if |streams_| is empty, false with high
+ // probability otherwise. Operated on with std::memory_order_relaxed because
+ // it's ok to lose or log some additional statements near the instant streams
+ // are added/removed.
+ static std::atomic<bool> streams_empty_;
+
+ // Flags for formatting options
+ static bool thread_, timestamp_;
+
+ // Determines if logs will be directed to stderr in debug mode.
+ static bool log_to_stderr_;
+#else // RTC_LOG_ENABLED()
+ // Next methods do nothing; no one will call these functions.
+ inline static void UpdateMinLogSeverity() {}
+#if defined(WEBRTC_ANDROID)
+ inline static void OutputToDebug(const std::string& msg,
+ LoggingSeverity severity,
+ const char* tag) {}
+#else
+ inline static void OutputToDebug(const std::string& msg,
+ LoggingSeverity severity) {}
+#endif // defined(WEBRTC_ANDROID)
+ inline void FinishPrintStream() {}
+#endif // RTC_LOG_ENABLED()
+
+ // The stringbuilder that buffers the formatted message before output
+ rtc::StringBuilder print_stream_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+//////////////////////////////////////////////////////////////////////
+// Logging Helpers
+//////////////////////////////////////////////////////////////////////
+
+#define RTC_LOG_FILE_LINE(sev, file, line) \
+ ::rtc::webrtc_logging_impl::LogCall() & \
+ ::rtc::webrtc_logging_impl::LogStreamer<>() \
+ << ::rtc::webrtc_logging_impl::LogMetadata(file, line, sev)
+
+#define RTC_LOG(sev) \
+ !rtc::LogMessage::IsNoop<::rtc::sev>() && \
+ RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__)
+
+// The _V version is for when a variable is passed in.
+#define RTC_LOG_V(sev) \
+ !rtc::LogMessage::IsNoop(sev) && RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__)
+
+// The _F version prefixes the message with the current function name.
+#if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F)
+#define RTC_LOG_F(sev) RTC_LOG(sev) << __PRETTY_FUNCTION__ << ": "
+#define RTC_LOG_T_F(sev) \
+ RTC_LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": "
+#else
+#define RTC_LOG_F(sev) RTC_LOG(sev) << __FUNCTION__ << ": "
+#define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " << __FUNCTION__ << ": "
+#endif
+
+#define RTC_LOG_CHECK_LEVEL(sev) ::rtc::LogCheckLevel(::rtc::sev)
+#define RTC_LOG_CHECK_LEVEL_V(sev) ::rtc::LogCheckLevel(sev)
+
+inline bool LogCheckLevel(LoggingSeverity sev) {
+ return (LogMessage::GetMinLogSeverity() <= sev);
+}
+
+#define RTC_LOG_E(sev, ctx, err) \
+ !rtc::LogMessage::IsNoop<::rtc::sev>() && \
+ ::rtc::webrtc_logging_impl::LogCall() & \
+ ::rtc::webrtc_logging_impl::LogStreamer<>() \
+ << ::rtc::webrtc_logging_impl::LogMetadataErr { \
+ {__FILE__, __LINE__, ::rtc::sev}, ::rtc::ERRCTX_##ctx, (err) \
+ }
+
+#define RTC_LOG_T(sev) RTC_LOG(sev) << this << ": "
+
+#define RTC_LOG_ERRNO_EX(sev, err) RTC_LOG_E(sev, ERRNO, err)
+#define RTC_LOG_ERRNO(sev) RTC_LOG_ERRNO_EX(sev, errno)
+
+#if defined(WEBRTC_WIN)
+#define RTC_LOG_GLE_EX(sev, err) RTC_LOG_E(sev, HRESULT, err)
+#define RTC_LOG_GLE(sev) RTC_LOG_GLE_EX(sev, static_cast<int>(GetLastError()))
+#define RTC_LOG_ERR_EX(sev, err) RTC_LOG_GLE_EX(sev, err)
+#define RTC_LOG_ERR(sev) RTC_LOG_GLE(sev)
+#elif defined(__native_client__) && __native_client__
+#define RTC_LOG_ERR_EX(sev, err) RTC_LOG(sev)
+#define RTC_LOG_ERR(sev) RTC_LOG(sev)
+#elif defined(WEBRTC_POSIX)
+#define RTC_LOG_ERR_EX(sev, err) RTC_LOG_ERRNO_EX(sev, err)
+#define RTC_LOG_ERR(sev) RTC_LOG_ERRNO(sev)
+#endif // WEBRTC_WIN
+
+#ifdef WEBRTC_ANDROID
+
+namespace webrtc_logging_impl {
+// TODO(kwiberg): Replace these with absl::string_view.
+inline const char* AdaptString(const char* str) {
+ return str;
+}
+inline const char* AdaptString(const std::string& str) {
+ return str.c_str();
+}
+} // namespace webrtc_logging_impl
+
+#define RTC_LOG_TAG(sev, tag) \
+ !rtc::LogMessage::IsNoop(sev) && \
+ ::rtc::webrtc_logging_impl::LogCall() & \
+ ::rtc::webrtc_logging_impl::LogStreamer<>() \
+ << ::rtc::webrtc_logging_impl::LogMetadataTag { \
+ sev, ::rtc::webrtc_logging_impl::AdaptString(tag) \
+ }
+
+#else
+
+// DEPRECATED. This macro is only intended for Android.
+#define RTC_LOG_TAG(sev, tag) RTC_LOG_V(sev)
+
+#endif
+
+// The RTC_DLOG macros are equivalent to their RTC_LOG counterparts except that
+// they only generate code in debug builds.
+#if RTC_DLOG_IS_ON
+#define RTC_DLOG(sev) RTC_LOG(sev)
+#define RTC_DLOG_V(sev) RTC_LOG_V(sev)
+#define RTC_DLOG_F(sev) RTC_LOG_F(sev)
+#else
+#define RTC_DLOG_EAT_STREAM_PARAMS() \
+ while (false) \
+ ::rtc::webrtc_logging_impl::LogMessageVoidify() & \
+ (::rtc::webrtc_logging_impl::LogStreamer<>())
+#define RTC_DLOG(sev) RTC_DLOG_EAT_STREAM_PARAMS()
+#define RTC_DLOG_V(sev) RTC_DLOG_EAT_STREAM_PARAMS()
+#define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS()
+#endif
+
+} // namespace rtc
+
+#endif // RTC_BASE_LOGGING_H_
diff --git a/webrtc/rtc_base/memory/BUILD.gn b/webrtc/rtc_base/memory/BUILD.gn
new file mode 100644
index 0000000..838fbc6
--- /dev/null
+++ b/webrtc/rtc_base/memory/BUILD.gn
@@ -0,0 +1,56 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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")
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+rtc_library("aligned_malloc") {
+ sources = [
+ "aligned_malloc.cc",
+ "aligned_malloc.h",
+ ]
+ deps = [ "..:checks" ]
+}
+
+# Test only utility.
+# TODO: Tag with `testonly = true` once all depending targets are correctly
+# tagged.
+rtc_library("fifo_buffer") {
+ visibility = [
+ ":unittests",
+ "..:rtc_base_tests_utils",
+ "..:rtc_base_unittests",
+ "../../p2p:rtc_p2p", # This needs to be fixed.
+ ]
+ sources = [
+ "fifo_buffer.cc",
+ "fifo_buffer.h",
+ ]
+ deps = [
+ "..:rtc_base",
+ "../synchronization:mutex",
+ "../task_utils:pending_task_safety_flag",
+ "../task_utils:to_queued_task",
+ ]
+}
+
+rtc_library("unittests") {
+ testonly = true
+ sources = [
+ "aligned_malloc_unittest.cc",
+ "fifo_buffer_unittest.cc",
+ ]
+ deps = [
+ ":aligned_malloc",
+ ":fifo_buffer",
+ "../../test:test_support",
+ ]
+}
diff --git a/webrtc/system_wrappers/source/aligned_malloc.cc b/webrtc/rtc_base/memory/aligned_malloc.cc
index a654e97..b00fab2 100644
--- a/webrtc/system_wrappers/source/aligned_malloc.cc
+++ b/webrtc/rtc_base/memory/aligned_malloc.cc
@@ -8,19 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/system_wrappers/include/aligned_malloc.h"
+#include "rtc_base/memory/aligned_malloc.h"
-#include <memory.h>
-#include <stdlib.h>
+#include <stdlib.h> // for free, malloc
+#include <string.h> // for memcpy
-#if _WIN32
+#include "rtc_base/checks.h"
+
+#ifdef _WIN32
#include <windows.h>
#else
#include <stdint.h>
#endif
-#include "webrtc/typedefs.h"
-
// Reference on memory alignment:
// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
namespace webrtc {
@@ -63,9 +63,7 @@ void* AlignedMalloc(size_t size, size_t alignment) {
// A pointer to the start of the memory must be stored so that it can be
// retreived for deletion, ergo the sizeof(uintptr_t).
void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
- if (memory_pointer == NULL) {
- return NULL;
- }
+ RTC_CHECK(memory_pointer) << "Couldn't allocate memory in AlignedMalloc";
// Aligning after the sizeof(uintptr_t) bytes will leave room for the header
// in the same memory block.
diff --git a/webrtc/system_wrappers/include/aligned_malloc.h b/webrtc/rtc_base/memory/aligned_malloc.h
index 277abec..42a6daa 100644
--- a/webrtc/system_wrappers/include/aligned_malloc.h
+++ b/webrtc/rtc_base/memory/aligned_malloc.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ALIGNED_MALLOC_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ALIGNED_MALLOC_H_
+#ifndef RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
+#define RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
// The functions declared here
// 1) Allocates block of aligned memory.
@@ -36,24 +36,22 @@ void AlignedFree(void* mem_block);
// Templated versions to facilitate usage of aligned malloc without casting
// to and from void*.
-template<typename T>
+template <typename T>
T* GetRightAlign(const T* ptr, size_t alignment) {
- return reinterpret_cast<T*>(GetRightAlign(reinterpret_cast<const void*>(ptr),
- alignment));
+ return reinterpret_cast<T*>(
+ GetRightAlign(reinterpret_cast<const void*>(ptr), alignment));
}
-template<typename T>
+template <typename T>
T* AlignedMalloc(size_t size, size_t alignment) {
return reinterpret_cast<T*>(AlignedMalloc(size, alignment));
}
-// Deleter for use with scoped_ptr. E.g., use as
-// scoped_ptr<Foo, AlignedFreeDeleter> foo;
+// Deleter for use with unique_ptr. E.g., use as
+// std::unique_ptr<Foo, AlignedFreeDeleter> foo;
struct AlignedFreeDeleter {
- inline void operator()(void* ptr) const {
- AlignedFree(ptr);
- }
+ inline void operator()(void* ptr) const { AlignedFree(ptr); }
};
} // namespace webrtc
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ALIGNED_MALLOC_H_
+#endif // RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
diff --git a/webrtc/rtc_base/meson.build b/webrtc/rtc_base/meson.build
new file mode 100644
index 0000000..5977c7e
--- /dev/null
+++ b/webrtc/rtc_base/meson.build
@@ -0,0 +1,64 @@
+base_sources = [
+ 'checks.cc',
+ 'event.cc',
+ 'event_tracer.cc',
+ 'experiments/field_trial_parser.cc',
+ 'logging.cc',
+ 'memory/aligned_malloc.cc',
+ 'platform_thread.cc',
+ 'platform_thread_types.cc',
+ 'race_checker.cc',
+ 'string_encode.cc',
+ 'string_to_number.cc',
+ 'string_utils.cc',
+ 'strings/string_builder.cc',
+ 'synchronization/mutex.cc',
+ 'synchronization/rw_lock_wrapper.cc',
+ 'synchronization/yield.cc',
+ 'synchronization/yield_policy.cc',
+ 'system/file_wrapper.cc',
+ 'time_utils.cc',
+ 'zero_memory.cc',
+]
+
+base_headers = [
+ [ '', 'arraysize.h' ],
+ [ '', 'checks.h' ],
+ [ '', 'constructor_magic.h' ],
+ [ '', 'deprecation.h' ],
+ [ '', 'ref_count.h' ],
+ [ '', 'type_traits.h' ],
+ [ 'numerics', 'safe_compare.h' ],
+ [ 'system', 'file_wrapper.h' ],
+ [ 'system', 'inline.h' ],
+ [ 'system', 'rtc_export.h' ],
+]
+
+if have_posix
+ base_sources += [
+ 'synchronization/rw_lock_posix.cc',
+ ]
+elif have_win
+ base_sources += [
+ 'synchronization/rw_lock_win.cc',
+ ]
+endif
+
+foreach h : base_headers
+ install_headers(
+ join_paths(h[0], h[1]),
+ subdir: join_paths('webrtc_audio_processing', 'rtc_base', h[0])
+ )
+endforeach
+
+libbase = static_library('libbase',
+ base_sources,
+ dependencies: common_deps,
+ include_directories: webrtc_inc,
+ cpp_args : common_cxxflags
+)
+
+base_dep = declare_dependency(
+ link_with: libbase
+)
+
diff --git a/webrtc/rtc_base/numerics/safe_compare.h b/webrtc/rtc_base/numerics/safe_compare.h
new file mode 100644
index 0000000..85f0a30
--- /dev/null
+++ b/webrtc/rtc_base/numerics/safe_compare.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 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.
+ */
+
+// This file defines six constexpr functions:
+//
+// rtc::SafeEq // ==
+// rtc::SafeNe // !=
+// rtc::SafeLt // <
+// rtc::SafeLe // <=
+// rtc::SafeGt // >
+// rtc::SafeGe // >=
+//
+// They each accept two arguments of arbitrary types, and in almost all cases,
+// they simply call the appropriate comparison operator. However, if both
+// arguments are integers, they don't compare them using C++'s quirky rules,
+// but instead adhere to the true mathematical definitions. It is as if the
+// arguments were first converted to infinite-range signed integers, and then
+// compared, although of course nothing expensive like that actually takes
+// place. In practice, for signed/signed and unsigned/unsigned comparisons and
+// some mixed-signed comparisons with a compile-time constant, the overhead is
+// zero; in the remaining cases, it is just a few machine instructions (no
+// branches).
+
+#ifndef RTC_BASE_NUMERICS_SAFE_COMPARE_H_
+#define RTC_BASE_NUMERICS_SAFE_COMPARE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <type_traits>
+#include <utility>
+
+#include "rtc_base/type_traits.h"
+
+namespace rtc {
+
+namespace safe_cmp_impl {
+
+template <size_t N>
+struct LargerIntImpl : std::false_type {};
+template <>
+struct LargerIntImpl<sizeof(int8_t)> : std::true_type {
+ using type = int16_t;
+};
+template <>
+struct LargerIntImpl<sizeof(int16_t)> : std::true_type {
+ using type = int32_t;
+};
+template <>
+struct LargerIntImpl<sizeof(int32_t)> : std::true_type {
+ using type = int64_t;
+};
+
+// LargerInt<T1, T2>::value is true iff there's a signed type that's larger
+// than T1 (and no larger than the larger of T2 and int*, for performance
+// reasons); and if there is such a type, LargerInt<T1, T2>::type is an alias
+// for it.
+template <typename T1, typename T2>
+struct LargerInt
+ : LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*)
+ ? sizeof(T1)
+ : 0> {};
+
+template <typename T>
+constexpr typename std::make_unsigned<T>::type MakeUnsigned(T a) {
+ return static_cast<typename std::make_unsigned<T>::type>(a);
+}
+
+// Overload for when both T1 and T2 have the same signedness.
+template <typename Op,
+ typename T1,
+ typename T2,
+ typename std::enable_if<std::is_signed<T1>::value ==
+ std::is_signed<T2>::value>::type* = nullptr>
+constexpr bool Cmp(T1 a, T2 b) {
+ return Op::Op(a, b);
+}
+
+// Overload for signed - unsigned comparison that can be promoted to a bigger
+// signed type.
+template <typename Op,
+ typename T1,
+ typename T2,
+ typename std::enable_if<std::is_signed<T1>::value &&
+ std::is_unsigned<T2>::value &&
+ LargerInt<T2, T1>::value>::type* = nullptr>
+constexpr bool Cmp(T1 a, T2 b) {
+ return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b));
+}
+
+// Overload for unsigned - signed comparison that can be promoted to a bigger
+// signed type.
+template <typename Op,
+ typename T1,
+ typename T2,
+ typename std::enable_if<std::is_unsigned<T1>::value &&
+ std::is_signed<T2>::value &&
+ LargerInt<T1, T2>::value>::type* = nullptr>
+constexpr bool Cmp(T1 a, T2 b) {
+ return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b);
+}
+
+// Overload for signed - unsigned comparison that can't be promoted to a bigger
+// signed type.
+template <typename Op,
+ typename T1,
+ typename T2,
+ typename std::enable_if<std::is_signed<T1>::value &&
+ std::is_unsigned<T2>::value &&
+ !LargerInt<T2, T1>::value>::type* = nullptr>
+constexpr bool Cmp(T1 a, T2 b) {
+ return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b);
+}
+
+// Overload for unsigned - signed comparison that can't be promoted to a bigger
+// signed type.
+template <typename Op,
+ typename T1,
+ typename T2,
+ typename std::enable_if<std::is_unsigned<T1>::value &&
+ std::is_signed<T2>::value &&
+ !LargerInt<T1, T2>::value>::type* = nullptr>
+constexpr bool Cmp(T1 a, T2 b) {
+ return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b));
+}
+
+#define RTC_SAFECMP_MAKE_OP(name, op) \
+ struct name { \
+ template <typename T1, typename T2> \
+ static constexpr bool Op(T1 a, T2 b) { \
+ return a op b; \
+ } \
+ };
+RTC_SAFECMP_MAKE_OP(EqOp, ==)
+RTC_SAFECMP_MAKE_OP(NeOp, !=)
+RTC_SAFECMP_MAKE_OP(LtOp, <)
+RTC_SAFECMP_MAKE_OP(LeOp, <=)
+RTC_SAFECMP_MAKE_OP(GtOp, >)
+RTC_SAFECMP_MAKE_OP(GeOp, >=)
+#undef RTC_SAFECMP_MAKE_OP
+
+} // namespace safe_cmp_impl
+
+#define RTC_SAFECMP_MAKE_FUN(name) \
+ template <typename T1, typename T2> \
+ constexpr \
+ typename std::enable_if<IsIntlike<T1>::value && IsIntlike<T2>::value, \
+ bool>::type Safe##name(T1 a, T2 b) { \
+ /* Unary plus here turns enums into real integral types. */ \
+ return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b); \
+ } \
+ template <typename T1, typename T2> \
+ constexpr \
+ typename std::enable_if<!IsIntlike<T1>::value || !IsIntlike<T2>::value, \
+ bool>::type Safe##name(const T1& a, \
+ const T2& b) { \
+ return safe_cmp_impl::name##Op::Op(a, b); \
+ }
+RTC_SAFECMP_MAKE_FUN(Eq)
+RTC_SAFECMP_MAKE_FUN(Ne)
+RTC_SAFECMP_MAKE_FUN(Lt)
+RTC_SAFECMP_MAKE_FUN(Le)
+RTC_SAFECMP_MAKE_FUN(Gt)
+RTC_SAFECMP_MAKE_FUN(Ge)
+#undef RTC_SAFECMP_MAKE_FUN
+
+} // namespace rtc
+
+#endif // RTC_BASE_NUMERICS_SAFE_COMPARE_H_
diff --git a/webrtc/base/safe_conversions.h b/webrtc/rtc_base/numerics/safe_conversions.h
index 51239bc..5d58672 100644
--- a/webrtc/base/safe_conversions.h
+++ b/webrtc/rtc_base/numerics/safe_conversions.h
@@ -10,37 +10,43 @@
// Borrowed from Chromium's src/base/numerics/safe_conversions.h.
-#ifndef WEBRTC_BASE_SAFE_CONVERSIONS_H_
-#define WEBRTC_BASE_SAFE_CONVERSIONS_H_
+#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
#include <limits>
-#include "webrtc/base/checks.h"
-#include "webrtc/base/safe_conversions_impl.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions_impl.h"
namespace rtc {
// Convenience function that returns true if the supplied value is in range
// for the destination type.
template <typename Dst, typename Src>
-inline bool IsValueInRangeForNumericType(Src value) {
+inline constexpr bool IsValueInRangeForNumericType(Src value) {
return internal::RangeCheck<Dst>(value) == internal::TYPE_VALID;
}
-// checked_cast<> is analogous to static_cast<> for numeric types,
-// except that it CHECKs that the specified numeric conversion will not
-// overflow or underflow. NaN source will always trigger a CHECK.
+// checked_cast<> and dchecked_cast<> are analogous to static_cast<> for
+// numeric types, except that they [D]CHECK that the specified numeric
+// conversion will not overflow or underflow. NaN source will always trigger
+// the [D]CHECK.
template <typename Dst, typename Src>
-inline Dst checked_cast(Src value) {
+inline constexpr Dst checked_cast(Src value) {
RTC_CHECK(IsValueInRangeForNumericType<Dst>(value));
return static_cast<Dst>(value);
}
+template <typename Dst, typename Src>
+inline constexpr Dst dchecked_cast(Src value) {
+ RTC_DCHECK(IsValueInRangeForNumericType<Dst>(value));
+ return static_cast<Dst>(value);
+}
// saturated_cast<> is analogous to static_cast<> for numeric types, except
// that the specified numeric conversion will saturate rather than overflow or
// underflow. NaN assignment to an integral will trigger a RTC_CHECK condition.
template <typename Dst, typename Src>
-inline Dst saturated_cast(Src value) {
+inline constexpr Dst saturated_cast(Src value) {
// Optimization for floating point values, which already saturate.
if (std::numeric_limits<Dst>::is_iec559)
return static_cast<Dst>(value);
@@ -67,4 +73,4 @@ inline Dst saturated_cast(Src value) {
} // namespace rtc
-#endif // WEBRTC_BASE_SAFE_CONVERSIONS_H_
+#endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/webrtc/base/safe_conversions_impl.h b/webrtc/rtc_base/numerics/safe_conversions_impl.h
index 52e52ef..e924ce3 100644
--- a/webrtc/base/safe_conversions_impl.h
+++ b/webrtc/rtc_base/numerics/safe_conversions_impl.h
@@ -10,37 +10,29 @@
// Borrowed from Chromium's src/base/numerics/safe_conversions_impl.h.
-#ifndef WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_
-#define WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_
+#ifndef RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#define RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
#include <limits>
namespace rtc {
namespace internal {
-enum DstSign {
- DST_UNSIGNED,
- DST_SIGNED
-};
+enum DstSign { DST_UNSIGNED, DST_SIGNED };
-enum SrcSign {
- SRC_UNSIGNED,
- SRC_SIGNED
-};
+enum SrcSign { SRC_UNSIGNED, SRC_SIGNED };
-enum DstRange {
- OVERLAPS_RANGE,
- CONTAINS_RANGE
-};
+enum DstRange { OVERLAPS_RANGE, CONTAINS_RANGE };
// Helper templates to statically determine if our destination type can contain
// all values represented by the source type.
-template <typename Dst, typename Src,
- DstSign IsDstSigned = std::numeric_limits<Dst>::is_signed ?
- DST_SIGNED : DST_UNSIGNED,
- SrcSign IsSrcSigned = std::numeric_limits<Src>::is_signed ?
- SRC_SIGNED : SRC_UNSIGNED>
+template <typename Dst,
+ typename Src,
+ DstSign IsDstSigned =
+ std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED,
+ SrcSign IsSrcSigned =
+ std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED>
struct StaticRangeCheck {};
template <typename Dst, typename Src>
@@ -48,20 +40,18 @@ struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_SIGNED> {
typedef std::numeric_limits<Dst> DstLimits;
typedef std::numeric_limits<Src> SrcLimits;
// Compare based on max_exponent, which we must compute for integrals.
- static const size_t kDstMaxExponent = DstLimits::is_iec559 ?
- DstLimits::max_exponent :
- (sizeof(Dst) * 8 - 1);
- static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ?
- SrcLimits::max_exponent :
- (sizeof(Src) * 8 - 1);
- static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ?
- CONTAINS_RANGE : OVERLAPS_RANGE;
+ static const size_t kDstMaxExponent =
+ DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1);
+ static const size_t kSrcMaxExponent =
+ SrcLimits::is_iec559 ? SrcLimits::max_exponent : (sizeof(Src) * 8 - 1);
+ static const DstRange value =
+ kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE;
};
template <typename Dst, typename Src>
struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED> {
- static const DstRange value = sizeof(Dst) >= sizeof(Src) ?
- CONTAINS_RANGE : OVERLAPS_RANGE;
+ static const DstRange value =
+ sizeof(Dst) >= sizeof(Src) ? CONTAINS_RANGE : OVERLAPS_RANGE;
};
template <typename Dst, typename Src>
@@ -69,12 +59,11 @@ struct StaticRangeCheck<Dst, Src, DST_SIGNED, SRC_UNSIGNED> {
typedef std::numeric_limits<Dst> DstLimits;
typedef std::numeric_limits<Src> SrcLimits;
// Compare based on max_exponent, which we must compute for integrals.
- static const size_t kDstMaxExponent = DstLimits::is_iec559 ?
- DstLimits::max_exponent :
- (sizeof(Dst) * 8 - 1);
+ static const size_t kDstMaxExponent =
+ DstLimits::is_iec559 ? DstLimits::max_exponent : (sizeof(Dst) * 8 - 1);
static const size_t kSrcMaxExponent = sizeof(Src) * 8;
- static const DstRange value = kDstMaxExponent >= kSrcMaxExponent ?
- CONTAINS_RANGE : OVERLAPS_RANGE;
+ static const DstRange value =
+ kDstMaxExponent >= kSrcMaxExponent ? CONTAINS_RANGE : OVERLAPS_RANGE;
};
template <typename Dst, typename Src>
@@ -82,7 +71,6 @@ struct StaticRangeCheck<Dst, Src, DST_UNSIGNED, SRC_SIGNED> {
static const DstRange value = OVERLAPS_RANGE;
};
-
enum RangeCheckResult {
TYPE_VALID = 0, // Value can be represented by the destination type.
TYPE_UNDERFLOW = 1, // Value would overflow.
@@ -94,15 +82,15 @@ enum RangeCheckResult {
// check by taking advantage of the fact that only NaN can be out of range in
// both directions at once.
#define BASE_NUMERIC_RANGE_CHECK_RESULT(is_in_upper_bound, is_in_lower_bound) \
- RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \
- ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW))
+ RangeCheckResult(((is_in_upper_bound) ? 0 : TYPE_OVERFLOW) | \
+ ((is_in_lower_bound) ? 0 : TYPE_UNDERFLOW))
template <typename Dst,
typename Src,
- DstSign IsDstSigned = std::numeric_limits<Dst>::is_signed ?
- DST_SIGNED : DST_UNSIGNED,
- SrcSign IsSrcSigned = std::numeric_limits<Src>::is_signed ?
- SRC_SIGNED : SRC_UNSIGNED,
+ DstSign IsDstSigned =
+ std::numeric_limits<Dst>::is_signed ? DST_SIGNED : DST_UNSIGNED,
+ SrcSign IsSrcSigned =
+ std::numeric_limits<Src>::is_signed ? SRC_SIGNED : SRC_UNSIGNED,
DstRange IsSrcRangeContained = StaticRangeCheck<Dst, Src>::value>
struct RangeCheckImpl {};
@@ -113,68 +101,69 @@ struct RangeCheckImpl {};
// Dst range always contains the result: nothing to check.
template <typename Dst, typename Src, DstSign IsDstSigned, SrcSign IsSrcSigned>
struct RangeCheckImpl<Dst, Src, IsDstSigned, IsSrcSigned, CONTAINS_RANGE> {
- static RangeCheckResult Check(Src value) {
- return TYPE_VALID;
- }
+ static constexpr RangeCheckResult Check(Src value) { return TYPE_VALID; }
};
// Signed to signed narrowing.
template <typename Dst, typename Src>
struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
- static RangeCheckResult Check(Src value) {
+ static constexpr RangeCheckResult Check(Src value) {
typedef std::numeric_limits<Dst> DstLimits;
- return DstLimits::is_iec559 ?
- BASE_NUMERIC_RANGE_CHECK_RESULT(
- value <= static_cast<Src>(DstLimits::max()),
- value >= static_cast<Src>(DstLimits::max() * -1)) :
- BASE_NUMERIC_RANGE_CHECK_RESULT(
- value <= static_cast<Src>(DstLimits::max()),
- value >= static_cast<Src>(DstLimits::min()));
+ return DstLimits::is_iec559
+ ? BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()),
+ value >= static_cast<Src>(DstLimits::max() * -1))
+ : BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()),
+ value >= static_cast<Src>(DstLimits::min()));
}
};
// Unsigned to unsigned narrowing.
template <typename Dst, typename Src>
struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
- static RangeCheckResult Check(Src value) {
+ static constexpr RangeCheckResult Check(Src value) {
typedef std::numeric_limits<Dst> DstLimits;
return BASE_NUMERIC_RANGE_CHECK_RESULT(
- value <= static_cast<Src>(DstLimits::max()), true);
+ value <= static_cast<Src>(DstLimits::max()), true);
}
};
// Unsigned to signed.
template <typename Dst, typename Src>
struct RangeCheckImpl<Dst, Src, DST_SIGNED, SRC_UNSIGNED, OVERLAPS_RANGE> {
- static RangeCheckResult Check(Src value) {
+ static constexpr RangeCheckResult Check(Src value) {
typedef std::numeric_limits<Dst> DstLimits;
- return sizeof(Dst) > sizeof(Src) ? TYPE_VALID :
- BASE_NUMERIC_RANGE_CHECK_RESULT(
- value <= static_cast<Src>(DstLimits::max()), true);
+ return sizeof(Dst) > sizeof(Src)
+ ? TYPE_VALID
+ : BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()), true);
}
};
// Signed to unsigned.
template <typename Dst, typename Src>
struct RangeCheckImpl<Dst, Src, DST_UNSIGNED, SRC_SIGNED, OVERLAPS_RANGE> {
- static RangeCheckResult Check(Src value) {
- typedef std::numeric_limits<Dst> DstLimits;
- typedef std::numeric_limits<Src> SrcLimits;
- // Compare based on max_exponent, which we must compute for integrals.
- static const size_t kDstMaxExponent = sizeof(Dst) * 8;
- static const size_t kSrcMaxExponent = SrcLimits::is_iec559 ?
- SrcLimits::max_exponent :
- (sizeof(Src) * 8 - 1);
- return (kDstMaxExponent >= kSrcMaxExponent) ?
- BASE_NUMERIC_RANGE_CHECK_RESULT(true, value >= static_cast<Src>(0)) :
- BASE_NUMERIC_RANGE_CHECK_RESULT(
- value <= static_cast<Src>(DstLimits::max()),
- value >= static_cast<Src>(0));
+ typedef std::numeric_limits<Dst> DstLimits;
+ typedef std::numeric_limits<Src> SrcLimits;
+ // Compare based on max_exponent, which we must compute for integrals.
+ static constexpr size_t DstMaxExponent() { return sizeof(Dst) * 8; }
+ static constexpr size_t SrcMaxExponent() {
+ return SrcLimits::is_iec559 ? SrcLimits::max_exponent
+ : (sizeof(Src) * 8 - 1);
+ }
+ static constexpr RangeCheckResult Check(Src value) {
+ return (DstMaxExponent() >= SrcMaxExponent())
+ ? BASE_NUMERIC_RANGE_CHECK_RESULT(true,
+ value >= static_cast<Src>(0))
+ : BASE_NUMERIC_RANGE_CHECK_RESULT(
+ value <= static_cast<Src>(DstLimits::max()),
+ value >= static_cast<Src>(0));
}
};
template <typename Dst, typename Src>
-inline RangeCheckResult RangeCheck(Src value) {
+inline constexpr RangeCheckResult RangeCheck(Src value) {
static_assert(std::numeric_limits<Src>::is_specialized,
"argument must be numeric");
static_assert(std::numeric_limits<Dst>::is_specialized,
@@ -185,4 +174,4 @@ inline RangeCheckResult RangeCheck(Src value) {
} // namespace internal
} // namespace rtc
-#endif // WEBRTC_BASE_SAFE_CONVERSIONS_IMPL_H_
+#endif // RTC_BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
diff --git a/webrtc/rtc_base/numerics/safe_minmax.h b/webrtc/rtc_base/numerics/safe_minmax.h
new file mode 100644
index 0000000..6c41dfd
--- /dev/null
+++ b/webrtc/rtc_base/numerics/safe_minmax.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright 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.
+ */
+
+// Minimum and maximum
+// ===================
+//
+// rtc::SafeMin(x, y)
+// rtc::SafeMax(x, y)
+//
+// (These are both constexpr.)
+//
+// Accept two arguments of either any two integral or any two floating-point
+// types, and return the smaller and larger value, respectively, with no
+// truncation or wrap-around. If only one of the input types is statically
+// guaranteed to be able to represent the result, the return type is that type;
+// if either one would do, the result type is the smaller type. (One of these
+// two cases always applies.)
+//
+// * The case with one floating-point and one integral type is not allowed,
+// because the floating-point type will have greater range, but may not
+// have sufficient precision to represent the integer value exactly.)
+//
+// Clamp (a.k.a. constrain to a given interval)
+// ============================================
+//
+// rtc::SafeClamp(x, a, b)
+//
+// Accepts three arguments of any mix of integral types or any mix of
+// floating-point types, and returns the value in the closed interval [a, b]
+// that is closest to x (that is, if x < a it returns a; if x > b it returns b;
+// and if a <= x <= b it returns x). As for SafeMin() and SafeMax(), there is
+// no truncation or wrap-around. The result type
+//
+// 1. is statically guaranteed to be able to represent the result;
+//
+// 2. is no larger than the largest of the three argument types; and
+//
+// 3. has the same signedness as the type of the first argument, if this is
+// possible without violating the First or Second Law.
+//
+// There is always at least one type that meets criteria 1 and 2. If more than
+// one type meets these criteria equally well, the result type is one of the
+// types that is smallest. Note that unlike SafeMin() and SafeMax(),
+// SafeClamp() will sometimes pick a return type that isn't the type of any of
+// its arguments.
+//
+// * In this context, a type A is smaller than a type B if it has a smaller
+// range; that is, if A::max() - A::min() < B::max() - B::min(). For
+// example, int8_t < int16_t == uint16_t < int32_t, and all integral types
+// are smaller than all floating-point types.)
+//
+// * As for SafeMin and SafeMax, mixing integer and floating-point arguments
+// is not allowed, because floating-point types have greater range than
+// integer types, but do not have sufficient precision to represent the
+// values of most integer types exactly.
+//
+// Requesting a specific return type
+// =================================
+//
+// All three functions allow callers to explicitly specify the return type as a
+// template parameter, overriding the default return type. E.g.
+//
+// rtc::SafeMin<int>(x, y) // returns an int
+//
+// If the requested type is statically guaranteed to be able to represent the
+// result, then everything's fine, and the return type is as requested. But if
+// the requested type is too small, a static_assert is triggered.
+
+#ifndef RTC_BASE_NUMERICS_SAFE_MINMAX_H_
+#define RTC_BASE_NUMERICS_SAFE_MINMAX_H_
+
+#include <limits>
+#include <type_traits>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_compare.h"
+#include "rtc_base/type_traits.h"
+
+namespace rtc {
+
+namespace safe_minmax_impl {
+
+// Make the range of a type available via something other than a constexpr
+// function, to work around MSVC limitations. See
+// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
+template <typename T>
+struct Limits {
+ static constexpr T lowest = std::numeric_limits<T>::lowest();
+ static constexpr T max = std::numeric_limits<T>::max();
+};
+
+template <typename T, bool is_enum = std::is_enum<T>::value>
+struct UnderlyingType;
+
+template <typename T>
+struct UnderlyingType<T, false> {
+ using type = T;
+};
+
+template <typename T>
+struct UnderlyingType<T, true> {
+ using type = typename std::underlying_type<T>::type;
+};
+
+// Given two types T1 and T2, find types that can hold the smallest (in
+// ::min_t) and the largest (in ::max_t) of the two values.
+template <typename T1,
+ typename T2,
+ bool int1 = IsIntlike<T1>::value,
+ bool int2 = IsIntlike<T2>::value>
+struct MType {
+ static_assert(int1 == int2,
+ "You may not mix integral and floating-point arguments");
+};
+
+// Specialization for when neither type is integral (and therefore presumably
+// floating-point).
+template <typename T1, typename T2>
+struct MType<T1, T2, false, false> {
+ using min_t = typename std::common_type<T1, T2>::type;
+ static_assert(std::is_same<min_t, T1>::value ||
+ std::is_same<min_t, T2>::value,
+ "");
+
+ using max_t = typename std::common_type<T1, T2>::type;
+ static_assert(std::is_same<max_t, T1>::value ||
+ std::is_same<max_t, T2>::value,
+ "");
+};
+
+// Specialization for when both types are integral.
+template <typename T1, typename T2>
+struct MType<T1, T2, true, true> {
+ // The type with the lowest minimum value. In case of a tie, the type with
+ // the lowest maximum value. In case that too is a tie, the types have the
+ // same range, and we arbitrarily pick T1.
+ using min_t = typename std::conditional<
+ SafeLt(Limits<T1>::lowest, Limits<T2>::lowest),
+ T1,
+ typename std::conditional<
+ SafeGt(Limits<T1>::lowest, Limits<T2>::lowest),
+ T2,
+ typename std::conditional<SafeLe(Limits<T1>::max, Limits<T2>::max),
+ T1,
+ T2>::type>::type>::type;
+ static_assert(std::is_same<min_t, T1>::value ||
+ std::is_same<min_t, T2>::value,
+ "");
+
+ // The type with the highest maximum value. In case of a tie, the types have
+ // the same range (because in C++, integer types with the same maximum also
+ // have the same minimum).
+ static_assert(SafeNe(Limits<T1>::max, Limits<T2>::max) ||
+ SafeEq(Limits<T1>::lowest, Limits<T2>::lowest),
+ "integer types with the same max should have the same min");
+ using max_t = typename std::
+ conditional<SafeGe(Limits<T1>::max, Limits<T2>::max), T1, T2>::type;
+ static_assert(std::is_same<max_t, T1>::value ||
+ std::is_same<max_t, T2>::value,
+ "");
+};
+
+// A dummy type that we pass around at compile time but never actually use.
+// Declared but not defined.
+struct DefaultType;
+
+// ::type is A, except we fall back to B if A is DefaultType. We static_assert
+// that the chosen type can hold all values that B can hold.
+template <typename A, typename B>
+struct TypeOr {
+ using type = typename std::
+ conditional<std::is_same<A, DefaultType>::value, B, A>::type;
+ static_assert(SafeLe(Limits<type>::lowest, Limits<B>::lowest) &&
+ SafeGe(Limits<type>::max, Limits<B>::max),
+ "The specified type isn't large enough");
+ static_assert(IsIntlike<type>::value == IsIntlike<B>::value &&
+ std::is_floating_point<type>::value ==
+ std::is_floating_point<type>::value,
+ "float<->int conversions not allowed");
+};
+
+} // namespace safe_minmax_impl
+
+template <
+ typename R = safe_minmax_impl::DefaultType,
+ typename T1 = safe_minmax_impl::DefaultType,
+ typename T2 = safe_minmax_impl::DefaultType,
+ typename R2 = typename safe_minmax_impl::TypeOr<
+ R,
+ typename safe_minmax_impl::MType<
+ typename safe_minmax_impl::UnderlyingType<T1>::type,
+ typename safe_minmax_impl::UnderlyingType<T2>::type>::min_t>::type>
+constexpr R2 SafeMin(T1 a, T2 b) {
+ static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value,
+ "The first argument must be integral or floating-point");
+ static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value,
+ "The second argument must be integral or floating-point");
+ return SafeLt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
+}
+
+template <
+ typename R = safe_minmax_impl::DefaultType,
+ typename T1 = safe_minmax_impl::DefaultType,
+ typename T2 = safe_minmax_impl::DefaultType,
+ typename R2 = typename safe_minmax_impl::TypeOr<
+ R,
+ typename safe_minmax_impl::MType<
+ typename safe_minmax_impl::UnderlyingType<T1>::type,
+ typename safe_minmax_impl::UnderlyingType<T2>::type>::max_t>::type>
+constexpr R2 SafeMax(T1 a, T2 b) {
+ static_assert(IsIntlike<T1>::value || std::is_floating_point<T1>::value,
+ "The first argument must be integral or floating-point");
+ static_assert(IsIntlike<T2>::value || std::is_floating_point<T2>::value,
+ "The second argument must be integral or floating-point");
+ return SafeGt(a, b) ? static_cast<R2>(a) : static_cast<R2>(b);
+}
+
+namespace safe_minmax_impl {
+
+// Given three types T, L, and H, let ::type be a suitable return value for
+// SafeClamp(T, L, H). See the docs at the top of this file for details.
+template <typename T,
+ typename L,
+ typename H,
+ bool int1 = IsIntlike<T>::value,
+ bool int2 = IsIntlike<L>::value,
+ bool int3 = IsIntlike<H>::value>
+struct ClampType {
+ static_assert(int1 == int2 && int1 == int3,
+ "You may not mix integral and floating-point arguments");
+};
+
+// Specialization for when all three types are floating-point.
+template <typename T, typename L, typename H>
+struct ClampType<T, L, H, false, false, false> {
+ using type = typename std::common_type<T, L, H>::type;
+};
+
+// Specialization for when all three types are integral.
+template <typename T, typename L, typename H>
+struct ClampType<T, L, H, true, true, true> {
+ private:
+ // Range of the return value. The return type must be able to represent this
+ // full range.
+ static constexpr auto r_min =
+ SafeMax(Limits<L>::lowest, SafeMin(Limits<H>::lowest, Limits<T>::lowest));
+ static constexpr auto r_max =
+ SafeMin(Limits<H>::max, SafeMax(Limits<L>::max, Limits<T>::max));
+
+ // Is the given type an acceptable return type? (That is, can it represent
+ // all possible return values, and is it no larger than the largest of the
+ // input types?)
+ template <typename A>
+ struct AcceptableType {
+ private:
+ static constexpr bool not_too_large = sizeof(A) <= sizeof(L) ||
+ sizeof(A) <= sizeof(H) ||
+ sizeof(A) <= sizeof(T);
+ static constexpr bool range_contained =
+ SafeLe(Limits<A>::lowest, r_min) && SafeLe(r_max, Limits<A>::max);
+
+ public:
+ static constexpr bool value = not_too_large && range_contained;
+ };
+
+ using best_signed_type = typename std::conditional<
+ AcceptableType<int8_t>::value,
+ int8_t,
+ typename std::conditional<
+ AcceptableType<int16_t>::value,
+ int16_t,
+ typename std::conditional<AcceptableType<int32_t>::value,
+ int32_t,
+ int64_t>::type>::type>::type;
+
+ using best_unsigned_type = typename std::conditional<
+ AcceptableType<uint8_t>::value,
+ uint8_t,
+ typename std::conditional<
+ AcceptableType<uint16_t>::value,
+ uint16_t,
+ typename std::conditional<AcceptableType<uint32_t>::value,
+ uint32_t,
+ uint64_t>::type>::type>::type;
+
+ public:
+ // Pick the best type, preferring the same signedness as T but falling back
+ // to the other one if necessary.
+ using type = typename std::conditional<
+ std::is_signed<T>::value,
+ typename std::conditional<AcceptableType<best_signed_type>::value,
+ best_signed_type,
+ best_unsigned_type>::type,
+ typename std::conditional<AcceptableType<best_unsigned_type>::value,
+ best_unsigned_type,
+ best_signed_type>::type>::type;
+ static_assert(AcceptableType<type>::value, "");
+};
+
+} // namespace safe_minmax_impl
+
+template <
+ typename R = safe_minmax_impl::DefaultType,
+ typename T = safe_minmax_impl::DefaultType,
+ typename L = safe_minmax_impl::DefaultType,
+ typename H = safe_minmax_impl::DefaultType,
+ typename R2 = typename safe_minmax_impl::TypeOr<
+ R,
+ typename safe_minmax_impl::ClampType<
+ typename safe_minmax_impl::UnderlyingType<T>::type,
+ typename safe_minmax_impl::UnderlyingType<L>::type,
+ typename safe_minmax_impl::UnderlyingType<H>::type>::type>::type>
+R2 SafeClamp(T x, L min, H max) {
+ static_assert(IsIntlike<H>::value || std::is_floating_point<H>::value,
+ "The first argument must be integral or floating-point");
+ static_assert(IsIntlike<T>::value || std::is_floating_point<T>::value,
+ "The second argument must be integral or floating-point");
+ static_assert(IsIntlike<L>::value || std::is_floating_point<L>::value,
+ "The third argument must be integral or floating-point");
+ RTC_DCHECK_LE(min, max);
+ return SafeLe(x, min)
+ ? static_cast<R2>(min)
+ : SafeGe(x, max) ? static_cast<R2>(max) : static_cast<R2>(x);
+}
+
+} // namespace rtc
+
+#endif // RTC_BASE_NUMERICS_SAFE_MINMAX_H_
diff --git a/webrtc/rtc_base/platform_thread.cc b/webrtc/rtc_base/platform_thread.cc
new file mode 100644
index 0000000..8a5f2c9
--- /dev/null
+++ b/webrtc/rtc_base/platform_thread.cc
@@ -0,0 +1,192 @@
+/*
+ * 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 "rtc_base/platform_thread.h"
+
+#if !defined(WEBRTC_WIN)
+#include <sched.h>
+#endif
+#include <stdint.h>
+#include <time.h>
+
+#include <algorithm>
+
+#include "rtc_base/checks.h"
+
+namespace rtc {
+namespace {
+#if !defined(WEBRTC_WIN)
+struct ThreadAttributes {
+ ThreadAttributes() { pthread_attr_init(&attr); }
+ ~ThreadAttributes() { pthread_attr_destroy(&attr); }
+ pthread_attr_t* operator&() { return &attr; }
+ pthread_attr_t attr;
+};
+#endif // defined(WEBRTC_WIN)
+} // namespace
+
+PlatformThread::PlatformThread(ThreadRunFunction func,
+ void* obj,
+ absl::string_view thread_name,
+ ThreadPriority priority /*= kNormalPriority*/)
+ : run_function_(func), priority_(priority), obj_(obj), name_(thread_name) {
+ RTC_DCHECK(func);
+ RTC_DCHECK(!name_.empty());
+ // TODO(tommi): Consider lowering the limit to 15 (limit on Linux).
+ RTC_DCHECK(name_.length() < 64);
+ spawned_thread_checker_.Detach();
+}
+
+PlatformThread::~PlatformThread() {
+ RTC_DCHECK(thread_checker_.IsCurrent());
+#if defined(WEBRTC_WIN)
+ RTC_DCHECK(!thread_);
+ RTC_DCHECK(!thread_id_);
+#endif // defined(WEBRTC_WIN)
+}
+
+#if defined(WEBRTC_WIN)
+DWORD WINAPI PlatformThread::StartThread(void* param) {
+ // The GetLastError() function only returns valid results when it is called
+ // after a Win32 API function that returns a "failed" result. A crash dump
+ // contains the result from GetLastError() and to make sure it does not
+ // falsely report a Windows error we call SetLastError here.
+ ::SetLastError(ERROR_SUCCESS);
+ static_cast<PlatformThread*>(param)->Run();
+ return 0;
+}
+#else
+void* PlatformThread::StartThread(void* param) {
+ static_cast<PlatformThread*>(param)->Run();
+ return 0;
+}
+#endif // defined(WEBRTC_WIN)
+
+void PlatformThread::Start() {
+ RTC_DCHECK(thread_checker_.IsCurrent());
+ RTC_DCHECK(!thread_) << "Thread already started?";
+#if defined(WEBRTC_WIN)
+ // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
+ // Set the reserved stack stack size to 1M, which is the default on Windows
+ // and Linux.
+ thread_ = ::CreateThread(nullptr, 1024 * 1024, &StartThread, this,
+ STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id_);
+ RTC_CHECK(thread_) << "CreateThread failed";
+ RTC_DCHECK(thread_id_);
+#else
+ ThreadAttributes attr;
+ // Set the stack stack size to 1M.
+ pthread_attr_setstacksize(&attr, 1024 * 1024);
+ RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this));
+#endif // defined(WEBRTC_WIN)
+}
+
+bool PlatformThread::IsRunning() const {
+ RTC_DCHECK(thread_checker_.IsCurrent());
+#if defined(WEBRTC_WIN)
+ return thread_ != nullptr;
+#else
+ return thread_ != 0;
+#endif // defined(WEBRTC_WIN)
+}
+
+PlatformThreadRef PlatformThread::GetThreadRef() const {
+#if defined(WEBRTC_WIN)
+ return thread_id_;
+#else
+ return thread_;
+#endif // defined(WEBRTC_WIN)
+}
+
+void PlatformThread::Stop() {
+ RTC_DCHECK(thread_checker_.IsCurrent());
+ if (!IsRunning())
+ return;
+
+#if defined(WEBRTC_WIN)
+ WaitForSingleObject(thread_, INFINITE);
+ CloseHandle(thread_);
+ thread_ = nullptr;
+ thread_id_ = 0;
+#else
+ RTC_CHECK_EQ(0, pthread_join(thread_, nullptr));
+ thread_ = 0;
+#endif // defined(WEBRTC_WIN)
+ spawned_thread_checker_.Detach();
+}
+
+void PlatformThread::Run() {
+ // Attach the worker thread checker to this thread.
+ RTC_DCHECK(spawned_thread_checker_.IsCurrent());
+ rtc::SetCurrentThreadName(name_.c_str());
+ SetPriority(priority_);
+ run_function_(obj_);
+}
+
+bool PlatformThread::SetPriority(ThreadPriority priority) {
+ RTC_DCHECK(spawned_thread_checker_.IsCurrent());
+
+#if defined(WEBRTC_WIN)
+ return SetThreadPriority(thread_, priority) != FALSE;
+#elif defined(__native_client__) || defined(WEBRTC_FUCHSIA)
+ // Setting thread priorities is not supported in NaCl or Fuchsia.
+ return true;
+#elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
+ // TODO(tommi): Switch to the same mechanism as Chromium uses for changing
+ // thread priorities.
+ return true;
+#else
+ const int policy = SCHED_FIFO;
+ const int min_prio = sched_get_priority_min(policy);
+ const int max_prio = sched_get_priority_max(policy);
+ if (min_prio == -1 || max_prio == -1) {
+ return false;
+ }
+
+ if (max_prio - min_prio <= 2)
+ return false;
+
+ // Convert webrtc priority to system priorities:
+ sched_param param;
+ const int top_prio = max_prio - 1;
+ const int low_prio = min_prio + 1;
+ switch (priority) {
+ case kLowPriority:
+ param.sched_priority = low_prio;
+ break;
+ case kNormalPriority:
+ // The -1 ensures that the kHighPriority is always greater or equal to
+ // kNormalPriority.
+ param.sched_priority = (low_prio + top_prio - 1) / 2;
+ break;
+ case kHighPriority:
+ param.sched_priority = std::max(top_prio - 2, low_prio);
+ break;
+ case kHighestPriority:
+ param.sched_priority = std::max(top_prio - 1, low_prio);
+ break;
+ case kRealtimePriority:
+ param.sched_priority = top_prio;
+ break;
+ }
+ return pthread_setschedparam(thread_, policy, &param) == 0;
+#endif // defined(WEBRTC_WIN)
+}
+
+#if defined(WEBRTC_WIN)
+bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) {
+ RTC_DCHECK(thread_checker_.IsCurrent());
+ RTC_DCHECK(IsRunning());
+
+ return QueueUserAPC(function, thread_, data) != FALSE;
+}
+#endif
+
+} // namespace rtc
diff --git a/webrtc/rtc_base/platform_thread.h b/webrtc/rtc_base/platform_thread.h
new file mode 100644
index 0000000..4968de9
--- /dev/null
+++ b/webrtc/rtc_base/platform_thread.h
@@ -0,0 +1,104 @@
+/*
+ * 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 RTC_BASE_PLATFORM_THREAD_H_
+#define RTC_BASE_PLATFORM_THREAD_H_
+
+#ifndef WEBRTC_WIN
+#include <pthread.h>
+#endif
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/platform_thread_types.h"
+#include "rtc_base/thread_checker.h"
+
+namespace rtc {
+
+// Callback function that the spawned thread will enter once spawned.
+typedef void (*ThreadRunFunction)(void*);
+
+enum ThreadPriority {
+#ifdef WEBRTC_WIN
+ kLowPriority = THREAD_PRIORITY_BELOW_NORMAL,
+ kNormalPriority = THREAD_PRIORITY_NORMAL,
+ kHighPriority = THREAD_PRIORITY_ABOVE_NORMAL,
+ kHighestPriority = THREAD_PRIORITY_HIGHEST,
+ kRealtimePriority = THREAD_PRIORITY_TIME_CRITICAL
+#else
+ kLowPriority = 1,
+ kNormalPriority = 2,
+ kHighPriority = 3,
+ kHighestPriority = 4,
+ kRealtimePriority = 5
+#endif
+};
+
+// Represents a simple worker thread. The implementation must be assumed
+// to be single threaded, meaning that all methods of the class, must be
+// called from the same thread, including instantiation.
+class PlatformThread {
+ public:
+ PlatformThread(ThreadRunFunction func,
+ void* obj,
+ absl::string_view thread_name,
+ ThreadPriority priority = kNormalPriority);
+ virtual ~PlatformThread();
+
+ const std::string& name() const { return name_; }
+
+ // Spawns a thread and tries to set thread priority according to the priority
+ // from when CreateThread was called.
+ void Start();
+
+ bool IsRunning() const;
+
+ // Returns an identifier for the worker thread that can be used to do
+ // thread checks.
+ PlatformThreadRef GetThreadRef() const;
+
+ // Stops (joins) the spawned thread.
+ void Stop();
+
+ protected:
+#if defined(WEBRTC_WIN)
+ // Exposed to derived classes to allow for special cases specific to Windows.
+ bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data);
+#endif
+
+ private:
+ void Run();
+ bool SetPriority(ThreadPriority priority);
+
+ ThreadRunFunction const run_function_ = nullptr;
+ const ThreadPriority priority_ = kNormalPriority;
+ void* const obj_;
+ // TODO(pbos): Make sure call sites use string literals and update to a const
+ // char* instead of a std::string.
+ const std::string name_;
+ rtc::ThreadChecker thread_checker_;
+ rtc::ThreadChecker spawned_thread_checker_;
+#if defined(WEBRTC_WIN)
+ static DWORD WINAPI StartThread(void* param);
+
+ HANDLE thread_ = nullptr;
+ DWORD thread_id_ = 0;
+#else
+ static void* StartThread(void* param);
+
+ pthread_t thread_ = 0;
+#endif // defined(WEBRTC_WIN)
+ RTC_DISALLOW_COPY_AND_ASSIGN(PlatformThread);
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_PLATFORM_THREAD_H_
diff --git a/webrtc/rtc_base/platform_thread_types.cc b/webrtc/rtc_base/platform_thread_types.cc
new file mode 100644
index 0000000..b0243b4
--- /dev/null
+++ b/webrtc/rtc_base/platform_thread_types.cc
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/platform_thread_types.h"
+
+#if defined(WEBRTC_LINUX)
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#endif
+
+#if defined(WEBRTC_WIN)
+#include "rtc_base/arraysize.h"
+
+// The SetThreadDescription API was brought in version 1607 of Windows 10.
+// For compatibility with various versions of winuser and avoid clashing with
+// a potentially defined type, we use the RTC_ prefix.
+typedef HRESULT(WINAPI* RTC_SetThreadDescription)(HANDLE hThread,
+ PCWSTR lpThreadDescription);
+#endif
+
+namespace rtc {
+
+PlatformThreadId CurrentThreadId() {
+#if defined(WEBRTC_WIN)
+ return GetCurrentThreadId();
+#elif defined(WEBRTC_POSIX)
+#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
+ return pthread_mach_thread_np(pthread_self());
+#elif defined(WEBRTC_ANDROID)
+ return gettid();
+#elif defined(WEBRTC_FUCHSIA)
+ return zx_thread_self();
+#elif defined(WEBRTC_LINUX)
+ return syscall(__NR_gettid);
+#elif defined(__EMSCRIPTEN__)
+ return static_cast<PlatformThreadId>(pthread_self());
+#else
+ // Default implementation for nacl and solaris.
+ return reinterpret_cast<PlatformThreadId>(pthread_self());
+#endif
+#endif // defined(WEBRTC_POSIX)
+}
+
+PlatformThreadRef CurrentThreadRef() {
+#if defined(WEBRTC_WIN)
+ return GetCurrentThreadId();
+#elif defined(WEBRTC_FUCHSIA)
+ return zx_thread_self();
+#elif defined(WEBRTC_POSIX)
+ return pthread_self();
+#endif
+}
+
+bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
+#if defined(WEBRTC_WIN) || defined(WEBRTC_FUCHSIA)
+ return a == b;
+#elif defined(WEBRTC_POSIX)
+ return pthread_equal(a, b);
+#endif
+}
+
+void SetCurrentThreadName(const char* name) {
+#if defined(WEBRTC_WIN)
+ // The SetThreadDescription API works even if no debugger is attached.
+ // The names set with this API also show up in ETW traces. Very handy.
+ static auto set_thread_description_func =
+ reinterpret_cast<RTC_SetThreadDescription>(::GetProcAddress(
+ ::GetModuleHandleA("Kernel32.dll"), "SetThreadDescription"));
+ if (set_thread_description_func) {
+ // Convert from ASCII to UTF-16.
+ wchar_t wide_thread_name[64];
+ for (size_t i = 0; i < arraysize(wide_thread_name) - 1; ++i) {
+ wide_thread_name[i] = name[i];
+ if (wide_thread_name[i] == L'\0')
+ break;
+ }
+ // Guarantee null-termination.
+ wide_thread_name[arraysize(wide_thread_name) - 1] = L'\0';
+ set_thread_description_func(::GetCurrentThread(), wide_thread_name);
+ }
+
+ // For details see:
+ // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
+#pragma pack(push, 8)
+ struct {
+ DWORD dwType;
+ LPCSTR szName;
+ DWORD dwThreadID;
+ DWORD dwFlags;
+ } threadname_info = {0x1000, name, static_cast<DWORD>(-1), 0};
+#pragma pack(pop)
+
+#pragma warning(push)
+#pragma warning(disable : 6320 6322)
+ __try {
+ ::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(ULONG_PTR),
+ reinterpret_cast<ULONG_PTR*>(&threadname_info));
+ } __except (EXCEPTION_EXECUTE_HANDLER) { // NOLINT
+ }
+#pragma warning(pop)
+#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
+ prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name)); // NOLINT
+#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
+ pthread_setname_np(name);
+#endif
+}
+
+} // namespace rtc
diff --git a/webrtc/base/platform_thread.h b/webrtc/rtc_base/platform_thread_types.h
index 50033b3..6b9101e 100644
--- a/webrtc/base/platform_thread.h
+++ b/webrtc/rtc_base/platform_thread_types.h
@@ -8,28 +8,47 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_BASE_PLATFORM_THREAD_H_
-#define WEBRTC_BASE_PLATFORM_THREAD_H_
+#ifndef RTC_BASE_PLATFORM_THREAD_TYPES_H_
+#define RTC_BASE_PLATFORM_THREAD_TYPES_H_
+// clang-format off
+// clang formating would change include order.
#if defined(WEBRTC_WIN)
+// Include winsock2.h before including <windows.h> to maintain consistency with
+// win32.h. To include win32.h directly, it must be broken out into its own
+// build target.
#include <winsock2.h>
#include <windows.h>
+#elif defined(WEBRTC_FUCHSIA)
+#include <zircon/types.h>
+#include <zircon/process.h>
#elif defined(WEBRTC_POSIX)
#include <pthread.h>
#include <unistd.h>
+#if defined(WEBRTC_MAC)
+#include <pthread_spis.h>
#endif
+#endif
+// clang-format on
namespace rtc {
-
#if defined(WEBRTC_WIN)
typedef DWORD PlatformThreadId;
typedef DWORD PlatformThreadRef;
+#elif defined(WEBRTC_FUCHSIA)
+typedef zx_handle_t PlatformThreadId;
+typedef zx_handle_t PlatformThreadRef;
#elif defined(WEBRTC_POSIX)
typedef pid_t PlatformThreadId;
typedef pthread_t PlatformThreadRef;
#endif
+// Retrieve the ID of the current thread.
PlatformThreadId CurrentThreadId();
+
+// Retrieves a reference to the current thread. On Windows, this is the same
+// as CurrentThreadId. On other platforms it's the pthread_t returned by
+// pthread_self().
PlatformThreadRef CurrentThreadRef();
// Compares two thread identifiers for equality.
@@ -40,4 +59,4 @@ void SetCurrentThreadName(const char* name);
} // namespace rtc
-#endif // WEBRTC_BASE_PLATFORM_THREAD_H_
+#endif // RTC_BASE_PLATFORM_THREAD_TYPES_H_
diff --git a/webrtc/rtc_base/race_checker.cc b/webrtc/rtc_base/race_checker.cc
new file mode 100644
index 0000000..bf9dfdc
--- /dev/null
+++ b/webrtc/rtc_base/race_checker.cc
@@ -0,0 +1,54 @@
+/*
+ * 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 "rtc_base/race_checker.h"
+
+namespace rtc {
+
+RaceChecker::RaceChecker() {}
+
+// Note that the implementation here is in itself racy, but we pretend it does
+// not matter because we want this useful in release builds without having to
+// pay the cost of using atomics. A race hitting the race checker is likely to
+// cause access_count_ to diverge from zero and therefore cause the ThreadRef
+// comparison to fail, signaling a race, although it may not be in the exact
+// spot where a race *first* appeared in the code we're trying to protect. There
+// is also a chance that an actual race is missed, however the probability of
+// that has been considered small enough to be an acceptable trade off.
+bool RaceChecker::Acquire() const {
+ const PlatformThreadRef current_thread = CurrentThreadRef();
+ // Set new accessing thread if this is a new use.
+ if (access_count_++ == 0)
+ accessing_thread_ = current_thread;
+ // If this is being used concurrently this check will fail for the second
+ // thread entering since it won't set the thread. Recursive use of checked
+ // methods are OK since the accessing thread remains the same.
+ const PlatformThreadRef accessing_thread = accessing_thread_;
+ return IsThreadRefEqual(accessing_thread, current_thread);
+}
+
+void RaceChecker::Release() const {
+ --access_count_;
+}
+
+namespace internal {
+RaceCheckerScope::RaceCheckerScope(const RaceChecker* race_checker)
+ : race_checker_(race_checker), race_check_ok_(race_checker->Acquire()) {}
+
+bool RaceCheckerScope::RaceDetected() const {
+ return !race_check_ok_;
+}
+
+RaceCheckerScope::~RaceCheckerScope() {
+ race_checker_->Release();
+}
+
+} // namespace internal
+} // namespace rtc
diff --git a/webrtc/rtc_base/race_checker.h b/webrtc/rtc_base/race_checker.h
new file mode 100644
index 0000000..4d57460
--- /dev/null
+++ b/webrtc/rtc_base/race_checker.h
@@ -0,0 +1,78 @@
+/*
+ * 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 RTC_BASE_RACE_CHECKER_H_
+#define RTC_BASE_RACE_CHECKER_H_
+
+#include "rtc_base/checks.h"
+#include "rtc_base/platform_thread_types.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace rtc {
+
+namespace internal {
+class RaceCheckerScope;
+} // namespace internal
+
+// Best-effort race-checking implementation. This primitive uses no
+// synchronization at all to be as-fast-as-possible in the non-racy case.
+class RTC_LOCKABLE RaceChecker {
+ public:
+ friend class internal::RaceCheckerScope;
+ RaceChecker();
+
+ private:
+ bool Acquire() const RTC_EXCLUSIVE_LOCK_FUNCTION();
+ void Release() const RTC_UNLOCK_FUNCTION();
+
+ // Volatile to prevent code being optimized away in Acquire()/Release().
+ mutable volatile int access_count_ = 0;
+ mutable volatile PlatformThreadRef accessing_thread_;
+};
+
+namespace internal {
+class RTC_SCOPED_LOCKABLE RaceCheckerScope {
+ public:
+ explicit RaceCheckerScope(const RaceChecker* race_checker)
+ RTC_EXCLUSIVE_LOCK_FUNCTION(race_checker);
+
+ bool RaceDetected() const;
+ ~RaceCheckerScope() RTC_UNLOCK_FUNCTION();
+
+ private:
+ const RaceChecker* const race_checker_;
+ const bool race_check_ok_;
+};
+
+class RTC_SCOPED_LOCKABLE RaceCheckerScopeDoNothing {
+ public:
+ explicit RaceCheckerScopeDoNothing(const RaceChecker* race_checker)
+ RTC_EXCLUSIVE_LOCK_FUNCTION(race_checker) {}
+
+ ~RaceCheckerScopeDoNothing() RTC_UNLOCK_FUNCTION() {}
+};
+
+} // namespace internal
+} // namespace rtc
+
+#define RTC_CHECK_RUNS_SERIALIZED(x) \
+ rtc::internal::RaceCheckerScope race_checker(x); \
+ RTC_CHECK(!race_checker.RaceDetected())
+
+#if RTC_DCHECK_IS_ON
+#define RTC_DCHECK_RUNS_SERIALIZED(x) \
+ rtc::internal::RaceCheckerScope race_checker(x); \
+ RTC_DCHECK(!race_checker.RaceDetected())
+#else
+#define RTC_DCHECK_RUNS_SERIALIZED(x) \
+ rtc::internal::RaceCheckerScopeDoNothing race_checker(x)
+#endif
+
+#endif // RTC_BASE_RACE_CHECKER_H_
diff --git a/webrtc/rtc_base/ref_count.h b/webrtc/rtc_base/ref_count.h
new file mode 100644
index 0000000..d8d652a
--- /dev/null
+++ b/webrtc/rtc_base/ref_count.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 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 RTC_BASE_REF_COUNT_H_
+#define RTC_BASE_REF_COUNT_H_
+
+namespace rtc {
+
+// Refcounted objects should implement the following informal interface:
+//
+// void AddRef() const ;
+// RefCountReleaseStatus Release() const;
+//
+// You may access members of a reference-counted object, including the AddRef()
+// and Release() methods, only if you already own a reference to it, or if
+// you're borrowing someone else's reference. (A newly created object is a
+// special case: the reference count is zero on construction, and the code that
+// creates the object should immediately call AddRef(), bringing the reference
+// count from zero to one, e.g., by constructing an rtc::scoped_refptr).
+//
+// AddRef() creates a new reference to the object.
+//
+// Release() releases a reference to the object; the caller now has one less
+// reference than before the call. Returns kDroppedLastRef if the number of
+// references dropped to zero because of this (in which case the object destroys
+// itself). Otherwise, returns kOtherRefsRemained, to signal that at the precise
+// time the caller's reference was dropped, other references still remained (but
+// if other threads own references, this may of course have changed by the time
+// Release() returns).
+//
+// The caller of Release() must treat it in the same way as a delete operation:
+// Regardless of the return value from Release(), the caller mustn't access the
+// object. The object might still be alive, due to references held by other
+// users of the object, but the object can go away at any time, e.g., as the
+// result of another thread calling Release().
+//
+// Calling AddRef() and Release() manually is discouraged. It's recommended to
+// use rtc::scoped_refptr to manage all pointers to reference counted objects.
+// Note that rtc::scoped_refptr depends on compile-time duck-typing; formally
+// implementing the below RefCountInterface is not required.
+
+enum class RefCountReleaseStatus { kDroppedLastRef, kOtherRefsRemained };
+
+// Interfaces where refcounting is part of the public api should
+// inherit this abstract interface. The implementation of these
+// methods is usually provided by the RefCountedObject template class,
+// applied as a leaf in the inheritance tree.
+class RefCountInterface {
+ public:
+ virtual void AddRef() const = 0;
+ virtual RefCountReleaseStatus Release() const = 0;
+
+ // Non-public destructor, because Release() has exclusive responsibility for
+ // destroying the object.
+ protected:
+ virtual ~RefCountInterface() {}
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_REF_COUNT_H_
diff --git a/webrtc/rtc_base/ref_counted_object.h b/webrtc/rtc_base/ref_counted_object.h
new file mode 100644
index 0000000..ce18379
--- /dev/null
+++ b/webrtc/rtc_base/ref_counted_object.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 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 RTC_BASE_REF_COUNTED_OBJECT_H_
+#define RTC_BASE_REF_COUNTED_OBJECT_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/ref_count.h"
+#include "rtc_base/ref_counter.h"
+
+namespace rtc {
+
+template <class T>
+class RefCountedObject : public T {
+ public:
+ RefCountedObject() {}
+
+ template <class P0>
+ explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {}
+
+ template <class P0, class P1, class... Args>
+ RefCountedObject(P0&& p0, P1&& p1, Args&&... args)
+ : T(std::forward<P0>(p0),
+ std::forward<P1>(p1),
+ std::forward<Args>(args)...) {}
+
+ virtual void AddRef() const { ref_count_.IncRef(); }
+
+ virtual RefCountReleaseStatus Release() const {
+ const auto status = ref_count_.DecRef();
+ if (status == RefCountReleaseStatus::kDroppedLastRef) {
+ delete this;
+ }
+ return status;
+ }
+
+ // Return whether the reference count is one. If the reference count is used
+ // in the conventional way, a reference count of 1 implies that the current
+ // thread owns the reference and no other thread shares it. This call
+ // performs the test for a reference count of one, and performs the memory
+ // barrier needed for the owning thread to act on the object, knowing that it
+ // has exclusive access to the object.
+ virtual bool HasOneRef() const { return ref_count_.HasOneRef(); }
+
+ protected:
+ virtual ~RefCountedObject() {}
+
+ mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject);
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_REF_COUNTED_OBJECT_H_
diff --git a/webrtc/rtc_base/ref_counter.h b/webrtc/rtc_base/ref_counter.h
new file mode 100644
index 0000000..6ffeda8
--- /dev/null
+++ b/webrtc/rtc_base/ref_counter.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 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 RTC_BASE_REF_COUNTER_H_
+#define RTC_BASE_REF_COUNTER_H_
+
+#include <atomic>
+
+#include "rtc_base/ref_count.h"
+
+namespace webrtc {
+namespace webrtc_impl {
+
+class RefCounter {
+ public:
+ explicit RefCounter(int ref_count) : ref_count_(ref_count) {}
+ RefCounter() = delete;
+
+ void IncRef() {
+ // Relaxed memory order: The current thread is allowed to act on the
+ // resource protected by the reference counter both before and after the
+ // atomic op, so this function doesn't prevent memory access reordering.
+ ref_count_.fetch_add(1, std::memory_order_relaxed);
+ }
+
+ // Returns kDroppedLastRef if this call dropped the last reference; the caller
+ // should therefore free the resource protected by the reference counter.
+ // Otherwise, returns kOtherRefsRemained (note that in case of multithreading,
+ // some other caller may have dropped the last reference by the time this call
+ // returns; all we know is that we didn't do it).
+ rtc::RefCountReleaseStatus DecRef() {
+ // Use release-acquire barrier to ensure all actions on the protected
+ // resource are finished before the resource can be freed.
+ // When ref_count_after_subtract > 0, this function require
+ // std::memory_order_release part of the barrier.
+ // When ref_count_after_subtract == 0, this function require
+ // std::memory_order_acquire part of the barrier.
+ // In addition std::memory_order_release is used for synchronization with
+ // the HasOneRef function to make sure all actions on the protected resource
+ // are finished before the resource is assumed to have exclusive access.
+ int ref_count_after_subtract =
+ ref_count_.fetch_sub(1, std::memory_order_acq_rel) - 1;
+ return ref_count_after_subtract == 0
+ ? rtc::RefCountReleaseStatus::kDroppedLastRef
+ : rtc::RefCountReleaseStatus::kOtherRefsRemained;
+ }
+
+ // Return whether the reference count is one. If the reference count is used
+ // in the conventional way, a reference count of 1 implies that the current
+ // thread owns the reference and no other thread shares it. This call performs
+ // the test for a reference count of one, and performs the memory barrier
+ // needed for the owning thread to act on the resource protected by the
+ // reference counter, knowing that it has exclusive access.
+ bool HasOneRef() const {
+ // To ensure resource protected by the reference counter has exclusive
+ // access, all changes to the resource before it was released by other
+ // threads must be visible by current thread. That is provided by release
+ // (in DecRef) and acquire (in this function) ordering.
+ return ref_count_.load(std::memory_order_acquire) == 1;
+ }
+
+ private:
+ std::atomic<int> ref_count_;
+};
+
+} // namespace webrtc_impl
+} // namespace webrtc
+
+#endif // RTC_BASE_REF_COUNTER_H_
diff --git a/webrtc/rtc_base/sanitizer.h b/webrtc/rtc_base/sanitizer.h
new file mode 100644
index 0000000..8af0824
--- /dev/null
+++ b/webrtc/rtc_base/sanitizer.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 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 RTC_BASE_SANITIZER_H_
+#define RTC_BASE_SANITIZER_H_
+
+#include <stddef.h> // For size_t.
+
+#ifdef __cplusplus
+#include "absl/meta/type_traits.h"
+#endif
+
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+#define RTC_HAS_ASAN 1
+#endif
+#if __has_feature(memory_sanitizer)
+#define RTC_HAS_MSAN 1
+#endif
+#endif
+#ifndef RTC_HAS_ASAN
+#define RTC_HAS_ASAN 0
+#endif
+#ifndef RTC_HAS_MSAN
+#define RTC_HAS_MSAN 0
+#endif
+
+#if RTC_HAS_ASAN
+#include <sanitizer/asan_interface.h>
+#endif
+#if RTC_HAS_MSAN
+#include <sanitizer/msan_interface.h>
+#endif
+
+#ifdef __has_attribute
+#if __has_attribute(no_sanitize)
+#define RTC_NO_SANITIZE(what) __attribute__((no_sanitize(what)))
+#endif
+#endif
+#ifndef RTC_NO_SANITIZE
+#define RTC_NO_SANITIZE(what)
+#endif
+
+// Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements)
+// as being unaddressable, so that reads and writes are not allowed. ASan may
+// narrow the range to the nearest alignment boundaries.
+static inline void rtc_AsanPoison(const volatile void* ptr,
+ size_t element_size,
+ size_t num_elements) {
+#if RTC_HAS_ASAN
+ ASAN_POISON_MEMORY_REGION(ptr, element_size * num_elements);
+#endif
+}
+
+// Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements)
+// as being addressable, so that reads and writes are allowed. ASan may widen
+// the range to the nearest alignment boundaries.
+static inline void rtc_AsanUnpoison(const volatile void* ptr,
+ size_t element_size,
+ size_t num_elements) {
+#if RTC_HAS_ASAN
+ ASAN_UNPOISON_MEMORY_REGION(ptr, element_size * num_elements);
+#endif
+}
+
+// Ask MSan to mark the memory range [ptr, ptr + element_size * num_elements)
+// as being uninitialized.
+static inline void rtc_MsanMarkUninitialized(const volatile void* ptr,
+ size_t element_size,
+ size_t num_elements) {
+#if RTC_HAS_MSAN
+ __msan_poison(ptr, element_size * num_elements);
+#endif
+}
+
+// Force an MSan check (if any bits in the memory range [ptr, ptr +
+// element_size * num_elements) are uninitialized the call will crash with an
+// MSan report).
+static inline void rtc_MsanCheckInitialized(const volatile void* ptr,
+ size_t element_size,
+ size_t num_elements) {
+#if RTC_HAS_MSAN
+ __msan_check_mem_is_initialized(ptr, element_size * num_elements);
+#endif
+}
+
+#ifdef __cplusplus
+
+namespace rtc {
+namespace sanitizer_impl {
+
+template <typename T>
+constexpr bool IsTriviallyCopyable() {
+ return static_cast<bool>(absl::is_trivially_copy_constructible<T>::value &&
+ (absl::is_trivially_copy_assignable<T>::value ||
+ !std::is_copy_assignable<T>::value) &&
+ absl::is_trivially_destructible<T>::value);
+}
+
+} // namespace sanitizer_impl
+
+template <typename T>
+inline void AsanPoison(const T& mem) {
+ rtc_AsanPoison(mem.data(), sizeof(mem.data()[0]), mem.size());
+}
+
+template <typename T>
+inline void AsanUnpoison(const T& mem) {
+ rtc_AsanUnpoison(mem.data(), sizeof(mem.data()[0]), mem.size());
+}
+
+template <typename T>
+inline void MsanMarkUninitialized(const T& mem) {
+ rtc_MsanMarkUninitialized(mem.data(), sizeof(mem.data()[0]), mem.size());
+}
+
+template <typename T>
+inline T MsanUninitialized(T t) {
+#if RTC_HAS_MSAN
+ // TODO(bugs.webrtc.org/8762): Switch to std::is_trivially_copyable when it
+ // becomes available in downstream projects.
+ static_assert(sanitizer_impl::IsTriviallyCopyable<T>(), "");
+#endif
+ rtc_MsanMarkUninitialized(&t, sizeof(T), 1);
+ return t;
+}
+
+template <typename T>
+inline void MsanCheckInitialized(const T& mem) {
+ rtc_MsanCheckInitialized(mem.data(), sizeof(mem.data()[0]), mem.size());
+}
+
+} // namespace rtc
+
+#endif // __cplusplus
+
+#endif // RTC_BASE_SANITIZER_H_
diff --git a/webrtc/rtc_base/string_encode.cc b/webrtc/rtc_base/string_encode.cc
new file mode 100644
index 0000000..1570b93
--- /dev/null
+++ b/webrtc/rtc_base/string_encode.cc
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/string_encode.h"
+
+#include <cstdio>
+
+#include "rtc_base/arraysize.h"
+#include "rtc_base/checks.h"
+
+namespace rtc {
+
+/////////////////////////////////////////////////////////////////////////////
+// String Encoding Utilities
+/////////////////////////////////////////////////////////////////////////////
+
+namespace {
+const char HEX[] = "0123456789abcdef";
+
+// Convert an unsigned value from 0 to 15 to the hex character equivalent...
+char hex_encode(unsigned char val) {
+ RTC_DCHECK_LT(val, 16);
+ return (val < 16) ? HEX[val] : '!';
+}
+
+// ...and vice-versa.
+bool hex_decode(char ch, unsigned char* val) {
+ if ((ch >= '0') && (ch <= '9')) {
+ *val = ch - '0';
+ } else if ((ch >= 'A') && (ch <= 'F')) {
+ *val = (ch - 'A') + 10;
+ } else if ((ch >= 'a') && (ch <= 'f')) {
+ *val = (ch - 'a') + 10;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+size_t hex_encode_output_length(size_t srclen, char delimiter) {
+ return delimiter && srclen > 0 ? (srclen * 3 - 1) : (srclen * 2);
+}
+
+// hex_encode shows the hex representation of binary data in ascii, with
+// |delimiter| between bytes, or none if |delimiter| == 0.
+void hex_encode_with_delimiter(char* buffer,
+ const char* csource,
+ size_t srclen,
+ char delimiter) {
+ RTC_DCHECK(buffer);
+
+ // Init and check bounds.
+ const unsigned char* bsource =
+ reinterpret_cast<const unsigned char*>(csource);
+ size_t srcpos = 0, bufpos = 0;
+
+ while (srcpos < srclen) {
+ unsigned char ch = bsource[srcpos++];
+ buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
+ buffer[bufpos + 1] = hex_encode((ch)&0xF);
+ bufpos += 2;
+
+ // Don't write a delimiter after the last byte.
+ if (delimiter && (srcpos < srclen)) {
+ buffer[bufpos] = delimiter;
+ ++bufpos;
+ }
+ }
+}
+
+} // namespace
+
+std::string hex_encode(const std::string& str) {
+ return hex_encode(str.c_str(), str.size());
+}
+
+std::string hex_encode(const char* source, size_t srclen) {
+ return hex_encode_with_delimiter(source, srclen, 0);
+}
+
+std::string hex_encode_with_delimiter(const char* source,
+ size_t srclen,
+ char delimiter) {
+ std::string s(hex_encode_output_length(srclen, delimiter), 0);
+ hex_encode_with_delimiter(&s[0], source, srclen, delimiter);
+ return s;
+}
+
+size_t hex_decode(char* cbuffer,
+ size_t buflen,
+ const char* source,
+ size_t srclen) {
+ return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
+}
+
+size_t hex_decode_with_delimiter(char* cbuffer,
+ size_t buflen,
+ const char* source,
+ size_t srclen,
+ char delimiter) {
+ RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size
+ if (buflen == 0)
+ return 0;
+
+ // Init and bounds check.
+ unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
+ size_t srcpos = 0, bufpos = 0;
+ size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
+ if (buflen < needed)
+ return 0;
+
+ while (srcpos < srclen) {
+ if ((srclen - srcpos) < 2) {
+ // This means we have an odd number of bytes.
+ return 0;
+ }
+
+ unsigned char h1, h2;
+ if (!hex_decode(source[srcpos], &h1) ||
+ !hex_decode(source[srcpos + 1], &h2))
+ return 0;
+
+ bbuffer[bufpos++] = (h1 << 4) | h2;
+ srcpos += 2;
+
+ // Remove the delimiter if needed.
+ if (delimiter && (srclen - srcpos) > 1) {
+ if (source[srcpos] != delimiter)
+ return 0;
+ ++srcpos;
+ }
+ }
+
+ return bufpos;
+}
+
+size_t hex_decode(char* buffer, size_t buflen, const std::string& source) {
+ return hex_decode_with_delimiter(buffer, buflen, source, 0);
+}
+size_t hex_decode_with_delimiter(char* buffer,
+ size_t buflen,
+ const std::string& source,
+ char delimiter) {
+ return hex_decode_with_delimiter(buffer, buflen, source.c_str(),
+ source.length(), delimiter);
+}
+
+size_t tokenize(const std::string& source,
+ char delimiter,
+ std::vector<std::string>* fields) {
+ fields->clear();
+ size_t last = 0;
+ for (size_t i = 0; i < source.length(); ++i) {
+ if (source[i] == delimiter) {
+ if (i != last) {
+ fields->push_back(source.substr(last, i - last));
+ }
+ last = i + 1;
+ }
+ }
+ if (last != source.length()) {
+ fields->push_back(source.substr(last, source.length() - last));
+ }
+ return fields->size();
+}
+
+size_t tokenize_with_empty_tokens(const std::string& source,
+ char delimiter,
+ std::vector<std::string>* fields) {
+ fields->clear();
+ size_t last = 0;
+ for (size_t i = 0; i < source.length(); ++i) {
+ if (source[i] == delimiter) {
+ fields->push_back(source.substr(last, i - last));
+ last = i + 1;
+ }
+ }
+ fields->push_back(source.substr(last, source.length() - last));
+ return fields->size();
+}
+
+size_t tokenize_append(const std::string& source,
+ char delimiter,
+ std::vector<std::string>* fields) {
+ if (!fields)
+ return 0;
+
+ std::vector<std::string> new_fields;
+ tokenize(source, delimiter, &new_fields);
+ fields->insert(fields->end(), new_fields.begin(), new_fields.end());
+ return fields->size();
+}
+
+size_t tokenize(const std::string& source,
+ char delimiter,
+ char start_mark,
+ char end_mark,
+ std::vector<std::string>* fields) {
+ if (!fields)
+ return 0;
+ fields->clear();
+
+ std::string remain_source = source;
+ while (!remain_source.empty()) {
+ size_t start_pos = remain_source.find(start_mark);
+ if (std::string::npos == start_pos)
+ break;
+ std::string pre_mark;
+ if (start_pos > 0) {
+ pre_mark = remain_source.substr(0, start_pos - 1);
+ }
+
+ ++start_pos;
+ size_t end_pos = remain_source.find(end_mark, start_pos);
+ if (std::string::npos == end_pos)
+ break;
+
+ // We have found the matching marks. First tokenize the pre-mask. Then add
+ // the marked part as a single field. Finally, loop back for the post-mark.
+ tokenize_append(pre_mark, delimiter, fields);
+ fields->push_back(remain_source.substr(start_pos, end_pos - start_pos));
+ remain_source = remain_source.substr(end_pos + 1);
+ }
+
+ return tokenize_append(remain_source, delimiter, fields);
+}
+
+bool tokenize_first(const std::string& source,
+ const char delimiter,
+ std::string* token,
+ std::string* rest) {
+ // Find the first delimiter
+ size_t left_pos = source.find(delimiter);
+ if (left_pos == std::string::npos) {
+ return false;
+ }
+
+ // Look for additional occurrances of delimiter.
+ size_t right_pos = left_pos + 1;
+ while (source[right_pos] == delimiter) {
+ right_pos++;
+ }
+
+ *token = source.substr(0, left_pos);
+ *rest = source.substr(right_pos);
+ return true;
+}
+
+std::string join(const std::vector<std::string>& source, char delimiter) {
+ if (source.size() == 0) {
+ return std::string();
+ }
+ // Find length of the string to be returned to pre-allocate memory.
+ size_t source_string_length = 0;
+ for (size_t i = 0; i < source.size(); ++i) {
+ source_string_length += source[i].length();
+ }
+
+ // Build the joined string.
+ std::string joined_string;
+ joined_string.reserve(source_string_length + source.size() - 1);
+ for (size_t i = 0; i < source.size(); ++i) {
+ if (i != 0) {
+ joined_string += delimiter;
+ }
+ joined_string += source[i];
+ }
+ return joined_string;
+}
+
+size_t split(const std::string& source,
+ char delimiter,
+ std::vector<std::string>* fields) {
+ RTC_DCHECK(fields);
+ fields->clear();
+ size_t last = 0;
+ for (size_t i = 0; i < source.length(); ++i) {
+ if (source[i] == delimiter) {
+ fields->push_back(source.substr(last, i - last));
+ last = i + 1;
+ }
+ }
+ fields->push_back(source.substr(last, source.length() - last));
+ return fields->size();
+}
+
+std::string ToString(const bool b) {
+ return b ? "true" : "false";
+}
+
+std::string ToString(const char* const s) {
+ return std::string(s);
+}
+std::string ToString(const std::string s) {
+ return s;
+}
+
+std::string ToString(const short s) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+std::string ToString(const unsigned short s) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+std::string ToString(const int s) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+std::string ToString(const unsigned int s) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+std::string ToString(const long int s) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+std::string ToString(const unsigned long int s) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+std::string ToString(const long long int s) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+std::string ToString(const unsigned long long int s) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+
+std::string ToString(const double d) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+
+std::string ToString(const long double d) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+
+std::string ToString(const void* const p) {
+ char buf[32];
+ const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p);
+ RTC_DCHECK_LE(len, arraysize(buf));
+ return std::string(&buf[0], len);
+}
+
+bool FromString(const std::string& s, bool* b) {
+ if (s == "false") {
+ *b = false;
+ return true;
+ }
+ if (s == "true") {
+ *b = true;
+ return true;
+ }
+ return false;
+}
+
+} // namespace rtc
diff --git a/webrtc/rtc_base/string_encode.h b/webrtc/rtc_base/string_encode.h
new file mode 100644
index 0000000..c1401b9
--- /dev/null
+++ b/webrtc/rtc_base/string_encode.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_STRING_ENCODE_H_
+#define RTC_BASE_STRING_ENCODE_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/string_to_number.h"
+
+namespace rtc {
+
+//////////////////////////////////////////////////////////////////////
+// String Encoding Utilities
+//////////////////////////////////////////////////////////////////////
+
+std::string hex_encode(const std::string& str);
+std::string hex_encode(const char* source, size_t srclen);
+std::string hex_encode_with_delimiter(const char* source,
+ size_t srclen,
+ char delimiter);
+
+// hex_decode converts ascii hex to binary.
+size_t hex_decode(char* buffer,
+ size_t buflen,
+ const char* source,
+ size_t srclen);
+
+// hex_decode, assuming that there is a delimiter between every byte
+// pair.
+// |delimiter| == 0 means no delimiter
+// If the buffer is too short or the data is invalid, we return 0.
+size_t hex_decode_with_delimiter(char* buffer,
+ size_t buflen,
+ const char* source,
+ size_t srclen,
+ char delimiter);
+
+// Helper functions for hex_decode.
+size_t hex_decode(char* buffer, size_t buflen, const std::string& source);
+size_t hex_decode_with_delimiter(char* buffer,
+ size_t buflen,
+ const std::string& source,
+ char delimiter);
+
+// Joins the source vector of strings into a single string, with each
+// field in source being separated by delimiter. No trailing delimiter is added.
+std::string join(const std::vector<std::string>& source, char delimiter);
+
+// Splits the source string into multiple fields separated by delimiter,
+// with duplicates of delimiter creating empty fields.
+size_t split(const std::string& source,
+ char delimiter,
+ std::vector<std::string>* fields);
+
+// Splits the source string into multiple fields separated by delimiter,
+// with duplicates of delimiter ignored. Trailing delimiter ignored.
+size_t tokenize(const std::string& source,
+ char delimiter,
+ std::vector<std::string>* fields);
+
+// Tokenize, including the empty tokens.
+size_t tokenize_with_empty_tokens(const std::string& source,
+ char delimiter,
+ std::vector<std::string>* fields);
+
+// Tokenize and append the tokens to fields. Return the new size of fields.
+size_t tokenize_append(const std::string& source,
+ char delimiter,
+ std::vector<std::string>* fields);
+
+// Splits the source string into multiple fields separated by delimiter, with
+// duplicates of delimiter ignored. Trailing delimiter ignored. A substring in
+// between the start_mark and the end_mark is treated as a single field. Return
+// the size of fields. For example, if source is "filename
+// \"/Library/Application Support/media content.txt\"", delimiter is ' ', and
+// the start_mark and end_mark are '"', this method returns two fields:
+// "filename" and "/Library/Application Support/media content.txt".
+size_t tokenize(const std::string& source,
+ char delimiter,
+ char start_mark,
+ char end_mark,
+ std::vector<std::string>* fields);
+
+// Extract the first token from source as separated by delimiter, with
+// duplicates of delimiter ignored. Return false if the delimiter could not be
+// found, otherwise return true.
+bool tokenize_first(const std::string& source,
+ const char delimiter,
+ std::string* token,
+ std::string* rest);
+
+// Convert arbitrary values to/from a string.
+// TODO(jonasolsson): Remove these when absl::StrCat becomes available.
+std::string ToString(bool b);
+
+std::string ToString(const char* s);
+std::string ToString(std::string t);
+
+std::string ToString(short s);
+std::string ToString(unsigned short s);
+std::string ToString(int s);
+std::string ToString(unsigned int s);
+std::string ToString(long int s);
+std::string ToString(unsigned long int s);
+std::string ToString(long long int s);
+std::string ToString(unsigned long long int s);
+
+std::string ToString(double t);
+std::string ToString(long double t);
+
+std::string ToString(const void* p);
+
+template <typename T,
+ typename std::enable_if<std::is_arithmetic<T>::value &&
+ !std::is_same<T, bool>::value,
+ int>::type = 0>
+static bool FromString(const std::string& s, T* t) {
+ RTC_DCHECK(t);
+ absl::optional<T> result = StringToNumber<T>(s);
+
+ if (result)
+ *t = *result;
+
+ return result.has_value();
+}
+
+bool FromString(const std::string& s, bool* b);
+
+template <typename T>
+static inline T FromString(const std::string& str) {
+ T val;
+ FromString(str, &val);
+ return val;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+} // namespace rtc
+
+#endif // RTC_BASE_STRING_ENCODE_H__
diff --git a/webrtc/rtc_base/string_to_number.cc b/webrtc/rtc_base/string_to_number.cc
new file mode 100644
index 0000000..351610f
--- /dev/null
+++ b/webrtc/rtc_base/string_to_number.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright 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 "rtc_base/string_to_number.h"
+
+#include <ctype.h>
+
+#include <cerrno>
+#include <cstdlib>
+
+#include "rtc_base/checks.h"
+
+namespace rtc {
+namespace string_to_number_internal {
+
+absl::optional<signed_type> ParseSigned(const char* str, int base) {
+ RTC_DCHECK(str);
+ if (isdigit(str[0]) || str[0] == '-') {
+ char* end = nullptr;
+ errno = 0;
+ const signed_type value = std::strtoll(str, &end, base);
+ if (end && *end == '\0' && errno == 0) {
+ return value;
+ }
+ }
+ return absl::nullopt;
+}
+
+absl::optional<unsigned_type> ParseUnsigned(const char* str, int base) {
+ RTC_DCHECK(str);
+ if (isdigit(str[0]) || str[0] == '-') {
+ // Explicitly discard negative values. std::strtoull parsing causes unsigned
+ // wraparound. We cannot just reject values that start with -, though, since
+ // -0 is perfectly fine, as is -0000000000000000000000000000000.
+ const bool is_negative = str[0] == '-';
+ char* end = nullptr;
+ errno = 0;
+ const unsigned_type value = std::strtoull(str, &end, base);
+ if (end && *end == '\0' && errno == 0 && (value == 0 || !is_negative)) {
+ return value;
+ }
+ }
+ return absl::nullopt;
+}
+
+template <typename T>
+T StrToT(const char* str, char** str_end);
+
+template <>
+inline float StrToT(const char* str, char** str_end) {
+ return std::strtof(str, str_end);
+}
+
+template <>
+inline double StrToT(const char* str, char** str_end) {
+ return std::strtod(str, str_end);
+}
+
+template <>
+inline long double StrToT(const char* str, char** str_end) {
+ return std::strtold(str, str_end);
+}
+
+template <typename T>
+absl::optional<T> ParseFloatingPoint(const char* str) {
+ RTC_DCHECK(str);
+ if (*str == '\0')
+ return absl::nullopt;
+ char* end = nullptr;
+ errno = 0;
+ const T value = StrToT<T>(str, &end);
+ if (end && *end == '\0' && errno == 0) {
+ return value;
+ }
+ return absl::nullopt;
+}
+
+template absl::optional<float> ParseFloatingPoint(const char* str);
+template absl::optional<double> ParseFloatingPoint(const char* str);
+template absl::optional<long double> ParseFloatingPoint(const char* str);
+
+} // namespace string_to_number_internal
+} // namespace rtc
diff --git a/webrtc/rtc_base/string_to_number.h b/webrtc/rtc_base/string_to_number.h
new file mode 100644
index 0000000..4cb5215
--- /dev/null
+++ b/webrtc/rtc_base/string_to_number.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 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 RTC_BASE_STRING_TO_NUMBER_H_
+#define RTC_BASE_STRING_TO_NUMBER_H_
+
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "absl/types/optional.h"
+
+namespace rtc {
+
+// This file declares a family of functions to parse integers from strings.
+// The standard C library functions either fail to indicate errors (atoi, etc.)
+// or are a hassle to work with (strtol, sscanf, etc.). The standard C++ library
+// functions (std::stoi, etc.) indicate errors by throwing exceptions, which
+// are disabled in WebRTC.
+//
+// Integers are parsed using one of the following functions:
+// absl::optional<int-type> StringToNumber(const char* str, int base = 10);
+// absl::optional<int-type> StringToNumber(const std::string& str,
+// int base = 10);
+//
+// These functions parse a value from the beginning of a string into one of the
+// fundamental integer types, or returns an empty Optional if parsing
+// failed. Values outside of the range supported by the type will be
+// rejected. The strings must begin with a digit or a minus sign. No leading
+// space nor trailing contents are allowed.
+// By setting base to 0, one of octal, decimal or hexadecimal will be
+// detected from the string's prefix (0, nothing or 0x, respectively).
+// If non-zero, base can be set to a value between 2 and 36 inclusively.
+//
+// If desired, this interface could be extended with support for floating-point
+// types.
+
+namespace string_to_number_internal {
+// These must be (unsigned) long long, to match the signature of strto(u)ll.
+using unsigned_type = unsigned long long; // NOLINT(runtime/int)
+using signed_type = long long; // NOLINT(runtime/int)
+
+absl::optional<signed_type> ParseSigned(const char* str, int base);
+absl::optional<unsigned_type> ParseUnsigned(const char* str, int base);
+
+template <typename T>
+absl::optional<T> ParseFloatingPoint(const char* str);
+} // namespace string_to_number_internal
+
+template <typename T>
+typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value,
+ absl::optional<T>>::type
+StringToNumber(const char* str, int base = 10) {
+ using string_to_number_internal::signed_type;
+ static_assert(
+ std::numeric_limits<T>::max() <=
+ std::numeric_limits<signed_type>::max() &&
+ std::numeric_limits<T>::lowest() >=
+ std::numeric_limits<signed_type>::lowest(),
+ "StringToNumber only supports signed integers as large as long long int");
+ absl::optional<signed_type> value =
+ string_to_number_internal::ParseSigned(str, base);
+ if (value && *value >= std::numeric_limits<T>::lowest() &&
+ *value <= std::numeric_limits<T>::max()) {
+ return static_cast<T>(*value);
+ }
+ return absl::nullopt;
+}
+
+template <typename T>
+typename std::enable_if<std::is_integral<T>::value &&
+ std::is_unsigned<T>::value,
+ absl::optional<T>>::type
+StringToNumber(const char* str, int base = 10) {
+ using string_to_number_internal::unsigned_type;
+ static_assert(std::numeric_limits<T>::max() <=
+ std::numeric_limits<unsigned_type>::max(),
+ "StringToNumber only supports unsigned integers as large as "
+ "unsigned long long int");
+ absl::optional<unsigned_type> value =
+ string_to_number_internal::ParseUnsigned(str, base);
+ if (value && *value <= std::numeric_limits<T>::max()) {
+ return static_cast<T>(*value);
+ }
+ return absl::nullopt;
+}
+
+template <typename T>
+typename std::enable_if<std::is_floating_point<T>::value,
+ absl::optional<T>>::type
+StringToNumber(const char* str, int base = 10) {
+ static_assert(
+ std::numeric_limits<T>::max() <= std::numeric_limits<long double>::max(),
+ "StringToNumber only supports floating-point numbers as large "
+ "as long double");
+ return string_to_number_internal::ParseFloatingPoint<T>(str);
+}
+
+// The std::string overloads only exists if there is a matching const char*
+// version.
+template <typename T>
+auto StringToNumber(const std::string& str, int base = 10)
+ -> decltype(StringToNumber<T>(str.c_str(), base)) {
+ return StringToNumber<T>(str.c_str(), base);
+}
+
+} // namespace rtc
+
+#endif // RTC_BASE_STRING_TO_NUMBER_H_
diff --git a/webrtc/rtc_base/string_utils.cc b/webrtc/rtc_base/string_utils.cc
new file mode 100644
index 0000000..1720c62
--- /dev/null
+++ b/webrtc/rtc_base/string_utils.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/string_utils.h"
+
+namespace rtc {
+
+size_t strcpyn(char* buffer,
+ size_t buflen,
+ const char* source,
+ size_t srclen /* = SIZE_UNKNOWN */) {
+ if (buflen <= 0)
+ return 0;
+
+ if (srclen == SIZE_UNKNOWN) {
+ srclen = strlen(source);
+ }
+ if (srclen >= buflen) {
+ srclen = buflen - 1;
+ }
+ memcpy(buffer, source, srclen);
+ buffer[srclen] = 0;
+ return srclen;
+}
+
+static const char kWhitespace[] = " \n\r\t";
+
+std::string string_trim(const std::string& s) {
+ std::string::size_type first = s.find_first_not_of(kWhitespace);
+ std::string::size_type last = s.find_last_not_of(kWhitespace);
+
+ if (first == std::string::npos || last == std::string::npos) {
+ return std::string("");
+ }
+
+ return s.substr(first, last - first + 1);
+}
+
+std::string ToHex(const int i) {
+ char buffer[50];
+ snprintf(buffer, sizeof(buffer), "%x", i);
+
+ return std::string(buffer);
+}
+
+} // namespace rtc
diff --git a/webrtc/rtc_base/string_utils.h b/webrtc/rtc_base/string_utils.h
new file mode 100644
index 0000000..23c55cb
--- /dev/null
+++ b/webrtc/rtc_base/string_utils.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_STRING_UTILS_H_
+#define RTC_BASE_STRING_UTILS_H_
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(WEBRTC_WIN)
+#include <malloc.h>
+#include <wchar.h>
+#include <windows.h>
+
+#endif // WEBRTC_WIN
+
+#if defined(WEBRTC_POSIX)
+#include <stdlib.h>
+#include <strings.h>
+#endif // WEBRTC_POSIX
+
+#include <string>
+
+namespace rtc {
+
+const size_t SIZE_UNKNOWN = static_cast<size_t>(-1);
+
+// Safe version of strncpy that always nul-terminate.
+size_t strcpyn(char* buffer,
+ size_t buflen,
+ const char* source,
+ size_t srclen = SIZE_UNKNOWN);
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF helpers (Windows only)
+///////////////////////////////////////////////////////////////////////////////
+
+#if defined(WEBRTC_WIN)
+
+inline std::wstring ToUtf16(const char* utf8, size_t len) {
+ if (len == 0)
+ return std::wstring();
+ int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len),
+ nullptr, 0);
+ std::wstring ws(len16, 0);
+ ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len), &*ws.begin(),
+ len16);
+ return ws;
+}
+
+inline std::wstring ToUtf16(const std::string& str) {
+ return ToUtf16(str.data(), str.length());
+}
+
+inline std::string ToUtf8(const wchar_t* wide, size_t len) {
+ if (len == 0)
+ return std::string();
+ int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len),
+ nullptr, 0, nullptr, nullptr);
+ std::string ns(len8, 0);
+ ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len), &*ns.begin(),
+ len8, nullptr, nullptr);
+ return ns;
+}
+
+inline std::string ToUtf8(const wchar_t* wide) {
+ return ToUtf8(wide, wcslen(wide));
+}
+
+inline std::string ToUtf8(const std::wstring& wstr) {
+ return ToUtf8(wstr.data(), wstr.length());
+}
+
+#endif // WEBRTC_WIN
+
+// Remove leading and trailing whitespaces.
+std::string string_trim(const std::string& s);
+
+// TODO(jonasolsson): replace with absl::Hex when that becomes available.
+std::string ToHex(const int i);
+
+} // namespace rtc
+
+#endif // RTC_BASE_STRING_UTILS_H_
diff --git a/webrtc/rtc_base/strings/string_builder.cc b/webrtc/rtc_base/strings/string_builder.cc
new file mode 100644
index 0000000..caa931b
--- /dev/null
+++ b/webrtc/rtc_base/strings/string_builder.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/strings/string_builder.h"
+
+#include <stdarg.h>
+
+#include <cstdio>
+#include <cstring>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace rtc {
+
+SimpleStringBuilder::SimpleStringBuilder(rtc::ArrayView<char> buffer)
+ : buffer_(buffer) {
+ buffer_[0] = '\0';
+ RTC_DCHECK(IsConsistent());
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(const char* str) {
+ return Append(str, strlen(str));
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(char ch) {
+ return Append(&ch, 1);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(const std::string& str) {
+ return Append(str.c_str(), str.length());
+}
+
+// Numeric conversion routines.
+//
+// We use std::[v]snprintf instead of std::to_string because:
+// * std::to_string relies on the current locale for formatting purposes,
+// and therefore concurrent calls to std::to_string from multiple threads
+// may result in partial serialization of calls
+// * snprintf allows us to print the number directly into our buffer.
+// * avoid allocating a std::string (potential heap alloc).
+// TODO(tommi): Switch to std::to_chars in C++17.
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(int i) {
+ return AppendFormat("%d", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(unsigned i) {
+ return AppendFormat("%u", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(long i) { // NOLINT
+ return AppendFormat("%ld", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(long long i) { // NOLINT
+ return AppendFormat("%lld", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(
+ unsigned long i) { // NOLINT
+ return AppendFormat("%lu", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(
+ unsigned long long i) { // NOLINT
+ return AppendFormat("%llu", i);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(float f) {
+ return AppendFormat("%g", f);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(double f) {
+ return AppendFormat("%g", f);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::operator<<(long double f) {
+ return AppendFormat("%Lg", f);
+}
+
+SimpleStringBuilder& SimpleStringBuilder::AppendFormat(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ const int len =
+ std::vsnprintf(&buffer_[size_], buffer_.size() - size_, fmt, args);
+ if (len >= 0) {
+ const size_t chars_added = rtc::SafeMin(len, buffer_.size() - 1 - size_);
+ size_ += chars_added;
+ RTC_DCHECK_EQ(len, chars_added) << "Buffer size was insufficient";
+ } else {
+ // This should never happen, but we're paranoid, so re-write the
+ // terminator in case vsnprintf() overwrote it.
+ RTC_NOTREACHED();
+ buffer_[size_] = '\0';
+ }
+ va_end(args);
+ RTC_DCHECK(IsConsistent());
+ return *this;
+}
+
+SimpleStringBuilder& SimpleStringBuilder::Append(const char* str,
+ size_t length) {
+ RTC_DCHECK_LT(size_ + length, buffer_.size())
+ << "Buffer size was insufficient";
+ const size_t chars_added = rtc::SafeMin(length, buffer_.size() - size_ - 1);
+ memcpy(&buffer_[size_], str, chars_added);
+ size_ += chars_added;
+ buffer_[size_] = '\0';
+ RTC_DCHECK(IsConsistent());
+ return *this;
+}
+
+StringBuilder& StringBuilder::AppendFormat(const char* fmt, ...) {
+ va_list args, copy;
+ va_start(args, fmt);
+ va_copy(copy, args);
+ const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
+ va_end(copy);
+
+ RTC_DCHECK_GE(predicted_length, 0);
+ if (predicted_length > 0) {
+ const size_t size = str_.size();
+ str_.resize(size + predicted_length);
+ // Pass "+ 1" to vsnprintf to include space for the '\0'.
+ const int actual_length =
+ std::vsnprintf(&str_[size], predicted_length + 1, fmt, args);
+ RTC_DCHECK_GE(actual_length, 0);
+ }
+ va_end(args);
+ return *this;
+}
+
+} // namespace rtc
diff --git a/webrtc/rtc_base/strings/string_builder.h b/webrtc/rtc_base/strings/string_builder.h
new file mode 100644
index 0000000..e528cf2
--- /dev/null
+++ b/webrtc/rtc_base/strings/string_builder.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_STRINGS_STRING_BUILDER_H_
+#define RTC_BASE_STRINGS_STRING_BUILDER_H_
+
+#include <cstdio>
+#include <string>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "rtc_base/string_encode.h"
+
+namespace rtc {
+
+// This is a minimalistic string builder class meant to cover the most cases of
+// when you might otherwise be tempted to use a stringstream (discouraged for
+// anything except logging). It uses a fixed-size buffer provided by the caller
+// and concatenates strings and numbers into it, allowing the results to be
+// read via |str()|.
+class SimpleStringBuilder {
+ public:
+ explicit SimpleStringBuilder(rtc::ArrayView<char> buffer);
+ SimpleStringBuilder(const SimpleStringBuilder&) = delete;
+ SimpleStringBuilder& operator=(const SimpleStringBuilder&) = delete;
+
+ SimpleStringBuilder& operator<<(const char* str);
+ SimpleStringBuilder& operator<<(char ch);
+ SimpleStringBuilder& operator<<(const std::string& str);
+ SimpleStringBuilder& operator<<(int i);
+ SimpleStringBuilder& operator<<(unsigned i);
+ SimpleStringBuilder& operator<<(long i); // NOLINT
+ SimpleStringBuilder& operator<<(long long i); // NOLINT
+ SimpleStringBuilder& operator<<(unsigned long i); // NOLINT
+ SimpleStringBuilder& operator<<(unsigned long long i); // NOLINT
+ SimpleStringBuilder& operator<<(float f);
+ SimpleStringBuilder& operator<<(double f);
+ SimpleStringBuilder& operator<<(long double f);
+
+ // Returns a pointer to the built string. The name |str()| is borrowed for
+ // compatibility reasons as we replace usage of stringstream throughout the
+ // code base.
+ const char* str() const { return buffer_.data(); }
+
+ // Returns the length of the string. The name |size()| is picked for STL
+ // compatibility reasons.
+ size_t size() const { return size_; }
+
+// Allows appending a printf style formatted string.
+#if defined(__GNUC__)
+ __attribute__((__format__(__printf__, 2, 3)))
+#endif
+ SimpleStringBuilder&
+ AppendFormat(const char* fmt, ...);
+
+ // An alternate way from operator<<() to append a string. This variant is
+ // slightly more efficient when the length of the string to append, is known.
+ SimpleStringBuilder& Append(const char* str, size_t length);
+
+ private:
+ bool IsConsistent() const {
+ return size_ <= buffer_.size() - 1 && buffer_[size_] == '\0';
+ }
+
+ // An always-zero-terminated fixed-size buffer that we write to. The fixed
+ // size allows the buffer to be stack allocated, which helps performance.
+ // Having a fixed size is furthermore useful to avoid unnecessary resizing
+ // while building it.
+ const rtc::ArrayView<char> buffer_;
+
+ // Represents the number of characters written to the buffer.
+ // This does not include the terminating '\0'.
+ size_t size_ = 0;
+};
+
+// A string builder that supports dynamic resizing while building a string.
+// The class is based around an instance of std::string and allows moving
+// ownership out of the class once the string has been built.
+// Note that this class uses the heap for allocations, so SimpleStringBuilder
+// might be more efficient for some use cases.
+class StringBuilder {
+ public:
+ StringBuilder() {}
+ explicit StringBuilder(absl::string_view s) : str_(s) {}
+
+ // TODO(tommi): Support construction from StringBuilder?
+ StringBuilder(const StringBuilder&) = delete;
+ StringBuilder& operator=(const StringBuilder&) = delete;
+
+ StringBuilder& operator<<(const absl::string_view str) {
+ str_.append(str.data(), str.length());
+ return *this;
+ }
+
+ StringBuilder& operator<<(char c) = delete;
+
+ StringBuilder& operator<<(int i) {
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(unsigned i) {
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(long i) { // NOLINT
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(long long i) { // NOLINT
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(unsigned long i) { // NOLINT
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(unsigned long long i) { // NOLINT
+ str_ += rtc::ToString(i);
+ return *this;
+ }
+
+ StringBuilder& operator<<(float f) {
+ str_ += rtc::ToString(f);
+ return *this;
+ }
+
+ StringBuilder& operator<<(double f) {
+ str_ += rtc::ToString(f);
+ return *this;
+ }
+
+ StringBuilder& operator<<(long double f) {
+ str_ += rtc::ToString(f);
+ return *this;
+ }
+
+ const std::string& str() const { return str_; }
+
+ void Clear() { str_.clear(); }
+
+ size_t size() const { return str_.size(); }
+
+ std::string Release() {
+ std::string ret = std::move(str_);
+ str_.clear();
+ return ret;
+ }
+
+ // Allows appending a printf style formatted string.
+ StringBuilder& AppendFormat(const char* fmt, ...)
+#if defined(__GNUC__)
+ __attribute__((__format__(__printf__, 2, 3)))
+#endif
+ ;
+
+ private:
+ std::string str_;
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_STRINGS_STRING_BUILDER_H_
diff --git a/webrtc/rtc_base/swap_queue.h b/webrtc/rtc_base/swap_queue.h
new file mode 100644
index 0000000..9eac49a
--- /dev/null
+++ b/webrtc/rtc_base/swap_queue.h
@@ -0,0 +1,249 @@
+/*
+ * 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 RTC_BASE_SWAP_QUEUE_H_
+#define RTC_BASE_SWAP_QUEUE_H_
+
+#include <stddef.h>
+
+#include <atomic>
+#include <utility>
+#include <vector>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/system/unused.h"
+
+namespace webrtc {
+
+namespace internal {
+
+// (Internal; please don't use outside this file.)
+template <typename T>
+bool NoopSwapQueueItemVerifierFunction(const T&) {
+ return true;
+}
+
+} // namespace internal
+
+// Functor to use when supplying a verifier function for the queue.
+template <typename T,
+ bool (*QueueItemVerifierFunction)(const T&) =
+ internal::NoopSwapQueueItemVerifierFunction>
+class SwapQueueItemVerifier {
+ public:
+ bool operator()(const T& t) const { return QueueItemVerifierFunction(t); }
+};
+
+// This class is a fixed-size queue. A single producer calls Insert() to insert
+// an element of type T at the back of the queue, and a single consumer calls
+// Remove() to remove an element from the front of the queue. It's safe for the
+// producer and the consumer to access the queue concurrently, from different
+// threads.
+//
+// To avoid the construction, copying, and destruction of Ts that a naive
+// queue implementation would require, for each "full" T passed from
+// producer to consumer, SwapQueue<T> passes an "empty" T in the other
+// direction (an "empty" T is one that contains nothing of value for the
+// consumer). This bidirectional movement is implemented with swap().
+//
+// // Create queue:
+// Bottle proto(568); // Prepare an empty Bottle. Heap allocates space for
+// // 568 ml.
+// SwapQueue<Bottle> q(N, proto); // Init queue with N copies of proto.
+// // Each copy allocates on the heap.
+// // Producer pseudo-code:
+// Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml.
+// loop {
+// b.Fill(amount); // Where amount <= 568 ml.
+// q.Insert(&b); // Swap our full Bottle for an empty one from q.
+// }
+//
+// // Consumer pseudo-code:
+// Bottle b(568); // Prepare an empty Bottle. Heap allocates space for 568 ml.
+// loop {
+// q.Remove(&b); // Swap our empty Bottle for the next-in-line full Bottle.
+// Drink(&b);
+// }
+//
+// For a well-behaved Bottle class, there are no allocations in the
+// producer, since it just fills an empty Bottle that's already large
+// enough; no deallocations in the consumer, since it returns each empty
+// Bottle to the queue after having drunk it; and no copies along the
+// way, since the queue uses swap() everywhere to move full Bottles in
+// one direction and empty ones in the other.
+template <typename T, typename QueueItemVerifier = SwapQueueItemVerifier<T>>
+class SwapQueue {
+ public:
+ // Creates a queue of size size and fills it with default constructed Ts.
+ explicit SwapQueue(size_t size) : queue_(size) {
+ RTC_DCHECK(VerifyQueueSlots());
+ }
+
+ // Same as above and accepts an item verification functor.
+ SwapQueue(size_t size, const QueueItemVerifier& queue_item_verifier)
+ : queue_item_verifier_(queue_item_verifier), queue_(size) {
+ RTC_DCHECK(VerifyQueueSlots());
+ }
+
+ // Creates a queue of size size and fills it with copies of prototype.
+ SwapQueue(size_t size, const T& prototype) : queue_(size, prototype) {
+ RTC_DCHECK(VerifyQueueSlots());
+ }
+
+ // Same as above and accepts an item verification functor.
+ SwapQueue(size_t size,
+ const T& prototype,
+ const QueueItemVerifier& queue_item_verifier)
+ : queue_item_verifier_(queue_item_verifier), queue_(size, prototype) {
+ RTC_DCHECK(VerifyQueueSlots());
+ }
+
+ // Resets the queue to have zero content while maintaining the queue size.
+ // Just like Remove(), this can only be called (safely) from the
+ // consumer.
+ void Clear() {
+ // Drop all non-empty elements by resetting num_elements_ and incrementing
+ // next_read_index_ by the previous value of num_elements_. Relaxed memory
+ // ordering is sufficient since the dropped elements are not accessed.
+ next_read_index_ += std::atomic_exchange_explicit(
+ &num_elements_, size_t{0}, std::memory_order_relaxed);
+ if (next_read_index_ >= queue_.size()) {
+ next_read_index_ -= queue_.size();
+ }
+
+ RTC_DCHECK_LT(next_read_index_, queue_.size());
+ }
+
+ // Inserts a "full" T at the back of the queue by swapping *input with an
+ // "empty" T from the queue.
+ // Returns true if the item was inserted or false if not (the queue was full).
+ // When specified, the T given in *input must pass the ItemVerifier() test.
+ // The contents of *input after the call are then also guaranteed to pass the
+ // ItemVerifier() test.
+ bool Insert(T* input) RTC_WARN_UNUSED_RESULT {
+ RTC_DCHECK(input);
+
+ RTC_DCHECK(queue_item_verifier_(*input));
+
+ // Load the value of num_elements_. Acquire memory ordering prevents reads
+ // and writes to queue_[next_write_index_] to be reordered to before the
+ // load. (That element might be accessed by a concurrent call to Remove()
+ // until the load finishes.)
+ if (std::atomic_load_explicit(&num_elements_, std::memory_order_acquire) ==
+ queue_.size()) {
+ return false;
+ }
+
+ using std::swap;
+ swap(*input, queue_[next_write_index_]);
+
+ // Increment the value of num_elements_ to account for the inserted element.
+ // Release memory ordering prevents the reads and writes to
+ // queue_[next_write_index_] to be reordered to after the increment. (Once
+ // the increment has finished, Remove() might start accessing that element.)
+ const size_t old_num_elements = std::atomic_fetch_add_explicit(
+ &num_elements_, size_t{1}, std::memory_order_release);
+
+ ++next_write_index_;
+ if (next_write_index_ == queue_.size()) {
+ next_write_index_ = 0;
+ }
+
+ RTC_DCHECK_LT(next_write_index_, queue_.size());
+ RTC_DCHECK_LT(old_num_elements, queue_.size());
+
+ return true;
+ }
+
+ // Removes the frontmost "full" T from the queue by swapping it with
+ // the "empty" T in *output.
+ // Returns true if an item could be removed or false if not (the queue was
+ // empty). When specified, The T given in *output must pass the ItemVerifier()
+ // test and the contents of *output after the call are then also guaranteed to
+ // pass the ItemVerifier() test.
+ bool Remove(T* output) RTC_WARN_UNUSED_RESULT {
+ RTC_DCHECK(output);
+
+ RTC_DCHECK(queue_item_verifier_(*output));
+
+ // Load the value of num_elements_. Acquire memory ordering prevents reads
+ // and writes to queue_[next_read_index_] to be reordered to before the
+ // load. (That element might be accessed by a concurrent call to Insert()
+ // until the load finishes.)
+ if (std::atomic_load_explicit(&num_elements_, std::memory_order_acquire) ==
+ 0) {
+ return false;
+ }
+
+ using std::swap;
+ swap(*output, queue_[next_read_index_]);
+
+ // Decrement the value of num_elements_ to account for the removed element.
+ // Release memory ordering prevents the reads and writes to
+ // queue_[next_write_index_] to be reordered to after the decrement. (Once
+ // the decrement has finished, Insert() might start accessing that element.)
+ std::atomic_fetch_sub_explicit(&num_elements_, size_t{1},
+ std::memory_order_release);
+
+ ++next_read_index_;
+ if (next_read_index_ == queue_.size()) {
+ next_read_index_ = 0;
+ }
+
+ RTC_DCHECK_LT(next_read_index_, queue_.size());
+
+ return true;
+ }
+
+ // Returns the current number of elements in the queue. Since elements may be
+ // concurrently added to the queue, the caller must treat this as a lower
+ // bound, not an exact count.
+ // May only be called by the consumer.
+ size_t SizeAtLeast() const {
+ // Acquire memory ordering ensures that we wait for the producer to finish
+ // inserting any element in progress.
+ return std::atomic_load_explicit(&num_elements_, std::memory_order_acquire);
+ }
+
+ private:
+ // Verify that the queue slots complies with the ItemVerifier test. This
+ // function is not thread-safe and can only be used in the constructors.
+ bool VerifyQueueSlots() {
+ for (const auto& v : queue_) {
+ RTC_DCHECK(queue_item_verifier_(v));
+ }
+ return true;
+ }
+
+ // TODO(peah): Change this to use std::function() once we can use C++11 std
+ // lib.
+ QueueItemVerifier queue_item_verifier_;
+
+ // Only accessed by the single producer.
+ size_t next_write_index_ = 0;
+
+ // Only accessed by the single consumer.
+ size_t next_read_index_ = 0;
+
+ // Accessed by both the producer and the consumer and used for synchronization
+ // between them.
+ std::atomic<size_t> num_elements_{0};
+
+ // The elements of the queue are acced by both the producer and the consumer,
+ // mediated by num_elements_. queue_.size() is constant.
+ std::vector<T> queue_;
+
+ SwapQueue(const SwapQueue&) = delete;
+ SwapQueue& operator=(const SwapQueue&) = delete;
+};
+
+} // namespace webrtc
+
+#endif // RTC_BASE_SWAP_QUEUE_H_
diff --git a/webrtc/rtc_base/synchronization/BUILD.gn b/webrtc/rtc_base/synchronization/BUILD.gn
new file mode 100644
index 0000000..a79a048
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/BUILD.gn
@@ -0,0 +1,138 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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")
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+rtc_library("yield") {
+ sources = [
+ "yield.cc",
+ "yield.h",
+ ]
+ deps = []
+}
+
+rtc_library("mutex") {
+ sources = [
+ "mutex.cc",
+ "mutex.h",
+ "mutex_critical_section.h",
+ "mutex_pthread.h",
+ ]
+ if (rtc_use_absl_mutex) {
+ sources += [ "mutex_abseil.h" ]
+ }
+
+ deps = [
+ ":yield",
+ "..:checks",
+ "..:macromagic",
+ "..:platform_thread_types",
+ "../system:unused",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ]
+ if (rtc_use_absl_mutex) {
+ absl_deps += [ "//third_party/abseil-cpp/absl/synchronization" ]
+ }
+}
+
+rtc_library("rw_lock_wrapper") {
+ public = [ "rw_lock_wrapper.h" ]
+ sources = [ "rw_lock_wrapper.cc" ]
+ deps = [ "..:macromagic" ]
+ if (is_win) {
+ sources += [
+ "rw_lock_win.cc",
+ "rw_lock_win.h",
+ ]
+ deps += [ "..:logging" ]
+ } else {
+ sources += [
+ "rw_lock_posix.cc",
+ "rw_lock_posix.h",
+ ]
+ }
+}
+
+rtc_library("sequence_checker") {
+ sources = [
+ "sequence_checker.cc",
+ "sequence_checker.h",
+ ]
+ deps = [
+ ":mutex",
+ "..:checks",
+ "..:criticalsection",
+ "..:macromagic",
+ "..:platform_thread_types",
+ "..:stringutils",
+ "../../api/task_queue",
+ "../system:rtc_export",
+ ]
+}
+
+rtc_library("yield_policy") {
+ sources = [
+ "yield_policy.cc",
+ "yield_policy.h",
+ ]
+ deps = [ "..:checks" ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/base:config",
+ "//third_party/abseil-cpp/absl/base:core_headers",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("synchronization_unittests") {
+ testonly = true
+ sources = [
+ "mutex_unittest.cc",
+ "yield_policy_unittest.cc",
+ ]
+ deps = [
+ ":mutex",
+ ":yield",
+ ":yield_policy",
+ "..:checks",
+ "..:macromagic",
+ "..:rtc_base",
+ "..:rtc_event",
+ "../../test:test_support",
+ "//third_party/google_benchmark",
+ ]
+ }
+
+ rtc_library("mutex_benchmark") {
+ testonly = true
+ sources = [ "mutex_benchmark.cc" ]
+ deps = [
+ ":mutex",
+ "../system:unused",
+ "//third_party/google_benchmark",
+ ]
+ }
+
+ rtc_library("sequence_checker_unittests") {
+ testonly = true
+
+ sources = [ "sequence_checker_unittest.cc" ]
+ deps = [
+ ":sequence_checker",
+ "..:checks",
+ "..:rtc_base_approved",
+ "..:task_queue_for_test",
+ "../../api:function_view",
+ "../../test:test_main",
+ "../../test:test_support",
+ ]
+ }
+}
diff --git a/webrtc/rtc_base/synchronization/mutex.cc b/webrtc/rtc_base/synchronization/mutex.cc
new file mode 100644
index 0000000..6c2d6ff
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/mutex.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/synchronization/mutex.h"
+
+#include "rtc_base/checks.h"
+#include "rtc_base/synchronization/yield.h"
+
+namespace webrtc {
+
+#if !defined(WEBRTC_ABSL_MUTEX)
+void GlobalMutex::Lock() {
+ while (mutex_locked_.exchange(1)) {
+ YieldCurrentThread();
+ }
+}
+
+void GlobalMutex::Unlock() {
+ int old = mutex_locked_.exchange(0);
+ RTC_DCHECK_EQ(old, 1) << "Unlock called without calling Lock first";
+}
+
+GlobalMutexLock::GlobalMutexLock(GlobalMutex* mutex) : mutex_(mutex) {
+ mutex_->Lock();
+}
+
+GlobalMutexLock::~GlobalMutexLock() {
+ mutex_->Unlock();
+}
+#endif // #if !defined(WEBRTC_ABSL_MUTEX)
+
+} // namespace webrtc
diff --git a/webrtc/rtc_base/synchronization/mutex.h b/webrtc/rtc_base/synchronization/mutex.h
new file mode 100644
index 0000000..620fe74
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/mutex.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_H_
+#define RTC_BASE_SYNCHRONIZATION_MUTEX_H_
+
+#include <atomic>
+
+#include "absl/base/const_init.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/system/unused.h"
+#include "rtc_base/thread_annotations.h"
+
+#if defined(WEBRTC_ABSL_MUTEX)
+#include "rtc_base/synchronization/mutex_abseil.h" // nogncheck
+#elif defined(WEBRTC_WIN)
+#include "rtc_base/synchronization/mutex_critical_section.h"
+#elif defined(WEBRTC_POSIX)
+#include "rtc_base/synchronization/mutex_pthread.h"
+#else
+#error Unsupported platform.
+#endif
+
+namespace webrtc {
+
+// The Mutex guarantees exclusive access and aims to follow Abseil semantics
+// (i.e. non-reentrant etc).
+class RTC_LOCKABLE Mutex final {
+ public:
+ Mutex() = default;
+ Mutex(const Mutex&) = delete;
+ Mutex& operator=(const Mutex&) = delete;
+
+ void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
+ impl_.Lock();
+ }
+ RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+ return impl_.TryLock();
+ }
+ void Unlock() RTC_UNLOCK_FUNCTION() {
+ impl_.Unlock();
+ }
+
+ private:
+ MutexImpl impl_;
+};
+
+// MutexLock, for serializing execution through a scope.
+class RTC_SCOPED_LOCKABLE MutexLock final {
+ public:
+ MutexLock(const MutexLock&) = delete;
+ MutexLock& operator=(const MutexLock&) = delete;
+
+ explicit MutexLock(Mutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION(mutex)
+ : mutex_(mutex) {
+ mutex->Lock();
+ }
+ ~MutexLock() RTC_UNLOCK_FUNCTION() { mutex_->Unlock(); }
+
+ private:
+ Mutex* mutex_;
+};
+
+// A mutex used to protect global variables. Do NOT use for other purposes.
+#if defined(WEBRTC_ABSL_MUTEX)
+using GlobalMutex = absl::Mutex;
+using GlobalMutexLock = absl::MutexLock;
+#else
+class RTC_LOCKABLE GlobalMutex final {
+ public:
+ GlobalMutex(const GlobalMutex&) = delete;
+ GlobalMutex& operator=(const GlobalMutex&) = delete;
+
+ constexpr explicit GlobalMutex(absl::ConstInitType /*unused*/)
+ : mutex_locked_(0) {}
+
+ void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION();
+ void Unlock() RTC_UNLOCK_FUNCTION();
+
+ private:
+ std::atomic<int> mutex_locked_; // 0 means lock not taken, 1 means taken.
+};
+
+// GlobalMutexLock, for serializing execution through a scope.
+class RTC_SCOPED_LOCKABLE GlobalMutexLock final {
+ public:
+ GlobalMutexLock(const GlobalMutexLock&) = delete;
+ GlobalMutexLock& operator=(const GlobalMutexLock&) = delete;
+
+ explicit GlobalMutexLock(GlobalMutex* mutex)
+ RTC_EXCLUSIVE_LOCK_FUNCTION(mutex_);
+ ~GlobalMutexLock() RTC_UNLOCK_FUNCTION();
+
+ private:
+ GlobalMutex* mutex_;
+};
+#endif // if defined(WEBRTC_ABSL_MUTEX)
+
+} // namespace webrtc
+
+#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_H_
diff --git a/webrtc/rtc_base/synchronization/mutex_critical_section.h b/webrtc/rtc_base/synchronization/mutex_critical_section.h
new file mode 100644
index 0000000..d206794
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/mutex_critical_section.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_
+#define RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_
+
+#if defined(WEBRTC_WIN)
+// clang-format off
+// clang formating would change include order.
+
+// Include winsock2.h before including <windows.h> to maintain consistency with
+// win32.h. To include win32.h directly, it must be broken out into its own
+// build target.
+#include <winsock2.h>
+#include <windows.h>
+#include <sal.h> // must come after windows headers.
+// clang-format on
+
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+class RTC_LOCKABLE MutexImpl final {
+ public:
+ MutexImpl() { InitializeCriticalSection(&critical_section_); }
+ MutexImpl(const MutexImpl&) = delete;
+ MutexImpl& operator=(const MutexImpl&) = delete;
+ ~MutexImpl() { DeleteCriticalSection(&critical_section_); }
+
+ void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
+ EnterCriticalSection(&critical_section_);
+ }
+ RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+ return TryEnterCriticalSection(&critical_section_) != FALSE;
+ }
+ void Unlock() RTC_UNLOCK_FUNCTION() {
+ LeaveCriticalSection(&critical_section_);
+ }
+
+ private:
+ CRITICAL_SECTION critical_section_;
+};
+
+} // namespace webrtc
+
+#endif // #if defined(WEBRTC_WIN)
+#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_CRITICAL_SECTION_H_
diff --git a/webrtc/rtc_base/synchronization/mutex_pthread.h b/webrtc/rtc_base/synchronization/mutex_pthread.h
new file mode 100644
index 0000000..c9496e7
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/mutex_pthread.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_
+#define RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_
+
+#if defined(WEBRTC_POSIX)
+
+#include <pthread.h>
+#if defined(WEBRTC_MAC)
+#include <pthread_spis.h>
+#endif
+
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+class RTC_LOCKABLE MutexImpl final {
+ public:
+ MutexImpl() {
+ pthread_mutexattr_t mutex_attribute;
+ pthread_mutexattr_init(&mutex_attribute);
+#if defined(WEBRTC_MAC)
+ pthread_mutexattr_setpolicy_np(&mutex_attribute,
+ _PTHREAD_MUTEX_POLICY_FIRSTFIT);
+#endif
+ pthread_mutex_init(&mutex_, &mutex_attribute);
+ pthread_mutexattr_destroy(&mutex_attribute);
+ }
+ MutexImpl(const MutexImpl&) = delete;
+ MutexImpl& operator=(const MutexImpl&) = delete;
+ ~MutexImpl() { pthread_mutex_destroy(&mutex_); }
+
+ void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { pthread_mutex_lock(&mutex_); }
+ RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+ return pthread_mutex_trylock(&mutex_) == 0;
+ }
+ void Unlock() RTC_UNLOCK_FUNCTION() { pthread_mutex_unlock(&mutex_); }
+
+ private:
+ pthread_mutex_t mutex_;
+};
+
+} // namespace webrtc
+#endif // #if defined(WEBRTC_POSIX)
+#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_
diff --git a/webrtc/system_wrappers/source/rw_lock_posix.cc b/webrtc/rtc_base/synchronization/rw_lock_posix.cc
index cdcb7fb..15ef3d7 100644
--- a/webrtc/system_wrappers/source/rw_lock_posix.cc
+++ b/webrtc/rtc_base/synchronization/rw_lock_posix.cc
@@ -8,12 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/system_wrappers/source/rw_lock_posix.h"
+#include "rtc_base/synchronization/rw_lock_posix.h"
+
+#include <stddef.h>
namespace webrtc {
-RWLockPosix::RWLockPosix() : lock_() {
-}
+RWLockPosix::RWLockPosix() : lock_() {}
RWLockPosix::~RWLockPosix() {
pthread_rwlock_destroy(&lock_);
diff --git a/webrtc/system_wrappers/source/rw_lock_posix.h b/webrtc/rtc_base/synchronization/rw_lock_posix.h
index 0ce7305..a103fe7 100644
--- a/webrtc/system_wrappers/source/rw_lock_posix.h
+++ b/webrtc/rtc_base/synchronization/rw_lock_posix.h
@@ -8,14 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
-
-#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
-#include "webrtc/typedefs.h"
+#ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_
+#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_
#include <pthread.h>
+#include "rtc_base/synchronization/rw_lock_wrapper.h"
+
namespace webrtc {
class RWLockPosix : public RWLockWrapper {
@@ -38,4 +37,4 @@ class RWLockPosix : public RWLockWrapper {
} // namespace webrtc
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
+#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_POSIX_H_
diff --git a/webrtc/rtc_base/synchronization/rw_lock_win.cc b/webrtc/rtc_base/synchronization/rw_lock_win.cc
new file mode 100644
index 0000000..3274c78
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/rw_lock_win.cc
@@ -0,0 +1,41 @@
+/*
+ * 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 "rtc_base/synchronization/rw_lock_win.h"
+
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+RWLockWin::RWLockWin() {
+ InitializeSRWLock(&lock_);
+}
+
+RWLockWin* RWLockWin::Create() {
+ return new RWLockWin();
+}
+
+void RWLockWin::AcquireLockExclusive() {
+ AcquireSRWLockExclusive(&lock_);
+}
+
+void RWLockWin::ReleaseLockExclusive() {
+ ReleaseSRWLockExclusive(&lock_);
+}
+
+void RWLockWin::AcquireLockShared() {
+ AcquireSRWLockShared(&lock_);
+}
+
+void RWLockWin::ReleaseLockShared() {
+ ReleaseSRWLockShared(&lock_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rw_lock_win.h b/webrtc/rtc_base/synchronization/rw_lock_win.h
index c279eab..43bde1d 100644
--- a/webrtc/system_wrappers/source/rw_lock_win.h
+++ b/webrtc/rtc_base/synchronization/rw_lock_win.h
@@ -8,33 +8,31 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
-
-#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
+#ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_
+#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_
#include <Windows.h>
+#include "rtc_base/synchronization/rw_lock_wrapper.h"
+
namespace webrtc {
class RWLockWin : public RWLockWrapper {
public:
static RWLockWin* Create();
- ~RWLockWin() {}
- virtual void AcquireLockExclusive();
- virtual void ReleaseLockExclusive();
+ void AcquireLockExclusive() override;
+ void ReleaseLockExclusive() override;
- virtual void AcquireLockShared();
- virtual void ReleaseLockShared();
+ void AcquireLockShared() override;
+ void ReleaseLockShared() override;
private:
RWLockWin();
- static bool LoadModule();
SRWLOCK lock_;
};
} // namespace webrtc
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
+#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WIN_H_
diff --git a/webrtc/system_wrappers/source/rw_lock.cc b/webrtc/rtc_base/synchronization/rw_lock_wrapper.cc
index ff44896..fb46419 100644
--- a/webrtc/system_wrappers/source/rw_lock.cc
+++ b/webrtc/rtc_base/synchronization/rw_lock_wrapper.cc
@@ -8,27 +8,19 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
-
-#include <assert.h>
+#include "rtc_base/synchronization/rw_lock_wrapper.h"
#if defined(_WIN32)
-#include "webrtc/system_wrappers/source/rw_lock_generic.h"
-#include "webrtc/system_wrappers/source/rw_lock_win.h"
+#include "rtc_base/synchronization/rw_lock_win.h"
#else
-#include "webrtc/system_wrappers/source/rw_lock_posix.h"
+#include "rtc_base/synchronization/rw_lock_posix.h"
#endif
namespace webrtc {
RWLockWrapper* RWLockWrapper::CreateRWLock() {
#ifdef _WIN32
- // Native implementation is faster, so use that if available.
- RWLockWrapper* lock = RWLockWin::Create();
- if (lock) {
- return lock;
- }
- return new RWLockGeneric();
+ return RWLockWin::Create();
#else
return RWLockPosix::Create();
#endif
diff --git a/webrtc/system_wrappers/include/rw_lock_wrapper.h b/webrtc/rtc_base/synchronization/rw_lock_wrapper.h
index 751b6a1..39f52fc 100644
--- a/webrtc/system_wrappers/include/rw_lock_wrapper.h
+++ b/webrtc/rtc_base/synchronization/rw_lock_wrapper.h
@@ -8,10 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RW_LOCK_WRAPPER_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RW_LOCK_WRAPPER_H_
+#ifndef RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_
+#define RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_
-#include "webrtc/base/thread_annotations.h"
+#include "rtc_base/thread_annotations.h"
// Note, Windows pre-Vista version of RW locks are not supported natively. For
// these OSs regular critical sections have been used to approximate RW lock
@@ -19,45 +19,43 @@
namespace webrtc {
-class LOCKABLE RWLockWrapper {
+class RTC_LOCKABLE RWLockWrapper {
public:
static RWLockWrapper* CreateRWLock();
virtual ~RWLockWrapper() {}
- virtual void AcquireLockExclusive() EXCLUSIVE_LOCK_FUNCTION() = 0;
- virtual void ReleaseLockExclusive() UNLOCK_FUNCTION() = 0;
+ virtual void AcquireLockExclusive() RTC_EXCLUSIVE_LOCK_FUNCTION() = 0;
+ virtual void ReleaseLockExclusive() RTC_UNLOCK_FUNCTION() = 0;
- virtual void AcquireLockShared() SHARED_LOCK_FUNCTION() = 0;
- virtual void ReleaseLockShared() UNLOCK_FUNCTION() = 0;
+ virtual void AcquireLockShared() RTC_SHARED_LOCK_FUNCTION() = 0;
+ virtual void ReleaseLockShared() RTC_UNLOCK_FUNCTION() = 0;
};
// RAII extensions of the RW lock. Prevents Acquire/Release missmatches and
// provides more compact locking syntax.
-class SCOPED_LOCKABLE ReadLockScoped {
+class RTC_SCOPED_LOCKABLE ReadLockScoped {
public:
- ReadLockScoped(RWLockWrapper& rw_lock) SHARED_LOCK_FUNCTION(rw_lock)
+ explicit ReadLockScoped(RWLockWrapper& rw_lock)
+ RTC_SHARED_LOCK_FUNCTION(rw_lock)
: rw_lock_(rw_lock) {
rw_lock_.AcquireLockShared();
}
- ~ReadLockScoped() UNLOCK_FUNCTION() {
- rw_lock_.ReleaseLockShared();
- }
+ ~ReadLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockShared(); }
private:
RWLockWrapper& rw_lock_;
};
-class SCOPED_LOCKABLE WriteLockScoped {
+class RTC_SCOPED_LOCKABLE WriteLockScoped {
public:
- WriteLockScoped(RWLockWrapper& rw_lock) EXCLUSIVE_LOCK_FUNCTION(rw_lock)
+ explicit WriteLockScoped(RWLockWrapper& rw_lock)
+ RTC_EXCLUSIVE_LOCK_FUNCTION(rw_lock)
: rw_lock_(rw_lock) {
rw_lock_.AcquireLockExclusive();
}
- ~WriteLockScoped() UNLOCK_FUNCTION() {
- rw_lock_.ReleaseLockExclusive();
- }
+ ~WriteLockScoped() RTC_UNLOCK_FUNCTION() { rw_lock_.ReleaseLockExclusive(); }
private:
RWLockWrapper& rw_lock_;
@@ -65,4 +63,4 @@ class SCOPED_LOCKABLE WriteLockScoped {
} // namespace webrtc
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RW_LOCK_WRAPPER_H_
+#endif // RTC_BASE_SYNCHRONIZATION_RW_LOCK_WRAPPER_H_
diff --git a/webrtc/rtc_base/synchronization/sequence_checker.cc b/webrtc/rtc_base/synchronization/sequence_checker.cc
new file mode 100644
index 0000000..1de26cf
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/sequence_checker.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "rtc_base/synchronization/sequence_checker.h"
+
+#if defined(WEBRTC_MAC)
+#include <dispatch/dispatch.h>
+#endif
+
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+namespace {
+// On Mac, returns the label of the current dispatch queue; elsewhere, return
+// null.
+const void* GetSystemQueueRef() {
+#if defined(WEBRTC_MAC)
+ return dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
+#else
+ return nullptr;
+#endif
+}
+
+} // namespace
+
+std::string ExpectationToString(const webrtc::SequenceChecker* checker) {
+#if RTC_DCHECK_IS_ON
+ return checker->ExpectationToString();
+#endif
+ return std::string();
+}
+
+SequenceCheckerImpl::SequenceCheckerImpl()
+ : attached_(true),
+ valid_thread_(rtc::CurrentThreadRef()),
+ valid_queue_(TaskQueueBase::Current()),
+ valid_system_queue_(GetSystemQueueRef()) {}
+
+SequenceCheckerImpl::~SequenceCheckerImpl() = default;
+
+bool SequenceCheckerImpl::IsCurrent() const {
+ const TaskQueueBase* const current_queue = TaskQueueBase::Current();
+ const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef();
+ const void* const current_system_queue = GetSystemQueueRef();
+ MutexLock scoped_lock(&lock_);
+ if (!attached_) { // Previously detached.
+ attached_ = true;
+ valid_thread_ = current_thread;
+ valid_queue_ = current_queue;
+ valid_system_queue_ = current_system_queue;
+ return true;
+ }
+ if (valid_queue_ || current_queue) {
+ return valid_queue_ == current_queue;
+ }
+ if (valid_system_queue_ && valid_system_queue_ == current_system_queue) {
+ return true;
+ }
+ return rtc::IsThreadRefEqual(valid_thread_, current_thread);
+}
+
+void SequenceCheckerImpl::Detach() {
+ MutexLock scoped_lock(&lock_);
+ attached_ = false;
+ // We don't need to touch the other members here, they will be
+ // reset on the next call to IsCurrent().
+}
+
+#if RTC_DCHECK_IS_ON
+std::string SequenceCheckerImpl::ExpectationToString() const {
+ const TaskQueueBase* const current_queue = TaskQueueBase::Current();
+ const rtc::PlatformThreadRef current_thread = rtc::CurrentThreadRef();
+ const void* const current_system_queue = GetSystemQueueRef();
+ MutexLock scoped_lock(&lock_);
+ if (!attached_)
+ return "Checker currently not attached.";
+
+ // The format of the string is meant to compliment the one we have inside of
+ // FatalLog() (checks.cc). Example:
+ //
+ // # Expected: TQ: 0x0 SysQ: 0x7fff69541330 Thread: 0x11dcf6dc0
+ // # Actual: TQ: 0x7fa8f0604190 SysQ: 0x7fa8f0604a30 Thread: 0x700006f1a000
+ // TaskQueue doesn't match
+
+ rtc::StringBuilder message;
+ message.AppendFormat(
+ "# Expected: TQ: %p SysQ: %p Thread: %p\n"
+ "# Actual: TQ: %p SysQ: %p Thread: %p\n",
+ valid_queue_, valid_system_queue_,
+ reinterpret_cast<const void*>(valid_thread_), current_queue,
+ current_system_queue, reinterpret_cast<const void*>(current_thread));
+
+ if ((valid_queue_ || current_queue) && valid_queue_ != current_queue) {
+ message << "TaskQueue doesn't match\n";
+ } else if (valid_system_queue_ &&
+ valid_system_queue_ != current_system_queue) {
+ message << "System queue doesn't match\n";
+ } else if (!rtc::IsThreadRefEqual(valid_thread_, current_thread)) {
+ message << "Threads don't match\n";
+ }
+
+ return message.Release();
+}
+#endif // RTC_DCHECK_IS_ON
+
+} // namespace webrtc
diff --git a/webrtc/rtc_base/synchronization/sequence_checker.h b/webrtc/rtc_base/synchronization/sequence_checker.h
new file mode 100644
index 0000000..ecf8490
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/sequence_checker.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_
+#define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_
+
+#include <type_traits>
+
+#include "api/task_queue/task_queue_base.h"
+#include "rtc_base/platform_thread_types.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/system/rtc_export.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+// Real implementation of SequenceChecker, for use in debug mode, or
+// for temporary use in release mode (e.g. to RTC_CHECK on a threading issue
+// seen only in the wild).
+//
+// Note: You should almost always use the SequenceChecker class to get the
+// right version for your build configuration.
+class RTC_EXPORT SequenceCheckerImpl {
+ public:
+ SequenceCheckerImpl();
+ ~SequenceCheckerImpl();
+
+ bool IsCurrent() const;
+ // Changes the task queue or thread that is checked for in IsCurrent. This can
+ // be useful when an object may be created on one task queue / thread and then
+ // used exclusively on another thread.
+ void Detach();
+
+ // Returns a string that is formatted to match with the error string printed
+ // by RTC_CHECK() when a condition is not met.
+ // This is used in conjunction with the RTC_DCHECK_RUN_ON() macro.
+ std::string ExpectationToString() const;
+
+ private:
+ mutable Mutex lock_;
+ // These are mutable so that IsCurrent can set them.
+ mutable bool attached_ RTC_GUARDED_BY(lock_);
+ mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_);
+ mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_);
+ mutable const void* valid_system_queue_ RTC_GUARDED_BY(lock_);
+};
+
+// Do nothing implementation, for use in release mode.
+//
+// Note: You should almost always use the SequenceChecker class to get the
+// right version for your build configuration.
+class SequenceCheckerDoNothing {
+ public:
+ bool IsCurrent() const { return true; }
+ void Detach() {}
+};
+
+// SequenceChecker is a helper class used to help verify that some methods
+// of a class are called on the same task queue or thread. A
+// SequenceChecker is bound to a a task queue if the object is
+// created on a task queue, or a thread otherwise.
+//
+//
+// Example:
+// class MyClass {
+// public:
+// void Foo() {
+// RTC_DCHECK_RUN_ON(sequence_checker_);
+// ... (do stuff) ...
+// }
+//
+// private:
+// SequenceChecker sequence_checker_;
+// }
+//
+// In Release mode, IsCurrent will always return true.
+#if RTC_DCHECK_IS_ON
+class RTC_LOCKABLE SequenceChecker : public SequenceCheckerImpl {};
+#else
+class RTC_LOCKABLE SequenceChecker : public SequenceCheckerDoNothing {};
+#endif // RTC_ENABLE_THREAD_CHECKER
+
+namespace webrtc_seq_check_impl {
+// Helper class used by RTC_DCHECK_RUN_ON (see example usage below).
+class RTC_SCOPED_LOCKABLE SequenceCheckerScope {
+ public:
+ template <typename ThreadLikeObject>
+ explicit SequenceCheckerScope(const ThreadLikeObject* thread_like_object)
+ RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
+ SequenceCheckerScope(const SequenceCheckerScope&) = delete;
+ SequenceCheckerScope& operator=(const SequenceCheckerScope&) = delete;
+ ~SequenceCheckerScope() RTC_UNLOCK_FUNCTION() {}
+
+ template <typename ThreadLikeObject>
+ static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
+ return thread_like_object->IsCurrent();
+ }
+};
+} // namespace webrtc_seq_check_impl
+} // namespace webrtc
+
+// RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate
+// variables are accessed from same thread/task queue.
+// Using tools designed to check mutexes, it checks at compile time everywhere
+// variable is access, there is a run-time dcheck thread/task queue is correct.
+//
+// class ThreadExample {
+// public:
+// void NeedVar1() {
+// RTC_DCHECK_RUN_ON(network_thread_);
+// transport_->Send();
+// }
+//
+// private:
+// rtc::Thread* network_thread_;
+// int transport_ RTC_GUARDED_BY(network_thread_);
+// };
+//
+// class SequenceCheckerExample {
+// public:
+// int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) {
+// return var2_;
+// }
+//
+// void CallMeFromPacer() {
+// RTC_DCHECK_RUN_ON(&pacer_sequence_checker_)
+// << "Should be called from pacer";
+// CalledFromPacer();
+// }
+//
+// private:
+// int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_);
+// SequenceChecker pacer_sequence_checker_;
+// };
+//
+// class TaskQueueExample {
+// public:
+// class Encoder {
+// public:
+// rtc::TaskQueue* Queue() { return encoder_queue_; }
+// void Encode() {
+// RTC_DCHECK_RUN_ON(encoder_queue_);
+// DoSomething(var_);
+// }
+//
+// private:
+// rtc::TaskQueue* const encoder_queue_;
+// Frame var_ RTC_GUARDED_BY(encoder_queue_);
+// };
+//
+// void Encode() {
+// // Will fail at runtime when DCHECK is enabled:
+// // encoder_->Encode();
+// // Will work:
+// rtc::scoped_refptr<Encoder> encoder = encoder_;
+// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
+// }
+//
+// private:
+// rtc::scoped_refptr<Encoder> encoder_;
+// }
+
+// Document if a function expected to be called from same thread/task queue.
+#define RTC_RUN_ON(x) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
+
+namespace webrtc {
+std::string ExpectationToString(const webrtc::SequenceChecker* checker);
+
+// Catch-all implementation for types other than explicitly supported above.
+template <typename ThreadLikeObject>
+std::string ExpectationToString(const ThreadLikeObject*) {
+ return std::string();
+}
+
+} // namespace webrtc
+
+#define RTC_DCHECK_RUN_ON(x) \
+ webrtc::webrtc_seq_check_impl::SequenceCheckerScope seq_check_scope(x); \
+ RTC_DCHECK((x)->IsCurrent()) << webrtc::ExpectationToString(x)
+
+#endif // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_
diff --git a/webrtc/rtc_base/synchronization/yield.cc b/webrtc/rtc_base/synchronization/yield.cc
new file mode 100644
index 0000000..cbb58d1
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/yield.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/synchronization/yield.h"
+
+#if defined(WEBRTC_WIN)
+#include <windows.h>
+#else
+#include <sched.h>
+#include <time.h>
+#endif
+
+namespace webrtc {
+
+void YieldCurrentThread() {
+ // TODO(bugs.webrtc.org/11634): use dedicated OS functionality instead of
+ // sleep for yielding.
+#if defined(WEBRTC_WIN)
+ ::Sleep(0);
+#elif defined(WEBRTC_MAC) && defined(RTC_USE_NATIVE_MUTEX_ON_MAC) && \
+ !RTC_USE_NATIVE_MUTEX_ON_MAC
+ sched_yield();
+#else
+ static const struct timespec ts_null = {0};
+ nanosleep(&ts_null, nullptr);
+#endif
+}
+
+} // namespace webrtc
diff --git a/webrtc/rtc_base/synchronization/yield.h b/webrtc/rtc_base/synchronization/yield.h
new file mode 100644
index 0000000..d4f5f99
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/yield.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef RTC_BASE_SYNCHRONIZATION_YIELD_H_
+#define RTC_BASE_SYNCHRONIZATION_YIELD_H_
+
+namespace webrtc {
+
+// Request rescheduling of threads.
+void YieldCurrentThread();
+
+} // namespace webrtc
+
+#endif // RTC_BASE_SYNCHRONIZATION_YIELD_H_
diff --git a/webrtc/rtc_base/synchronization/yield_policy.cc b/webrtc/rtc_base/synchronization/yield_policy.cc
new file mode 100644
index 0000000..d883d42
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/yield_policy.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "rtc_base/synchronization/yield_policy.h"
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "rtc_base/checks.h"
+#if !defined(ABSL_HAVE_THREAD_LOCAL) && defined(WEBRTC_POSIX)
+#include <pthread.h>
+#endif
+
+namespace rtc {
+namespace {
+
+#if defined(ABSL_HAVE_THREAD_LOCAL)
+
+ABSL_CONST_INIT thread_local YieldInterface* current_yield_policy = nullptr;
+
+YieldInterface* GetCurrentYieldPolicy() {
+ return current_yield_policy;
+}
+
+void SetCurrentYieldPolicy(YieldInterface* ptr) {
+ current_yield_policy = ptr;
+}
+
+#elif defined(WEBRTC_POSIX)
+
+// Emscripten does not support the C++11 thread_local keyword but does support
+// the pthread thread-local storage API.
+// https://github.com/emscripten-core/emscripten/issues/3502
+
+ABSL_CONST_INIT pthread_key_t g_current_yield_policy_tls = 0;
+
+void InitializeTls() {
+ RTC_CHECK_EQ(pthread_key_create(&g_current_yield_policy_tls, nullptr), 0);
+}
+
+pthread_key_t GetCurrentYieldPolicyTls() {
+ static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+ RTC_CHECK_EQ(pthread_once(&init_once, &InitializeTls), 0);
+ return g_current_yield_policy_tls;
+}
+
+YieldInterface* GetCurrentYieldPolicy() {
+ return static_cast<YieldInterface*>(
+ pthread_getspecific(GetCurrentYieldPolicyTls()));
+}
+
+void SetCurrentYieldPolicy(YieldInterface* ptr) {
+ pthread_setspecific(GetCurrentYieldPolicyTls(), ptr);
+}
+
+#else
+#error Unsupported platform
+#endif
+
+} // namespace
+
+ScopedYieldPolicy::ScopedYieldPolicy(YieldInterface* policy)
+ : previous_(GetCurrentYieldPolicy()) {
+ SetCurrentYieldPolicy(policy);
+}
+
+ScopedYieldPolicy::~ScopedYieldPolicy() {
+ SetCurrentYieldPolicy(previous_);
+}
+
+void ScopedYieldPolicy::YieldExecution() {
+ YieldInterface* current = GetCurrentYieldPolicy();
+ if (current)
+ current->YieldExecution();
+}
+
+} // namespace rtc
diff --git a/webrtc/rtc_base/synchronization/yield_policy.h b/webrtc/rtc_base/synchronization/yield_policy.h
new file mode 100644
index 0000000..5def6b7
--- /dev/null
+++ b/webrtc/rtc_base/synchronization/yield_policy.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_
+#define RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_
+
+namespace rtc {
+class YieldInterface {
+ public:
+ virtual ~YieldInterface() = default;
+ virtual void YieldExecution() = 0;
+};
+
+// Sets the current thread-local yield policy while it's in scope and reverts
+// to the previous policy when it leaves the scope.
+class ScopedYieldPolicy final {
+ public:
+ explicit ScopedYieldPolicy(YieldInterface* policy);
+ ScopedYieldPolicy(const ScopedYieldPolicy&) = delete;
+ ScopedYieldPolicy& operator=(const ScopedYieldPolicy&) = delete;
+ ~ScopedYieldPolicy();
+ // Will yield as specified by the currently active thread-local yield policy
+ // (which by default is a no-op).
+ static void YieldExecution();
+
+ private:
+ YieldInterface* const previous_;
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_SYNCHRONIZATION_YIELD_POLICY_H_
diff --git a/webrtc/rtc_base/system/arch.h b/webrtc/rtc_base/system/arch.h
new file mode 100644
index 0000000..ed216e6
--- /dev/null
+++ b/webrtc/rtc_base/system/arch.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can 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 platform-specific typedefs and defines.
+// Much of it is derived from Chromium's build/build_config.h.
+
+#ifndef RTC_BASE_SYSTEM_ARCH_H_
+#define RTC_BASE_SYSTEM_ARCH_H_
+
+// Processor architecture detection. For more info on what's defined, see:
+// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+// http://www.agner.org/optimize/calling_conventions.pdf
+// or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define WEBRTC_ARCH_X86_FAMILY
+#define WEBRTC_ARCH_X86_64
+#define WEBRTC_ARCH_64_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(_M_ARM64) || defined(__aarch64__)
+#define WEBRTC_ARCH_ARM_FAMILY
+#define WEBRTC_ARCH_64_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(_M_IX86) || defined(__i386__)
+#define WEBRTC_ARCH_X86_FAMILY
+#define WEBRTC_ARCH_X86
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__ARMEL__)
+#define WEBRTC_ARCH_ARM_FAMILY
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__MIPSEL__)
+#define WEBRTC_ARCH_MIPS_FAMILY
+#if defined(__LP64__)
+#define WEBRTC_ARCH_64_BITS
+#else
+#define WEBRTC_ARCH_32_BITS
+#endif
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__pnacl__)
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#elif defined(__EMSCRIPTEN__)
+#define WEBRTC_ARCH_32_BITS
+#define WEBRTC_ARCH_LITTLE_ENDIAN
+#else
+#error Please add support for your architecture in rtc_base/system/arch.h
+#endif
+
+#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
+#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
+#endif
+
+#endif // RTC_BASE_SYSTEM_ARCH_H_
diff --git a/webrtc/system_wrappers/include/asm_defines.h b/webrtc/rtc_base/system/asm_defines.h
index fe4c05e..a7f6aad 100644
--- a/webrtc/system_wrappers/include/asm_defines.h
+++ b/webrtc/rtc_base/system/asm_defines.h
@@ -8,8 +8,12 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ASM_DEFINES_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ASM_DEFINES_H_
+#ifndef RTC_BASE_SYSTEM_ASM_DEFINES_H_
+#define RTC_BASE_SYSTEM_ASM_DEFINES_H_
+
+// clang-format off
+// clang formatting breaks everything here, e.g. concatenating directives,
+// due to absence of context via asm keyword.
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
@@ -63,4 +67,6 @@ strheq \reg1, \reg2, \num
.text
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ASM_DEFINES_H_
+// clang-format on
+
+#endif // RTC_BASE_SYSTEM_ASM_DEFINES_H_
diff --git a/webrtc/rtc_base/system/file_wrapper.cc b/webrtc/rtc_base/system/file_wrapper.cc
new file mode 100644
index 0000000..2828790
--- /dev/null
+++ b/webrtc/rtc_base/system/file_wrapper.cc
@@ -0,0 +1,127 @@
+/*
+ * 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 "rtc_base/system/file_wrapper.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+#include <cerrno>
+
+#ifdef _WIN32
+#include <Windows.h>
+#else
+#include <string.h>
+#endif
+
+#include <utility>
+
+namespace webrtc {
+namespace {
+FILE* FileOpen(const char* file_name_utf8, bool read_only, int* error) {
+#if defined(_WIN32)
+ int len = MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, nullptr, 0);
+ std::wstring wstr(len, 0);
+ MultiByteToWideChar(CP_UTF8, 0, file_name_utf8, -1, &wstr[0], len);
+ FILE* file = _wfopen(wstr.c_str(), read_only ? L"rb" : L"wb");
+#else
+ FILE* file = fopen(file_name_utf8, read_only ? "rb" : "wb");
+#endif
+ if (!file && error) {
+ *error = errno;
+ }
+ return file;
+}
+
+const char* GetCstrCheckNoEmbeddedNul(const std::string& s) {
+ const char* p = s.c_str();
+ RTC_CHECK_EQ(strlen(p), s.size())
+ << "Invalid filename, containing NUL character";
+ return p;
+}
+} // namespace
+
+// static
+FileWrapper FileWrapper::OpenReadOnly(const char* file_name_utf8) {
+ return FileWrapper(FileOpen(file_name_utf8, true, nullptr));
+}
+
+// static
+FileWrapper FileWrapper::OpenReadOnly(const std::string& file_name_utf8) {
+ return OpenReadOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8));
+}
+
+// static
+FileWrapper FileWrapper::OpenWriteOnly(const char* file_name_utf8,
+ int* error /*=nullptr*/) {
+ return FileWrapper(FileOpen(file_name_utf8, false, error));
+}
+
+// static
+FileWrapper FileWrapper::OpenWriteOnly(const std::string& file_name_utf8,
+ int* error /*=nullptr*/) {
+ return OpenWriteOnly(GetCstrCheckNoEmbeddedNul(file_name_utf8), error);
+}
+
+FileWrapper::FileWrapper(FileWrapper&& other) {
+ operator=(std::move(other));
+}
+
+FileWrapper& FileWrapper::operator=(FileWrapper&& other) {
+ Close();
+ file_ = other.file_;
+ other.file_ = nullptr;
+ return *this;
+}
+
+bool FileWrapper::SeekRelative(int64_t offset) {
+ RTC_DCHECK(file_);
+ return fseek(file_, rtc::checked_cast<long>(offset), SEEK_CUR) == 0;
+}
+
+bool FileWrapper::SeekTo(int64_t position) {
+ RTC_DCHECK(file_);
+ return fseek(file_, rtc::checked_cast<long>(position), SEEK_SET) == 0;
+}
+
+bool FileWrapper::Flush() {
+ RTC_DCHECK(file_);
+ return fflush(file_) == 0;
+}
+
+size_t FileWrapper::Read(void* buf, size_t length) {
+ RTC_DCHECK(file_);
+ return fread(buf, 1, length, file_);
+}
+
+bool FileWrapper::ReadEof() const {
+ RTC_DCHECK(file_);
+ return feof(file_);
+}
+
+bool FileWrapper::Write(const void* buf, size_t length) {
+ RTC_DCHECK(file_);
+ return fwrite(buf, 1, length, file_) == length;
+}
+
+bool FileWrapper::Close() {
+ if (file_ == nullptr)
+ return true;
+
+ bool success = fclose(file_) == 0;
+ file_ = nullptr;
+ return success;
+}
+
+FILE* FileWrapper::Release() {
+ FILE* file = file_;
+ file_ = nullptr;
+ return file;
+}
+
+} // namespace webrtc
diff --git a/webrtc/rtc_base/system/file_wrapper.h b/webrtc/rtc_base/system/file_wrapper.h
new file mode 100644
index 0000000..42c463c
--- /dev/null
+++ b/webrtc/rtc_base/system/file_wrapper.h
@@ -0,0 +1,109 @@
+/*
+ * 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 RTC_BASE_SYSTEM_FILE_WRAPPER_H_
+#define RTC_BASE_SYSTEM_FILE_WRAPPER_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <string>
+
+// Implementation that can read (exclusive) or write from/to a file.
+
+namespace webrtc {
+
+// This class is a thin wrapper around FILE*. It's main features are that it
+// owns the FILE*, calling fclose on destruction, and that on windows, file
+// names passed to the open methods are always treated as utf-8, regardless of
+// system code page.
+
+// Most of the methods return only a success/fail indication. When needed, an
+// optional argument |int* error| should be added to all methods, in the same
+// way as for the OpenWriteOnly methods.
+class FileWrapper final {
+ public:
+ // Opens a file, in read or write mode. Use the is_open() method on the
+ // returned object to check if the open operation was successful. On failure,
+ // and if |error| is non-null, the system errno value is stored at |*error|.
+ // The file is closed by the destructor.
+ static FileWrapper OpenReadOnly(const char* file_name_utf8);
+ static FileWrapper OpenReadOnly(const std::string& file_name_utf8);
+ static FileWrapper OpenWriteOnly(const char* file_name_utf8,
+ int* error = nullptr);
+
+ static FileWrapper OpenWriteOnly(const std::string& file_name_utf8,
+ int* error = nullptr);
+
+ FileWrapper() = default;
+
+ // Takes over ownership of |file|, closing it on destruction. Calling with
+ // null |file| is allowed, and results in a FileWrapper with is_open() false.
+ explicit FileWrapper(FILE* file) : file_(file) {}
+ ~FileWrapper() { Close(); }
+
+ // Copying is not supported.
+ FileWrapper(const FileWrapper&) = delete;
+ FileWrapper& operator=(const FileWrapper&) = delete;
+
+ // Support for move semantics.
+ FileWrapper(FileWrapper&&);
+ FileWrapper& operator=(FileWrapper&&);
+
+ // Returns true if a file has been opened. If the file is not open, no methods
+ // but is_open and Close may be called.
+ bool is_open() const { return file_ != nullptr; }
+
+ // Closes the file, and implies Flush. Returns true on success, false if
+ // writing buffered data fails. On failure, the file is nevertheless closed.
+ // Calling Close on an already closed file does nothing and returns success.
+ bool Close();
+
+ // Releases and returns the wrapped file without closing it. This call passes
+ // the ownership of the file to the caller, and the wrapper is no longer
+ // responsible for closing it. Similarly the previously wrapped file is no
+ // longer available for the wrapper to use in any aspect.
+ FILE* Release();
+
+ // Write any buffered data to the underlying file. Returns true on success,
+ // false on write error. Note: Flushing when closing, is not required.
+ bool Flush();
+
+ // Seeks to the beginning of file. Returns true on success, false on failure,
+ // e.g., if the underlying file isn't seekable.
+ bool Rewind() { return SeekTo(0); }
+ // TODO(nisse): The seek functions are used only by the WavReader. If that
+ // code is demoted to test code, seek functions can be deleted from this
+ // utility.
+ // Seek relative to current file position.
+ bool SeekRelative(int64_t offset);
+ // Seek to given position.
+ bool SeekTo(int64_t position);
+
+ // Returns number of bytes read. Short count indicates EOF or error.
+ size_t Read(void* buf, size_t length);
+
+ // If the most recent Read() returned a short count, this methods returns true
+ // if the short count was due to EOF, and false it it was due to some i/o
+ // error.
+ bool ReadEof() const;
+
+ // Returns true if all data was successfully written (or buffered), or false
+ // if there was an error. Writing buffered data can fail later, and is
+ // reported with return value from Flush or Close.
+ bool Write(const void* buf, size_t length);
+
+ private:
+ FILE* file_ = nullptr;
+};
+
+} // namespace webrtc
+
+#endif // RTC_BASE_SYSTEM_FILE_WRAPPER_H_
diff --git a/webrtc/rtc_base/system/ignore_warnings.h b/webrtc/rtc_base/system/ignore_warnings.h
new file mode 100644
index 0000000..e891c50
--- /dev/null
+++ b/webrtc/rtc_base/system/ignore_warnings.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_
+#define RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_
+
+#ifdef __clang__
+#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wframe-larger-than=\"")
+#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("clang diagnostic pop")
+#elif __GNUC__
+#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN() \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wframe-larger-than=\"")
+#define RTC_POP_IGNORING_WFRAME_LARGER_THAN() _Pragma("GCC diagnostic pop")
+#else
+#define RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
+#define RTC_POP_IGNORING_WFRAME_LARGER_THAN()
+#endif
+
+#endif // RTC_BASE_SYSTEM_IGNORE_WARNINGS_H_
diff --git a/webrtc/rtc_base/system/inline.h b/webrtc/rtc_base/system/inline.h
new file mode 100644
index 0000000..f585d34
--- /dev/null
+++ b/webrtc/rtc_base/system/inline.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_SYSTEM_INLINE_H_
+#define RTC_BASE_SYSTEM_INLINE_H_
+
+#if defined(_MSC_VER)
+
+#define RTC_FORCE_INLINE __forceinline
+#define RTC_NO_INLINE __declspec(noinline)
+
+#elif defined(__GNUC__)
+
+#define RTC_FORCE_INLINE __attribute__((__always_inline__))
+#define RTC_NO_INLINE __attribute__((__noinline__))
+
+#else
+
+#define RTC_FORCE_INLINE
+#define RTC_NO_INLINE
+
+#endif
+
+#endif // RTC_BASE_SYSTEM_INLINE_H_
diff --git a/webrtc/rtc_base/system/rtc_export.h b/webrtc/rtc_base/system/rtc_export.h
new file mode 100644
index 0000000..d1eb60a
--- /dev/null
+++ b/webrtc/rtc_base/system/rtc_export.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_SYSTEM_RTC_EXPORT_H_
+#define RTC_BASE_SYSTEM_RTC_EXPORT_H_
+
+// RTC_EXPORT is used to mark symbols as exported or imported when WebRTC is
+// built or used as a shared library.
+// When WebRTC is built as a static library the RTC_EXPORT macro expands to
+// nothing.
+
+#ifdef WEBRTC_ENABLE_SYMBOL_EXPORT
+
+#ifdef WEBRTC_WIN
+
+#ifdef WEBRTC_LIBRARY_IMPL
+#define RTC_EXPORT __declspec(dllexport)
+#else
+#define RTC_EXPORT __declspec(dllimport)
+#endif
+
+#else // WEBRTC_WIN
+
+#if __has_attribute(visibility) && defined(WEBRTC_LIBRARY_IMPL)
+#define RTC_EXPORT __attribute__((visibility("default")))
+#endif
+
+#endif // WEBRTC_WIN
+
+#endif // WEBRTC_ENABLE_SYMBOL_EXPORT
+
+#ifndef RTC_EXPORT
+#define RTC_EXPORT
+#endif
+
+#endif // RTC_BASE_SYSTEM_RTC_EXPORT_H_
diff --git a/webrtc/rtc_base/system/unused.h b/webrtc/rtc_base/system/unused.h
new file mode 100644
index 0000000..a0add4e
--- /dev/null
+++ b/webrtc/rtc_base/system/unused.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_SYSTEM_UNUSED_H_
+#define RTC_BASE_SYSTEM_UNUSED_H_
+
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+// int foo() RTC_WARN_UNUSED_RESULT;
+// To explicitly ignore a result, cast to void.
+// TODO(kwiberg): Remove when we can use [[nodiscard]] from C++17.
+#if defined(__clang__)
+#define RTC_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+#elif defined(__GNUC__)
+// gcc has a __warn_unused_result__ attribute, but you can't quiet it by
+// casting to void, so we don't use it.
+#define RTC_WARN_UNUSED_RESULT
+#else
+#define RTC_WARN_UNUSED_RESULT
+#endif
+
+// Prevent the compiler from warning about an unused variable. For example:
+// int result = DoSomething();
+// assert(result == 17);
+// RTC_UNUSED(result);
+// Note: In most cases it is better to remove the unused variable rather than
+// suppressing the compiler warning.
+#ifndef RTC_UNUSED
+#define RTC_UNUSED(x) static_cast<void>(x)
+#endif // RTC_UNUSED
+
+#endif // RTC_BASE_SYSTEM_UNUSED_H_
diff --git a/webrtc/rtc_base/system/warn_current_thread_is_deadlocked.h b/webrtc/rtc_base/system/warn_current_thread_is_deadlocked.h
new file mode 100644
index 0000000..4a0ba9d
--- /dev/null
+++ b/webrtc/rtc_base/system/warn_current_thread_is_deadlocked.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2019 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_
+#define RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_
+
+namespace webrtc {
+
+#if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
+void WarnThatTheCurrentThreadIsProbablyDeadlocked();
+#else
+inline void WarnThatTheCurrentThreadIsProbablyDeadlocked() {}
+#endif
+
+} // namespace webrtc
+
+#endif // RTC_BASE_SYSTEM_WARN_CURRENT_THREAD_IS_DEADLOCKED_H_
diff --git a/webrtc/rtc_base/thread_annotations.h b/webrtc/rtc_base/thread_annotations.h
new file mode 100644
index 0000000..8569fab
--- /dev/null
+++ b/webrtc/rtc_base/thread_annotations.h
@@ -0,0 +1,95 @@
+//
+// 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.
+//
+// Borrowed from
+// https://code.google.com/p/gperftools/source/browse/src/base/thread_annotations.h
+// but adapted for clang attributes instead of the gcc.
+//
+// This header file contains the macro definitions for thread safety
+// annotations that allow the developers to document the locking policies
+// of their multi-threaded code. The annotations can also help program
+// analysis tools to identify potential thread safety issues.
+
+#ifndef RTC_BASE_THREAD_ANNOTATIONS_H_
+#define RTC_BASE_THREAD_ANNOTATIONS_H_
+
+#if defined(__clang__) && (!defined(SWIG))
+#define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define RTC_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+// Document if a shared variable/field needs to be protected by a lock.
+// GUARDED_BY allows the user to specify a particular lock that should be
+// held when accessing the annotated variable.
+#define RTC_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+// Document if the memory location pointed to by a pointer should be guarded
+// by a lock when dereferencing the pointer. Note that a pointer variable to a
+// shared memory location could itself be a shared variable. For example, if a
+// shared global pointer q, which is guarded by mu1, points to a shared memory
+// location that is guarded by mu2, q should be annotated as follows:
+// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+#define RTC_PT_GUARDED_BY(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+// Document the acquisition order between locks that can be held
+// simultaneously by a thread. For any two locks that need to be annotated
+// to establish an acquisition order, only one of them needs the annotation.
+// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
+// and ACQUIRED_BEFORE.)
+#define RTC_ACQUIRED_AFTER(x) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x))
+#define RTC_ACQUIRED_BEFORE(x) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x))
+
+// The following three annotations document the lock requirements for
+// functions/methods.
+
+// Document if a function expects certain locks to be held before it is called
+#define RTC_EXCLUSIVE_LOCKS_REQUIRED(...) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+#define RTC_SHARED_LOCKS_REQUIRED(...) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+
+// Document the locks acquired in the body of the function. These locks
+// cannot be held when calling this function (as google3's Mutex locks are
+// non-reentrant).
+#define RTC_LOCKS_EXCLUDED(...) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+// Document the lock the annotated function returns without acquiring it.
+#define RTC_LOCK_RETURNED(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+// Document if a class/type is a lockable type (such as the Mutex class).
+#define RTC_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+
+// Document if a class is a scoped lockable type (such as the MutexLock class).
+#define RTC_SCOPED_LOCKABLE RTC_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+// The following annotations specify lock and unlock primitives.
+#define RTC_EXCLUSIVE_LOCK_FUNCTION(...) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+#define RTC_SHARED_LOCK_FUNCTION(...) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+#define RTC_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+#define RTC_SHARED_TRYLOCK_FUNCTION(...) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+#define RTC_UNLOCK_FUNCTION(...) \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+// An escape hatch for thread safety analysis to ignore the annotated function.
+#define RTC_NO_THREAD_SAFETY_ANALYSIS \
+ RTC_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+#endif // RTC_BASE_THREAD_ANNOTATIONS_H_
diff --git a/webrtc/rtc_base/thread_checker.h b/webrtc/rtc_base/thread_checker.h
new file mode 100644
index 0000000..876a08e
--- /dev/null
+++ b/webrtc/rtc_base/thread_checker.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+// Borrowed from Chromium's src/base/threading/thread_checker.h.
+
+#ifndef RTC_BASE_THREAD_CHECKER_H_
+#define RTC_BASE_THREAD_CHECKER_H_
+
+#include "rtc_base/deprecation.h"
+#include "rtc_base/synchronization/sequence_checker.h"
+
+namespace rtc {
+// TODO(srte): Replace usages of this with SequenceChecker.
+class ThreadChecker : public webrtc::SequenceChecker {
+ public:
+ RTC_DEPRECATED bool CalledOnValidThread() const { return IsCurrent(); }
+ RTC_DEPRECATED void DetachFromThread() { Detach(); }
+};
+} // namespace rtc
+#endif // RTC_BASE_THREAD_CHECKER_H_
diff --git a/webrtc/rtc_base/time_utils.cc b/webrtc/rtc_base/time_utils.cc
new file mode 100644
index 0000000..11c9d5a
--- /dev/null
+++ b/webrtc/rtc_base/time_utils.cc
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <stdint.h>
+
+#if defined(WEBRTC_POSIX)
+#include <sys/time.h>
+#if defined(WEBRTC_MAC)
+#include <mach/mach_time.h>
+#endif
+#endif
+
+#if defined(WEBRTC_WIN)
+// clang-format off
+// clang formatting would put <windows.h> last,
+// which leads to compilation failure.
+#include <windows.h>
+#include <mmsystem.h>
+#include <sys/timeb.h>
+// clang-format on
+#endif
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/time_utils.h"
+
+namespace rtc {
+
+ClockInterface* g_clock = nullptr;
+
+ClockInterface* SetClockForTesting(ClockInterface* clock) {
+ ClockInterface* prev = g_clock;
+ g_clock = clock;
+ return prev;
+}
+
+ClockInterface* GetClockForTesting() {
+ return g_clock;
+}
+
+#if defined(WINUWP)
+
+namespace {
+
+class TimeHelper final {
+ public:
+ TimeHelper(const TimeHelper&) = delete;
+
+ // Resets the clock based upon an NTP server. This routine must be called
+ // prior to the main system start-up to ensure all clocks are based upon
+ // an NTP server time if NTP synchronization is required. No critical
+ // section is used thus this method must be called prior to any clock
+ // routines being used.
+ static void SyncWithNtp(int64_t ntp_server_time_ms) {
+ auto& singleton = Singleton();
+ TIME_ZONE_INFORMATION time_zone;
+ GetTimeZoneInformation(&time_zone);
+ int64_t time_zone_bias_ns =
+ rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
+ singleton.app_start_time_ns_ =
+ (ntp_server_time_ms - kNTPTimeToUnixTimeEpochOffset) * 1000000 -
+ time_zone_bias_ns;
+ singleton.UpdateReferenceTime();
+ }
+
+ // Returns the number of nanoseconds that have passed since unix epoch.
+ static int64_t TicksNs() {
+ auto& singleton = Singleton();
+ int64_t result = 0;
+ LARGE_INTEGER qpcnt;
+ QueryPerformanceCounter(&qpcnt);
+ result = rtc::dchecked_cast<int64_t>(
+ (rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
+ rtc::dchecked_cast<uint64_t>(singleton.os_ticks_per_second_)) *
+ 10000);
+ result = singleton.app_start_time_ns_ + result -
+ singleton.time_since_os_start_ns_;
+ return result;
+ }
+
+ private:
+ TimeHelper() {
+ TIME_ZONE_INFORMATION time_zone;
+ GetTimeZoneInformation(&time_zone);
+ int64_t time_zone_bias_ns =
+ rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
+ FILETIME ft;
+ // This will give us system file in UTC format.
+ GetSystemTimeAsFileTime(&ft);
+ LARGE_INTEGER li;
+ li.HighPart = ft.dwHighDateTime;
+ li.LowPart = ft.dwLowDateTime;
+
+ app_start_time_ns_ = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) * 100 -
+ time_zone_bias_ns;
+
+ UpdateReferenceTime();
+ }
+
+ static TimeHelper& Singleton() {
+ static TimeHelper singleton;
+ return singleton;
+ }
+
+ void UpdateReferenceTime() {
+ LARGE_INTEGER qpfreq;
+ QueryPerformanceFrequency(&qpfreq);
+ os_ticks_per_second_ = rtc::dchecked_cast<int64_t>(qpfreq.QuadPart);
+
+ LARGE_INTEGER qpcnt;
+ QueryPerformanceCounter(&qpcnt);
+ time_since_os_start_ns_ = rtc::dchecked_cast<int64_t>(
+ (rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
+ rtc::dchecked_cast<uint64_t>(os_ticks_per_second_)) *
+ 10000);
+ }
+
+ private:
+ static constexpr uint64_t kFileTimeToUnixTimeEpochOffset =
+ 116444736000000000ULL;
+ static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L;
+
+ // The number of nanoseconds since unix system epoch
+ int64_t app_start_time_ns_;
+ // The number of nanoseconds since the OS started
+ int64_t time_since_os_start_ns_;
+ // The OS calculated ticks per second
+ int64_t os_ticks_per_second_;
+};
+
+} // namespace
+
+void SyncWithNtp(int64_t time_from_ntp_server_ms) {
+ TimeHelper::SyncWithNtp(time_from_ntp_server_ms);
+}
+
+#endif // defined(WINUWP)
+
+int64_t SystemTimeNanos() {
+ int64_t ticks;
+#if defined(WEBRTC_MAC)
+ static mach_timebase_info_data_t timebase;
+ if (timebase.denom == 0) {
+ // Get the timebase if this is the first time we run.
+ // Recommended by Apple's QA1398.
+ if (mach_timebase_info(&timebase) != KERN_SUCCESS) {
+ RTC_NOTREACHED();
+ }
+ }
+ // Use timebase to convert absolute time tick units into nanoseconds.
+ const auto mul = [](uint64_t a, uint32_t b) -> int64_t {
+ RTC_DCHECK_NE(b, 0);
+ RTC_DCHECK_LE(a, std::numeric_limits<int64_t>::max() / b)
+ << "The multiplication " << a << " * " << b << " overflows";
+ return rtc::dchecked_cast<int64_t>(a * b);
+ };
+ ticks = mul(mach_absolute_time(), timebase.numer) / timebase.denom;
+#elif defined(WEBRTC_POSIX)
+ struct timespec ts;
+ // TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not
+ // supported?
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
+ static_cast<int64_t>(ts.tv_nsec);
+#elif defined(WINUWP)
+ ticks = TimeHelper::TicksNs();
+#elif defined(WEBRTC_WIN)
+ static volatile LONG last_timegettime = 0;
+ static volatile int64_t num_wrap_timegettime = 0;
+ volatile LONG* last_timegettime_ptr = &last_timegettime;
+ DWORD now = timeGetTime();
+ // Atomically update the last gotten time
+ DWORD old = InterlockedExchange(last_timegettime_ptr, now);
+ if (now < old) {
+ // If now is earlier than old, there may have been a race between threads.
+ // 0x0fffffff ~3.1 days, the code will not take that long to execute
+ // so it must have been a wrap around.
+ if (old > 0xf0000000 && now < 0x0fffffff) {
+ num_wrap_timegettime++;
+ }
+ }
+ ticks = now + (num_wrap_timegettime << 32);
+ // TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're
+ // just wasting a multiply and divide when doing Time() on Windows.
+ ticks = ticks * kNumNanosecsPerMillisec;
+#else
+#error Unsupported platform.
+#endif
+ return ticks;
+}
+
+int64_t SystemTimeMillis() {
+ return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec);
+}
+
+int64_t TimeNanos() {
+ if (g_clock) {
+ return g_clock->TimeNanos();
+ }
+ return SystemTimeNanos();
+}
+
+uint32_t Time32() {
+ return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec);
+}
+
+int64_t TimeMillis() {
+ return TimeNanos() / kNumNanosecsPerMillisec;
+}
+
+int64_t TimeMicros() {
+ return TimeNanos() / kNumNanosecsPerMicrosec;
+}
+
+int64_t TimeAfter(int64_t elapsed) {
+ RTC_DCHECK_GE(elapsed, 0);
+ return TimeMillis() + elapsed;
+}
+
+int32_t TimeDiff32(uint32_t later, uint32_t earlier) {
+ return later - earlier;
+}
+
+int64_t TimeDiff(int64_t later, int64_t earlier) {
+ return later - earlier;
+}
+
+TimestampWrapAroundHandler::TimestampWrapAroundHandler()
+ : last_ts_(0), num_wrap_(-1) {}
+
+int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) {
+ if (num_wrap_ == -1) {
+ last_ts_ = ts;
+ num_wrap_ = 0;
+ return ts;
+ }
+
+ if (ts < last_ts_) {
+ if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff)
+ ++num_wrap_;
+ } else if ((ts - last_ts_) > 0xf0000000) {
+ // Backwards wrap. Unwrap with last wrap count and don't update last_ts_.
+ return ts + (num_wrap_ - 1) * (int64_t{1} << 32);
+ }
+
+ last_ts_ = ts;
+ return ts + (num_wrap_ << 32);
+}
+
+int64_t TmToSeconds(const tm& tm) {
+ static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ static short int cumul_mdays[12] = {0, 31, 59, 90, 120, 151,
+ 181, 212, 243, 273, 304, 334};
+ int year = tm.tm_year + 1900;
+ int month = tm.tm_mon;
+ int day = tm.tm_mday - 1; // Make 0-based like the rest.
+ int hour = tm.tm_hour;
+ int min = tm.tm_min;
+ int sec = tm.tm_sec;
+
+ bool expiry_in_leap_year =
+ (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
+
+ if (year < 1970)
+ return -1;
+ if (month < 0 || month > 11)
+ return -1;
+ if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1))
+ return -1;
+ if (hour < 0 || hour > 23)
+ return -1;
+ if (min < 0 || min > 59)
+ return -1;
+ if (sec < 0 || sec > 59)
+ return -1;
+
+ day += cumul_mdays[month];
+
+ // Add number of leap days between 1970 and the expiration year, inclusive.
+ day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) +
+ (year / 400 - 1970 / 400));
+
+ // We will have added one day too much above if expiration is during a leap
+ // year, and expiration is in January or February.
+ if (expiry_in_leap_year && month <= 2 - 1) // |month| is zero based.
+ day -= 1;
+
+ // Combine all variables into seconds from 1970-01-01 00:00 (except |month|
+ // which was accumulated into |day| above).
+ return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60 +
+ min) *
+ 60 +
+ sec;
+}
+
+int64_t TimeUTCMicros() {
+ if (g_clock) {
+ return g_clock->TimeNanos() / kNumNanosecsPerMicrosec;
+ }
+#if defined(WEBRTC_POSIX)
+ struct timeval time;
+ gettimeofday(&time, nullptr);
+ // Convert from second (1.0) and microsecond (1e-6).
+ return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec +
+ time.tv_usec);
+
+#elif defined(WEBRTC_WIN)
+ struct _timeb time;
+ _ftime(&time);
+ // Convert from second (1.0) and milliseconds (1e-3).
+ return (static_cast<int64_t>(time.time) * rtc::kNumMicrosecsPerSec +
+ static_cast<int64_t>(time.millitm) * rtc::kNumMicrosecsPerMillisec);
+#endif
+}
+
+int64_t TimeUTCMillis() {
+ return TimeUTCMicros() / kNumMicrosecsPerMillisec;
+}
+
+} // namespace rtc
diff --git a/webrtc/rtc_base/time_utils.h b/webrtc/rtc_base/time_utils.h
new file mode 100644
index 0000000..147ab8d
--- /dev/null
+++ b/webrtc/rtc_base/time_utils.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2005 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_TIME_UTILS_H_
+#define RTC_BASE_TIME_UTILS_H_
+
+#include <stdint.h>
+#include <time.h>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/system/rtc_export.h"
+
+namespace rtc {
+
+static const int64_t kNumMillisecsPerSec = INT64_C(1000);
+static const int64_t kNumMicrosecsPerSec = INT64_C(1000000);
+static const int64_t kNumNanosecsPerSec = INT64_C(1000000000);
+
+static const int64_t kNumMicrosecsPerMillisec =
+ kNumMicrosecsPerSec / kNumMillisecsPerSec;
+static const int64_t kNumNanosecsPerMillisec =
+ kNumNanosecsPerSec / kNumMillisecsPerSec;
+static const int64_t kNumNanosecsPerMicrosec =
+ kNumNanosecsPerSec / kNumMicrosecsPerSec;
+
+// TODO(honghaiz): Define a type for the time value specifically.
+
+class ClockInterface {
+ public:
+ virtual ~ClockInterface() {}
+ virtual int64_t TimeNanos() const = 0;
+};
+
+// Sets the global source of time. This is useful mainly for unit tests.
+//
+// Returns the previously set ClockInterface, or nullptr if none is set.
+//
+// Does not transfer ownership of the clock. SetClockForTesting(nullptr)
+// should be called before the ClockInterface is deleted.
+//
+// This method is not thread-safe; it should only be used when no other thread
+// is running (for example, at the start/end of a unit test, or start/end of
+// main()).
+//
+// TODO(deadbeef): Instead of having functions that access this global
+// ClockInterface, we may want to pass the ClockInterface into everything
+// that uses it, eliminating the need for a global variable and this function.
+RTC_EXPORT ClockInterface* SetClockForTesting(ClockInterface* clock);
+
+// Returns previously set clock, or nullptr if no custom clock is being used.
+RTC_EXPORT ClockInterface* GetClockForTesting();
+
+#if defined(WINUWP)
+// Synchronizes the current clock based upon an NTP server's epoch in
+// milliseconds.
+void SyncWithNtp(int64_t time_from_ntp_server_ms);
+#endif // defined(WINUWP)
+
+// Returns the actual system time, even if a clock is set for testing.
+// Useful for timeouts while using a test clock, or for logging.
+int64_t SystemTimeNanos();
+int64_t SystemTimeMillis();
+
+// Returns the current time in milliseconds in 32 bits.
+uint32_t Time32();
+
+// Returns the current time in milliseconds in 64 bits.
+RTC_EXPORT int64_t TimeMillis();
+// Deprecated. Do not use this in any new code.
+inline int64_t Time() {
+ return TimeMillis();
+}
+
+// Returns the current time in microseconds.
+RTC_EXPORT int64_t TimeMicros();
+
+// Returns the current time in nanoseconds.
+RTC_EXPORT int64_t TimeNanos();
+
+// Returns a future timestamp, 'elapsed' milliseconds from now.
+int64_t TimeAfter(int64_t elapsed);
+
+// Number of milliseconds that would elapse between 'earlier' and 'later'
+// timestamps. The value is negative if 'later' occurs before 'earlier'.
+int64_t TimeDiff(int64_t later, int64_t earlier);
+int32_t TimeDiff32(uint32_t later, uint32_t earlier);
+
+// The number of milliseconds that have elapsed since 'earlier'.
+inline int64_t TimeSince(int64_t earlier) {
+ return TimeMillis() - earlier;
+}
+
+// The number of milliseconds that will elapse between now and 'later'.
+inline int64_t TimeUntil(int64_t later) {
+ return later - TimeMillis();
+}
+
+class TimestampWrapAroundHandler {
+ public:
+ TimestampWrapAroundHandler();
+
+ int64_t Unwrap(uint32_t ts);
+
+ private:
+ uint32_t last_ts_;
+ int64_t num_wrap_;
+};
+
+// Convert from tm, which is relative to 1900-01-01 00:00 to number of
+// seconds from 1970-01-01 00:00 ("epoch"). Don't return time_t since that
+// is still 32 bits on many systems.
+int64_t TmToSeconds(const tm& tm);
+
+// Return the number of microseconds since January 1, 1970, UTC.
+// Useful mainly when producing logs to be correlated with other
+// devices, and when the devices in question all have properly
+// synchronized clocks.
+//
+// Note that this function obeys the system's idea about what the time
+// is. It is not guaranteed to be monotonic; it will jump in case the
+// system time is changed, e.g., by some other process calling
+// settimeofday. Always use rtc::TimeMicros(), not this function, for
+// measuring time intervals and timeouts.
+int64_t TimeUTCMicros();
+
+// Return the number of milliseconds since January 1, 1970, UTC.
+// See above.
+int64_t TimeUTCMillis();
+
+} // namespace rtc
+
+#endif // RTC_BASE_TIME_UTILS_H_
diff --git a/webrtc/rtc_base/trace_event.h b/webrtc/rtc_base/trace_event.h
new file mode 100644
index 0000000..a0b788f
--- /dev/null
+++ b/webrtc/rtc_base/trace_event.h
@@ -0,0 +1,1022 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file under third_party_mods/chromium or at:
+// http://src.chromium.org/svn/trunk/src/LICENSE
+
+#ifndef RTC_BASE_TRACE_EVENT_H_
+#define RTC_BASE_TRACE_EVENT_H_
+
+#include <string>
+
+#include "rtc_base/event_tracer.h"
+
+#if defined(TRACE_EVENT0)
+#error "Another copy of trace_event.h has already been included."
+#endif
+
+#if defined(RTC_DISABLE_TRACE_EVENTS)
+#define RTC_TRACE_EVENTS_ENABLED 0
+#else
+#define RTC_TRACE_EVENTS_ENABLED 1
+#endif
+
+// Type values for identifying types in the TraceValue union.
+#define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1))
+#define TRACE_VALUE_TYPE_UINT (static_cast<unsigned char>(2))
+#define TRACE_VALUE_TYPE_INT (static_cast<unsigned char>(3))
+#define TRACE_VALUE_TYPE_DOUBLE (static_cast<unsigned char>(4))
+#define TRACE_VALUE_TYPE_POINTER (static_cast<unsigned char>(5))
+#define TRACE_VALUE_TYPE_STRING (static_cast<unsigned char>(6))
+#define TRACE_VALUE_TYPE_COPY_STRING (static_cast<unsigned char>(7))
+
+#if RTC_TRACE_EVENTS_ENABLED
+
+// Extracted from Chromium's src/base/debug/trace_event.h.
+
+// This header is designed to give you trace_event macros without specifying
+// how the events actually get collected and stored. If you need to expose trace
+// event to some other universe, you can copy-and-paste this file,
+// implement the TRACE_EVENT_API macros, and do any other necessary fixup for
+// the target platform. The end result is that multiple libraries can funnel
+// events through to a shared trace event collector.
+
+// Trace events are for tracking application performance and resource usage.
+// Macros are provided to track:
+// Begin and end of function calls
+// Counters
+//
+// Events are issued against categories. Whereas RTC_LOG's
+// categories are statically defined, TRACE categories are created
+// implicitly with a string. For example:
+// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent")
+//
+// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope:
+// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")
+// doSomethingCostly()
+// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")
+// Note: our tools can't always determine the correct BEGIN/END pairs unless
+// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you
+// need them to be in separate scopes.
+//
+// A common use case is to trace entire function scopes. This
+// issues a trace BEGIN and END automatically:
+// void doSomethingCostly() {
+// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly");
+// ...
+// }
+//
+// Additional parameters can be associated with an event:
+// void doSomethingCostly2(int howMuch) {
+// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly",
+// "howMuch", howMuch);
+// ...
+// }
+//
+// The trace system will automatically add to this information the
+// current process id, thread id, and a timestamp in microseconds.
+//
+// To trace an asynchronous procedure such as an IPC send/receive, use
+// ASYNC_BEGIN and ASYNC_END:
+// [single threaded sender code]
+// static int send_count = 0;
+// ++send_count;
+// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count);
+// Send(new MyMessage(send_count));
+// [receive code]
+// void OnMyMessage(send_count) {
+// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count);
+// }
+// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs.
+// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process.
+// Pointers can be used for the ID parameter, and they will be mangled
+// internally so that the same pointer on two different processes will not
+// match. For example:
+// class MyTracedClass {
+// public:
+// MyTracedClass() {
+// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this);
+// }
+// ~MyTracedClass() {
+// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this);
+// }
+// }
+//
+// Trace event also supports counters, which is a way to track a quantity
+// as it varies over time. Counters are created with the following macro:
+// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue);
+//
+// Counters are process-specific. The macro itself can be issued from any
+// thread, however.
+//
+// Sometimes, you want to track two counters at once. You can do this with two
+// counter macros:
+// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]);
+// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]);
+// Or you can do it with a combined macro:
+// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter",
+// "bytesPinned", g_myCounterValue[0],
+// "bytesAllocated", g_myCounterValue[1]);
+// This indicates to the tracing UI that these counters should be displayed
+// in a single graph, as a summed area chart.
+//
+// Since counters are in a global namespace, you may want to disembiguate with a
+// unique ID, by using the TRACE_COUNTER_ID* variations.
+//
+// By default, trace collection is compiled in, but turned off at runtime.
+// Collecting trace data is the responsibility of the embedding
+// application. In Chrome's case, navigating to about:tracing will turn on
+// tracing and display data collected across all active processes.
+//
+//
+// Memory scoping note:
+// Tracing copies the pointers, not the string content, of the strings passed
+// in for category, name, and arg_names. Thus, the following code will
+// cause problems:
+// char* str = strdup("impprtantName");
+// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD!
+// free(str); // Trace system now has dangling pointer
+//
+// To avoid this issue with the |name| and |arg_name| parameters, use the
+// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead.
+// Notes: The category must always be in a long-lived char* (i.e. static const).
+// The |arg_values|, when used, are always deep copied with the _COPY
+// macros.
+//
+// When are string argument values copied:
+// const char* arg_values are only referenced by default:
+// TRACE_EVENT1("category", "name",
+// "arg1", "literal string is only referenced");
+// Use TRACE_STR_COPY to force copying of a const char*:
+// TRACE_EVENT1("category", "name",
+// "arg1", TRACE_STR_COPY("string will be copied"));
+// std::string arg_values are always copied:
+// TRACE_EVENT1("category", "name",
+// "arg1", std::string("string will be copied"));
+//
+//
+// Thread Safety:
+// Thread safety is provided by methods defined in event_tracer.h. See the file
+// for details.
+
+// By default, const char* argument values are assumed to have long-lived scope
+// and will not be copied. Use this macro to force a const char* to be copied.
+#define TRACE_STR_COPY(str) \
+ webrtc::trace_event_internal::TraceStringWithCopy(str)
+
+// This will mark the trace event as disabled by default. The user will need
+// to explicitly enable the event.
+#define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name
+
+// By default, uint64 ID argument values are not mangled with the Process ID in
+// TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling.
+#define TRACE_ID_MANGLE(id) \
+ webrtc::trace_event_internal::TraceID::ForceMangle(id)
+
+// Records a pair of begin and end events called "name" for the current
+// scope, with 0, 1 or 2 associated arguments. If the category is not
+// enabled, then this does nothing.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+#define TRACE_EVENT0(category, name) \
+ INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name)
+#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val)
+#define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+
+// Records a single event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+#define TRACE_EVENT_INSTANT0(category, name) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+ category, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_INSTANT0(category, name) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+ category, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+
+// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+#define TRACE_EVENT_BEGIN0(category, name) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+ category, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_BEGIN0(category, name) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+ category, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+
+// Records a single END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+#define TRACE_EVENT_END0(category, name) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+ category, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+ category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_END0(category, name) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+ category, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+ category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+ arg2_name, arg2_val)
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+#define TRACE_COUNTER1(category, name, value) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+ category, name, TRACE_EVENT_FLAG_NONE, \
+ "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER1(category, name, value) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+ category, name, TRACE_EVENT_FLAG_COPY, \
+ "value", static_cast<int>(value))
+
+// Records the values of a multi-parted counter called "name" immediately.
+// The UI will treat value1 and value2 as parts of a whole, displaying their
+// values as a stacked-bar chart.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+#define TRACE_COUNTER2(category, name, value1_name, value1_val, \
+ value2_name, value2_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+ category, name, TRACE_EVENT_FLAG_NONE, \
+ value1_name, static_cast<int>(value1_val), \
+ value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \
+ value2_name, value2_val) \
+ INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+ category, name, TRACE_EVENT_FLAG_COPY, \
+ value1_name, static_cast<int>(value1_val), \
+ value2_name, static_cast<int>(value2_val))
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+// will be xored with a hash of the process ID so that the same pointer on
+// two different processes will not collide.
+#define TRACE_COUNTER_ID1(category, name, id, value) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, \
+ "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ "value", static_cast<int>(value))
+
+// Records the values of a multi-parted counter called "name" immediately.
+// The UI will treat value1 and value2 as parts of a whole, displaying their
+// values as a stacked-bar chart.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+// will be xored with a hash of the process ID so that the same pointer on
+// two different processes will not collide.
+#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \
+ value2_name, value2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, \
+ value1_name, static_cast<int>(value1_val), \
+ value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \
+ value2_name, value2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ value1_name, static_cast<int>(value1_val), \
+ value2_name, static_cast<int>(value2_val))
+
+
+// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC
+// events are considered to match if their category, name and id values all
+// match. |id| must either be a pointer or an integer value up to 64 bits. If
+// it's a pointer, the bits will be xored with a hash of the process ID so
+// that the same pointer on two different processes will not collide.
+// An asynchronous operation can consist of multiple phases. The first phase is
+// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
+// ASYNC_STEP macros. When the operation completes, call ASYNC_END.
+// An ASYNC trace typically occur on a single thread (if not, they will only be
+// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that
+// operation must use the same |name| and |id|. Each event can have its own
+// args.
+#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single ASYNC_STEP event for |step| immediately. If the category
+// is not enabled, then this does nothing. The |name| and |id| must match the
+// ASYNC_BEGIN event above. The |step| param identifies this step within the
+// async event. This should be called at the beginning of the next phase of an
+// asynchronous operation.
+#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+ arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
+#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \
+ arg1_name, arg1_val)
+
+// Records a single ASYNC_END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define TRACE_EVENT_ASYNC_END0(category, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+ category, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+ category, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+
+
+// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+// literals). They may not include " chars.
+// - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW
+// events are considered to match if their category, name and id values all
+// match. |id| must either be a pointer or an integer value up to 64 bits. If
+// it's a pointer, the bits will be xored with a hash of the process ID so
+// that the same pointer on two different processes will not collide.
+// FLOW events are different from ASYNC events in how they are drawn by the
+// tracing UI. A FLOW defines asynchronous data flow, such as posting a task
+// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be
+// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar
+// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined
+// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP
+// macros. When the operation completes, call FLOW_END. An async operation can
+// span threads and processes, but all events in that operation must use the
+// same |name| and |id|. Each event can have its own args.
+#define TRACE_EVENT_FLOW_BEGIN0(category, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single FLOW_STEP event for |step| immediately. If the category
+// is not enabled, then this does nothing. The |name| and |id| must match the
+// FLOW_BEGIN event above. The |step| param identifies this step within the
+// async event. This should be called at the beginning of the next phase of an
+// asynchronous operation.
+#define TRACE_EVENT_FLOW_STEP0(category, name, id, step) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+ arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
+#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \
+ arg1_name, arg1_val)
+
+// Records a single FLOW_END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define TRACE_EVENT_FLOW_END0(category, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+ category, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+ category, name, id, TRACE_EVENT_FLAG_NONE, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+ category, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+ category, name, id, TRACE_EVENT_FLAG_COPY, \
+ arg1_name, arg1_val, arg2_name, arg2_val)
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation specific tracing API definitions.
+
+// Get a pointer to the enabled state of the given trace category. Only
+// long-lived literal strings should be given as the category name. The returned
+// pointer can be held permanently in a local static for example. If the
+// unsigned char is non-zero, tracing is enabled. If tracing is enabled,
+// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
+// between the load of the tracing state and the call to
+// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
+// for best performance when tracing is disabled.
+// const unsigned char*
+// TRACE_EVENT_API_GET_CATEGORY_ENABLED(const char* category_name)
+#define TRACE_EVENT_API_GET_CATEGORY_ENABLED \
+ webrtc::EventTracer::GetCategoryEnabled
+
+// Add a trace event to the platform tracing system.
+// void TRACE_EVENT_API_ADD_TRACE_EVENT(
+// char phase,
+// const unsigned char* category_enabled,
+// const char* name,
+// unsigned long long id,
+// int num_args,
+// const char** arg_names,
+// const unsigned char* arg_types,
+// const unsigned long long* arg_values,
+// unsigned char flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT webrtc::EventTracer::AddTraceEvent
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Implementation detail: trace event macros create temporary variables
+// to keep instrumentation overhead low. These macros give each temporary
+// variable a unique name based on the line number to prevent name collissions.
+#define INTERNAL_TRACE_EVENT_UID3(a,b) \
+ trace_event_unique_##a##b
+#define INTERNAL_TRACE_EVENT_UID2(a,b) \
+ INTERNAL_TRACE_EVENT_UID3(a,b)
+#define INTERNAL_TRACE_EVENT_UID(name_prefix) \
+ INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
+
+#if WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS
+#define INTERNAL_TRACE_EVENT_INFO_TYPE const unsigned char*
+#else
+#define INTERNAL_TRACE_EVENT_INFO_TYPE static const unsigned char*
+#endif // WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS
+
+// Implementation detail: internal macro to create static category.
+#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category) \
+ INTERNAL_TRACE_EVENT_INFO_TYPE INTERNAL_TRACE_EVENT_UID(catstatic) = \
+ TRACE_EVENT_API_GET_CATEGORY_ENABLED(category);
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
+ if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \
+ webrtc::trace_event_internal::AddTraceEvent( \
+ phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \
+ webrtc::trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+// Implementation detail: internal macro to create static category and add begin
+// event if the category is enabled. Also adds the end event when the scope
+// ends.
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
+ webrtc::trace_event_internal::TraceEndOnScopeClose \
+ INTERNAL_TRACE_EVENT_UID(profileScope); \
+ if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \
+ webrtc::trace_event_internal::AddTraceEvent( \
+ TRACE_EVENT_PHASE_BEGIN, \
+ INTERNAL_TRACE_EVENT_UID(catstatic), \
+ name, webrtc::trace_event_internal::kNoEventId, \
+ TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
+ INTERNAL_TRACE_EVENT_UID(profileScope).Initialize( \
+ INTERNAL_TRACE_EVENT_UID(catstatic), name); \
+ }
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, \
+ ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
+ if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \
+ unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+ webrtc::trace_event_internal::TraceID trace_event_trace_id( \
+ id, &trace_event_flags); \
+ webrtc::trace_event_internal::AddTraceEvent( \
+ phase, INTERNAL_TRACE_EVENT_UID(catstatic), \
+ name, trace_event_trace_id.data(), trace_event_flags, \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+// Notes regarding the following definitions:
+// New values can be added and propagated to third party libraries, but existing
+// definitions must never be changed, because third party libraries may use old
+// definitions.
+
+// Phase indicates the nature of an event entry. E.g. part of a begin/end pair.
+#define TRACE_EVENT_PHASE_BEGIN ('B')
+#define TRACE_EVENT_PHASE_END ('E')
+#define TRACE_EVENT_PHASE_INSTANT ('I')
+#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
+#define TRACE_EVENT_PHASE_ASYNC_STEP ('T')
+#define TRACE_EVENT_PHASE_ASYNC_END ('F')
+#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s')
+#define TRACE_EVENT_PHASE_FLOW_STEP ('t')
+#define TRACE_EVENT_PHASE_FLOW_END ('f')
+#define TRACE_EVENT_PHASE_METADATA ('M')
+#define TRACE_EVENT_PHASE_COUNTER ('C')
+
+// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
+#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned char>(0))
+#define TRACE_EVENT_FLAG_COPY (static_cast<unsigned char>(1 << 0))
+#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned char>(1 << 1))
+#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned char>(1 << 2))
+
+namespace webrtc {
+namespace trace_event_internal {
+
+// Specify these values when the corresponding argument of AddTraceEvent is not
+// used.
+const int kZeroNumArgs = 0;
+const unsigned long long kNoEventId = 0;
+
+// TraceID encapsulates an ID that can either be an integer or pointer. Pointers
+// are mangled with the Process ID so that they are unlikely to collide when the
+// same pointer is used on different processes.
+class TraceID {
+ public:
+ class ForceMangle {
+ public:
+ explicit ForceMangle(unsigned long long id) : data_(id) {}
+ explicit ForceMangle(unsigned long id) : data_(id) {}
+ explicit ForceMangle(unsigned int id) : data_(id) {}
+ explicit ForceMangle(unsigned short id) : data_(id) {}
+ explicit ForceMangle(unsigned char id) : data_(id) {}
+ explicit ForceMangle(long long id)
+ : data_(static_cast<unsigned long long>(id)) {}
+ explicit ForceMangle(long id)
+ : data_(static_cast<unsigned long long>(id)) {}
+ explicit ForceMangle(int id)
+ : data_(static_cast<unsigned long long>(id)) {}
+ explicit ForceMangle(short id)
+ : data_(static_cast<unsigned long long>(id)) {}
+ explicit ForceMangle(signed char id)
+ : data_(static_cast<unsigned long long>(id)) {}
+
+ unsigned long long data() const { return data_; }
+
+ private:
+ unsigned long long data_;
+ };
+
+ explicit TraceID(const void* id, unsigned char* flags)
+ : data_(static_cast<unsigned long long>(
+ reinterpret_cast<uintptr_t>(id))) {
+ *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+ }
+ explicit TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) {
+ *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+ }
+ explicit TraceID(unsigned long long id, unsigned char* flags)
+ : data_(id) { (void)flags; }
+ explicit TraceID(unsigned long id, unsigned char* flags)
+ : data_(id) { (void)flags; }
+ explicit TraceID(unsigned int id, unsigned char* flags)
+ : data_(id) { (void)flags; }
+ explicit TraceID(unsigned short id, unsigned char* flags)
+ : data_(id) { (void)flags; }
+ explicit TraceID(unsigned char id, unsigned char* flags)
+ : data_(id) { (void)flags; }
+ explicit TraceID(long long id, unsigned char* flags)
+ : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+ explicit TraceID(long id, unsigned char* flags)
+ : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+ explicit TraceID(int id, unsigned char* flags)
+ : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+ explicit TraceID(short id, unsigned char* flags)
+ : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+ explicit TraceID(signed char id, unsigned char* flags)
+ : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+
+ unsigned long long data() const { return data_; }
+
+ private:
+ unsigned long long data_;
+};
+
+// Simple union to store various types as unsigned long long.
+union TraceValueUnion {
+ bool as_bool;
+ unsigned long long as_uint;
+ long long as_int;
+ double as_double;
+ const void* as_pointer;
+ const char* as_string;
+};
+
+// Simple container for const char* that should be copied instead of retained.
+class TraceStringWithCopy {
+ public:
+ explicit TraceStringWithCopy(const char* str) : str_(str) {}
+ operator const char* () const { return str_; }
+ private:
+ const char* str_;
+};
+
+// Define SetTraceValue for each allowed type. It stores the type and
+// value in the return arguments. This allows this API to avoid declaring any
+// structures so that it is portable to third_party libraries.
+#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \
+ union_member, \
+ value_type_id) \
+ static inline void SetTraceValue(actual_type arg, \
+ unsigned char* type, \
+ unsigned long long* value) { \
+ TraceValueUnion type_value; \
+ type_value.union_member = arg; \
+ *type = value_type_id; \
+ *value = type_value.as_uint; \
+ }
+// Simpler form for int types that can be safely casted.
+#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \
+ value_type_id) \
+ static inline void SetTraceValue(actual_type arg, \
+ unsigned char* type, \
+ unsigned long long* value) { \
+ *type = value_type_id; \
+ *value = static_cast<unsigned long long>(arg); \
+ }
+
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL)
+INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer,
+ TRACE_VALUE_TYPE_POINTER)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string,
+ TRACE_VALUE_TYPE_STRING)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string,
+ TRACE_VALUE_TYPE_COPY_STRING)
+
+#undef INTERNAL_DECLARE_SET_TRACE_VALUE
+#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
+
+// std::string version of SetTraceValue so that trace arguments can be strings.
+static inline void SetTraceValue(const std::string& arg,
+ unsigned char* type,
+ unsigned long long* value) {
+ TraceValueUnion type_value;
+ type_value.as_string = arg.c_str();
+ *type = TRACE_VALUE_TYPE_COPY_STRING;
+ *value = type_value.as_uint;
+}
+
+// These AddTraceEvent template functions are defined here instead of in the
+// macro, because the arg_values could be temporary objects, such as
+// std::string. In order to store pointers to the internal c_str and pass
+// through to the tracing API, the arg_values must live throughout
+// these procedures.
+
+static inline void AddTraceEvent(char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned char flags) {
+ TRACE_EVENT_API_ADD_TRACE_EVENT(phase, category_enabled, name, id,
+ kZeroNumArgs, nullptr, nullptr, nullptr,
+ flags);
+}
+
+template<class ARG1_TYPE>
+static inline void AddTraceEvent(char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned char flags,
+ const char* arg1_name,
+ const ARG1_TYPE& arg1_val) {
+ const int num_args = 1;
+ unsigned char arg_types[1];
+ unsigned long long arg_values[1];
+ SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+ TRACE_EVENT_API_ADD_TRACE_EVENT(
+ phase, category_enabled, name, id,
+ num_args, &arg1_name, arg_types, arg_values,
+ flags);
+}
+
+template<class ARG1_TYPE, class ARG2_TYPE>
+static inline void AddTraceEvent(char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned char flags,
+ const char* arg1_name,
+ const ARG1_TYPE& arg1_val,
+ const char* arg2_name,
+ const ARG2_TYPE& arg2_val) {
+ const int num_args = 2;
+ const char* arg_names[2] = { arg1_name, arg2_name };
+ unsigned char arg_types[2];
+ unsigned long long arg_values[2];
+ SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+ SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
+ TRACE_EVENT_API_ADD_TRACE_EVENT(
+ phase, category_enabled, name, id,
+ num_args, arg_names, arg_types, arg_values,
+ flags);
+}
+
+// Used by TRACE_EVENTx macro. Do not use directly.
+class TraceEndOnScopeClose {
+ public:
+ // Note: members of data_ intentionally left uninitialized. See Initialize.
+ TraceEndOnScopeClose() : p_data_(nullptr) {}
+ ~TraceEndOnScopeClose() {
+ if (p_data_)
+ AddEventIfEnabled();
+ }
+
+ void Initialize(const unsigned char* category_enabled,
+ const char* name) {
+ data_.category_enabled = category_enabled;
+ data_.name = name;
+ p_data_ = &data_;
+ }
+
+ private:
+ // Add the end event if the category is still enabled.
+ void AddEventIfEnabled() {
+ // Only called when p_data_ is non-null.
+ if (*p_data_->category_enabled) {
+ TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_END,
+ p_data_->category_enabled, p_data_->name,
+ kNoEventId, kZeroNumArgs, nullptr,
+ nullptr, nullptr, TRACE_EVENT_FLAG_NONE);
+ }
+ }
+
+ // This Data struct workaround is to avoid initializing all the members
+ // in Data during construction of this object, since this object is always
+ // constructed, even when tracing is disabled. If the members of Data were
+ // members of this class instead, compiler warnings occur about potential
+ // uninitialized accesses.
+ struct Data {
+ const unsigned char* category_enabled;
+ const char* name;
+ };
+ Data* p_data_;
+ Data data_;
+};
+
+} // namespace trace_event_internal
+} // namespace webrtc
+#else
+
+////////////////////////////////////////////////////////////////////////////////
+// This section defines no-op alternatives to the tracing macros when
+// RTC_DISABLE_TRACE_EVENTS is defined.
+
+#define RTC_NOOP() do {} while (0)
+
+#define TRACE_STR_COPY(str) RTC_NOOP()
+
+#define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name
+
+#define TRACE_ID_MANGLE(id) 0
+
+#define TRACE_EVENT0(category, name) RTC_NOOP()
+#define TRACE_EVENT1(category, name, arg1_name, arg1_val) RTC_NOOP()
+#define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \
+ RTC_NOOP()
+
+#define TRACE_EVENT_INSTANT0(category, name) RTC_NOOP()
+#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) RTC_NOOP()
+
+#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+
+#define TRACE_EVENT_COPY_INSTANT0(category, name) RTC_NOOP()
+#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+
+#define TRACE_EVENT_BEGIN0(category, name) RTC_NOOP()
+#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) RTC_NOOP()
+#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_BEGIN0(category, name) RTC_NOOP()
+#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+
+#define TRACE_EVENT_END0(category, name) RTC_NOOP()
+#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) RTC_NOOP()
+#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_END0(category, name) RTC_NOOP()
+#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+
+#define TRACE_COUNTER1(category, name, value) RTC_NOOP()
+#define TRACE_COPY_COUNTER1(category, name, value) RTC_NOOP()
+
+#define TRACE_COUNTER2(category, name, value1_name, value1_val, \
+ value2_name, value2_val) RTC_NOOP()
+#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \
+ value2_name, value2_val) RTC_NOOP()
+
+#define TRACE_COUNTER_ID1(category, name, id, value) RTC_NOOP()
+#define TRACE_COPY_COUNTER_ID1(category, name, id, value) RTC_NOOP()
+
+#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \
+ value2_name, value2_val) RTC_NOOP()
+#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \
+ value2_name, value2_val) RTC_NOOP()
+
+#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) RTC_NOOP()
+#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) RTC_NOOP()
+#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+
+#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) RTC_NOOP()
+#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \
+ arg1_name, arg1_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) RTC_NOOP()
+#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \
+ arg1_name, arg1_val) RTC_NOOP()
+
+#define TRACE_EVENT_ASYNC_END0(category, name, id) RTC_NOOP()
+#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) RTC_NOOP()
+#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+
+#define TRACE_EVENT_FLOW_BEGIN0(category, name, id) RTC_NOOP()
+#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) RTC_NOOP()
+#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+
+#define TRACE_EVENT_FLOW_STEP0(category, name, id, step) RTC_NOOP()
+#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, \
+ arg1_name, arg1_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) RTC_NOOP()
+#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, \
+ arg1_name, arg1_val) RTC_NOOP()
+
+#define TRACE_EVENT_FLOW_END0(category, name, id) RTC_NOOP()
+#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) RTC_NOOP()
+#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \
+ RTC_NOOP()
+#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) RTC_NOOP()
+
+#define TRACE_EVENT_API_GET_CATEGORY_ENABLED ""
+
+#define TRACE_EVENT_API_ADD_TRACE_EVENT RTC_NOOP()
+
+#endif // RTC_TRACE_EVENTS_ENABLED
+
+#endif // RTC_BASE_TRACE_EVENT_H_ \ No newline at end of file
diff --git a/webrtc/rtc_base/type_traits.h b/webrtc/rtc_base/type_traits.h
new file mode 100644
index 0000000..0cb899c
--- /dev/null
+++ b/webrtc/rtc_base/type_traits.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 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 RTC_BASE_TYPE_TRAITS_H_
+#define RTC_BASE_TYPE_TRAITS_H_
+
+#include <cstddef>
+#include <type_traits>
+
+namespace rtc {
+
+// Determines if the given class has zero-argument .data() and .size() methods
+// whose return values are convertible to T* and size_t, respectively.
+template <typename DS, typename T>
+class HasDataAndSize {
+ private:
+ template <
+ typename C,
+ typename std::enable_if<
+ std::is_convertible<decltype(std::declval<C>().data()), T*>::value &&
+ std::is_convertible<decltype(std::declval<C>().size()),
+ std::size_t>::value>::type* = nullptr>
+ static int Test(int);
+
+ template <typename>
+ static char Test(...);
+
+ public:
+ static constexpr bool value = std::is_same<decltype(Test<DS>(0)), int>::value;
+};
+
+namespace test_has_data_and_size {
+
+template <typename DR, typename SR>
+struct Test1 {
+ DR data();
+ SR size();
+};
+static_assert(HasDataAndSize<Test1<int*, int>, int>::value, "");
+static_assert(HasDataAndSize<Test1<int*, int>, const int>::value, "");
+static_assert(HasDataAndSize<Test1<const int*, int>, const int>::value, "");
+static_assert(!HasDataAndSize<Test1<const int*, int>, int>::value,
+ "implicit cast of const int* to int*");
+static_assert(!HasDataAndSize<Test1<char*, size_t>, int>::value,
+ "implicit cast of char* to int*");
+
+struct Test2 {
+ int* data;
+ size_t size;
+};
+static_assert(!HasDataAndSize<Test2, int>::value,
+ ".data and .size aren't functions");
+
+struct Test3 {
+ int* data();
+};
+static_assert(!HasDataAndSize<Test3, int>::value, ".size() is missing");
+
+class Test4 {
+ int* data();
+ size_t size();
+};
+static_assert(!HasDataAndSize<Test4, int>::value,
+ ".data() and .size() are private");
+
+} // namespace test_has_data_and_size
+
+namespace type_traits_impl {
+
+// Determines if the given type is an enum that converts implicitly to
+// an integral type.
+template <typename T>
+struct IsIntEnum {
+ private:
+ // This overload is used if the type is an enum, and unary plus
+ // compiles and turns it into an integral type.
+ template <typename X,
+ typename std::enable_if<
+ std::is_enum<X>::value &&
+ std::is_integral<decltype(+std::declval<X>())>::value>::type* =
+ nullptr>
+ static int Test(int);
+
+ // Otherwise, this overload is used.
+ template <typename>
+ static char Test(...);
+
+ public:
+ static constexpr bool value =
+ std::is_same<decltype(Test<typename std::remove_reference<T>::type>(0)),
+ int>::value;
+};
+
+} // namespace type_traits_impl
+
+// Determines if the given type is integral, or an enum that
+// converts implicitly to an integral type.
+template <typename T>
+struct IsIntlike {
+ private:
+ using X = typename std::remove_reference<T>::type;
+
+ public:
+ static constexpr bool value =
+ std::is_integral<X>::value || type_traits_impl::IsIntEnum<X>::value;
+};
+
+namespace test_enum_intlike {
+
+enum E1 { e1 };
+enum { e2 };
+enum class E3 { e3 };
+struct S {};
+
+static_assert(type_traits_impl::IsIntEnum<E1>::value, "");
+static_assert(type_traits_impl::IsIntEnum<decltype(e2)>::value, "");
+static_assert(!type_traits_impl::IsIntEnum<E3>::value, "");
+static_assert(!type_traits_impl::IsIntEnum<int>::value, "");
+static_assert(!type_traits_impl::IsIntEnum<float>::value, "");
+static_assert(!type_traits_impl::IsIntEnum<S>::value, "");
+
+static_assert(IsIntlike<E1>::value, "");
+static_assert(IsIntlike<decltype(e2)>::value, "");
+static_assert(!IsIntlike<E3>::value, "");
+static_assert(IsIntlike<int>::value, "");
+static_assert(!IsIntlike<float>::value, "");
+static_assert(!IsIntlike<S>::value, "");
+
+} // namespace test_enum_intlike
+
+} // namespace rtc
+
+#endif // RTC_BASE_TYPE_TRAITS_H_
diff --git a/webrtc/rtc_base/units/BUILD.gn b/webrtc/rtc_base/units/BUILD.gn
new file mode 100644
index 0000000..e2ab873
--- /dev/null
+++ b/webrtc/rtc_base/units/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can 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("unit_base") {
+ visibility = [
+ "../../api/units:*",
+ ":*",
+ ]
+ sources = [ "unit_base.h" ]
+
+ deps = [
+ "../../rtc_base:checks",
+ "../../rtc_base:safe_conversions",
+ ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("units_unittests") {
+ testonly = true
+ sources = [ "unit_base_unittest.cc" ]
+ deps = [
+ ":unit_base",
+ "../../test:test_support",
+ ]
+ }
+}
diff --git a/webrtc/rtc_base/units/unit_base.h b/webrtc/rtc_base/units/unit_base.h
new file mode 100644
index 0000000..7196bae
--- /dev/null
+++ b/webrtc/rtc_base/units/unit_base.h
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef RTC_BASE_UNITS_UNIT_BASE_H_
+#define RTC_BASE_UNITS_UNIT_BASE_H_
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_conversions.h"
+
+namespace webrtc {
+namespace rtc_units_impl {
+
+// UnitBase is a base class for implementing custom value types with a specific
+// unit. It provides type safety and commonly useful operations. The underlying
+// storage is always an int64_t, it's up to the unit implementation to choose
+// what scale it represents.
+//
+// It's used like:
+// class MyUnit: public UnitBase<MyUnit> {...};
+//
+// Unit_T is the subclass representing the specific unit.
+template <class Unit_T>
+class UnitBase {
+ public:
+ UnitBase() = delete;
+ static constexpr Unit_T Zero() { return Unit_T(0); }
+ static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); }
+ static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); }
+
+ constexpr bool IsZero() const { return value_ == 0; }
+ constexpr bool IsFinite() const { return !IsInfinite(); }
+ constexpr bool IsInfinite() const {
+ return value_ == PlusInfinityVal() || value_ == MinusInfinityVal();
+ }
+ constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); }
+ constexpr bool IsMinusInfinity() const {
+ return value_ == MinusInfinityVal();
+ }
+
+ constexpr bool operator==(const Unit_T& other) const {
+ return value_ == other.value_;
+ }
+ constexpr bool operator!=(const Unit_T& other) const {
+ return value_ != other.value_;
+ }
+ constexpr bool operator<=(const Unit_T& other) const {
+ return value_ <= other.value_;
+ }
+ constexpr bool operator>=(const Unit_T& other) const {
+ return value_ >= other.value_;
+ }
+ constexpr bool operator>(const Unit_T& other) const {
+ return value_ > other.value_;
+ }
+ constexpr bool operator<(const Unit_T& other) const {
+ return value_ < other.value_;
+ }
+ constexpr Unit_T RoundTo(const Unit_T& resolution) const {
+ RTC_DCHECK(IsFinite());
+ RTC_DCHECK(resolution.IsFinite());
+ RTC_DCHECK_GT(resolution.value_, 0);
+ return Unit_T((value_ + resolution.value_ / 2) / resolution.value_) *
+ resolution.value_;
+ }
+ constexpr Unit_T RoundUpTo(const Unit_T& resolution) const {
+ RTC_DCHECK(IsFinite());
+ RTC_DCHECK(resolution.IsFinite());
+ RTC_DCHECK_GT(resolution.value_, 0);
+ return Unit_T((value_ + resolution.value_ - 1) / resolution.value_) *
+ resolution.value_;
+ }
+ constexpr Unit_T RoundDownTo(const Unit_T& resolution) const {
+ RTC_DCHECK(IsFinite());
+ RTC_DCHECK(resolution.IsFinite());
+ RTC_DCHECK_GT(resolution.value_, 0);
+ return Unit_T(value_ / resolution.value_) * resolution.value_;
+ }
+
+ protected:
+ template <
+ typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+ static constexpr Unit_T FromValue(T value) {
+ if (Unit_T::one_sided)
+ RTC_DCHECK_GE(value, 0);
+ RTC_DCHECK_GT(value, MinusInfinityVal());
+ RTC_DCHECK_LT(value, PlusInfinityVal());
+ return Unit_T(rtc::dchecked_cast<int64_t>(value));
+ }
+ template <typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* =
+ nullptr>
+ static constexpr Unit_T FromValue(T value) {
+ if (value == std::numeric_limits<T>::infinity()) {
+ return PlusInfinity();
+ } else if (value == -std::numeric_limits<T>::infinity()) {
+ return MinusInfinity();
+ } else {
+ RTC_DCHECK(!std::isnan(value));
+ return FromValue(rtc::dchecked_cast<int64_t>(value));
+ }
+ }
+
+ template <
+ typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+ static constexpr Unit_T FromFraction(int64_t denominator, T value) {
+ if (Unit_T::one_sided)
+ RTC_DCHECK_GE(value, 0);
+ RTC_DCHECK_GT(value, MinusInfinityVal() / denominator);
+ RTC_DCHECK_LT(value, PlusInfinityVal() / denominator);
+ return Unit_T(rtc::dchecked_cast<int64_t>(value * denominator));
+ }
+ template <typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* =
+ nullptr>
+ static constexpr Unit_T FromFraction(int64_t denominator, T value) {
+ return FromValue(value * denominator);
+ }
+
+ template <typename T = int64_t>
+ constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
+ ToValue() const {
+ RTC_DCHECK(IsFinite());
+ return rtc::dchecked_cast<T>(value_);
+ }
+ template <typename T>
+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+ ToValue() const {
+ return IsPlusInfinity()
+ ? std::numeric_limits<T>::infinity()
+ : IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
+ : value_;
+ }
+ template <typename T>
+ constexpr T ToValueOr(T fallback_value) const {
+ return IsFinite() ? value_ : fallback_value;
+ }
+
+ template <int64_t Denominator, typename T = int64_t>
+ constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
+ ToFraction() const {
+ RTC_DCHECK(IsFinite());
+ if (Unit_T::one_sided) {
+ return rtc::dchecked_cast<T>(
+ DivRoundPositiveToNearest(value_, Denominator));
+ } else {
+ return rtc::dchecked_cast<T>(DivRoundToNearest(value_, Denominator));
+ }
+ }
+ template <int64_t Denominator, typename T>
+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+ ToFraction() const {
+ return ToValue<T>() * (1 / static_cast<T>(Denominator));
+ }
+
+ template <int64_t Denominator>
+ constexpr int64_t ToFractionOr(int64_t fallback_value) const {
+ return IsFinite() ? Unit_T::one_sided
+ ? DivRoundPositiveToNearest(value_, Denominator)
+ : DivRoundToNearest(value_, Denominator)
+ : fallback_value;
+ }
+
+ template <int64_t Factor, typename T = int64_t>
+ constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
+ ToMultiple() const {
+ RTC_DCHECK_GE(ToValue(), std::numeric_limits<T>::min() / Factor);
+ RTC_DCHECK_LE(ToValue(), std::numeric_limits<T>::max() / Factor);
+ return rtc::dchecked_cast<T>(ToValue() * Factor);
+ }
+ template <int64_t Factor, typename T>
+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+ ToMultiple() const {
+ return ToValue<T>() * Factor;
+ }
+
+ explicit constexpr UnitBase(int64_t value) : value_(value) {}
+
+ private:
+ template <class RelativeUnit_T>
+ friend class RelativeUnit;
+
+ static inline constexpr int64_t PlusInfinityVal() {
+ return std::numeric_limits<int64_t>::max();
+ }
+ static inline constexpr int64_t MinusInfinityVal() {
+ return std::numeric_limits<int64_t>::min();
+ }
+
+ constexpr Unit_T& AsSubClassRef() { return static_cast<Unit_T&>(*this); }
+ constexpr const Unit_T& AsSubClassRef() const {
+ return static_cast<const Unit_T&>(*this);
+ }
+ // Assumes that n >= 0 and d > 0.
+ static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) {
+ return (n + d / 2) / d;
+ }
+ // Assumes that d > 0.
+ static constexpr int64_t DivRoundToNearest(int64_t n, int64_t d) {
+ return (n + (n >= 0 ? d / 2 : -d / 2)) / d;
+ }
+
+ int64_t value_;
+};
+
+// Extends UnitBase to provide operations for relative units, that is, units
+// that have a meaningful relation between values such that a += b is a
+// sensible thing to do. For a,b <- same unit.
+template <class Unit_T>
+class RelativeUnit : public UnitBase<Unit_T> {
+ public:
+ constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const {
+ return std::max(min_value,
+ std::min(UnitBase<Unit_T>::AsSubClassRef(), max_value));
+ }
+ constexpr void Clamp(Unit_T min_value, Unit_T max_value) {
+ *this = Clamped(min_value, max_value);
+ }
+ constexpr Unit_T operator+(const Unit_T other) const {
+ if (this->IsPlusInfinity() || other.IsPlusInfinity()) {
+ RTC_DCHECK(!this->IsMinusInfinity());
+ RTC_DCHECK(!other.IsMinusInfinity());
+ return this->PlusInfinity();
+ } else if (this->IsMinusInfinity() || other.IsMinusInfinity()) {
+ RTC_DCHECK(!this->IsPlusInfinity());
+ RTC_DCHECK(!other.IsPlusInfinity());
+ return this->MinusInfinity();
+ }
+ return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue());
+ }
+ constexpr Unit_T operator-(const Unit_T other) const {
+ if (this->IsPlusInfinity() || other.IsMinusInfinity()) {
+ RTC_DCHECK(!this->IsMinusInfinity());
+ RTC_DCHECK(!other.IsPlusInfinity());
+ return this->PlusInfinity();
+ } else if (this->IsMinusInfinity() || other.IsPlusInfinity()) {
+ RTC_DCHECK(!this->IsPlusInfinity());
+ RTC_DCHECK(!other.IsMinusInfinity());
+ return this->MinusInfinity();
+ }
+ return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue());
+ }
+ constexpr Unit_T& operator+=(const Unit_T other) {
+ *this = *this + other;
+ return this->AsSubClassRef();
+ }
+ constexpr Unit_T& operator-=(const Unit_T other) {
+ *this = *this - other;
+ return this->AsSubClassRef();
+ }
+ constexpr double operator/(const Unit_T other) const {
+ return UnitBase<Unit_T>::template ToValue<double>() /
+ other.template ToValue<double>();
+ }
+ template <typename T>
+ constexpr typename std::enable_if<std::is_arithmetic<T>::value, Unit_T>::type
+ operator/(const T& scalar) const {
+ return UnitBase<Unit_T>::FromValue(
+ std::round(UnitBase<Unit_T>::template ToValue<int64_t>() / scalar));
+ }
+ constexpr Unit_T operator*(double scalar) const {
+ return UnitBase<Unit_T>::FromValue(std::round(this->ToValue() * scalar));
+ }
+ constexpr Unit_T operator*(int64_t scalar) const {
+ return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
+ }
+ constexpr Unit_T operator*(int32_t scalar) const {
+ return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
+ }
+
+ protected:
+ using UnitBase<Unit_T>::UnitBase;
+};
+
+template <class Unit_T>
+inline constexpr Unit_T operator*(double scalar, RelativeUnit<Unit_T> other) {
+ return other * scalar;
+}
+template <class Unit_T>
+inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit<Unit_T> other) {
+ return other * scalar;
+}
+template <class Unit_T>
+inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) {
+ return other * scalar;
+}
+
+} // namespace rtc_units_impl
+
+} // namespace webrtc
+
+#endif // RTC_BASE_UNITS_UNIT_BASE_H_
diff --git a/webrtc/rtc_base/win32.h b/webrtc/rtc_base/win32.h
new file mode 100644
index 0000000..c90296e
--- /dev/null
+++ b/webrtc/rtc_base/win32.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_BASE_WIN32_H_
+#define RTC_BASE_WIN32_H_
+
+#ifndef WEBRTC_WIN
+#error "Only #include this header in Windows builds"
+#endif
+
+// Make sure we don't get min/max macros
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+// clang-format off
+// clang formating would change include order.
+#include <winsock2.h> // must come first
+#include <windows.h>
+// clang-format on
+
+typedef int socklen_t;
+
+#ifndef SECURITY_MANDATORY_LABEL_AUTHORITY
+// Add defines that we use if we are compiling against older sdks
+#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
+#define TokenIntegrityLevel static_cast<TOKEN_INFORMATION_CLASS>(0x19)
+typedef struct _TOKEN_MANDATORY_LABEL {
+ SID_AND_ATTRIBUTES Label;
+} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
+#endif // SECURITY_MANDATORY_LABEL_AUTHORITY
+
+#undef SetPort
+
+#include <string>
+
+namespace rtc {
+
+const char* win32_inet_ntop(int af, const void* src, char* dst, socklen_t size);
+int win32_inet_pton(int af, const char* src, void* dst);
+
+enum WindowsMajorVersions {
+ kWindows2000 = 5,
+ kWindowsVista = 6,
+ kWindows10 = 10,
+};
+
+#if !defined(WINUWP)
+bool GetOsVersion(int* major, int* minor, int* build);
+
+inline bool IsWindowsVistaOrLater() {
+ int major;
+ return (GetOsVersion(&major, nullptr, nullptr) && major >= kWindowsVista);
+}
+
+inline bool IsWindowsXpOrLater() {
+ int major, minor;
+ return (GetOsVersion(&major, &minor, nullptr) &&
+ (major >= kWindowsVista || (major == kWindows2000 && minor >= 1)));
+}
+
+inline bool IsWindows8OrLater() {
+ int major, minor;
+ return (GetOsVersion(&major, &minor, nullptr) &&
+ (major > kWindowsVista || (major == kWindowsVista && minor >= 2)));
+}
+
+inline bool IsWindows10OrLater() {
+ int major;
+ return (GetOsVersion(&major, nullptr, nullptr) && (major >= kWindows10));
+}
+
+#else
+
+// When targetting WinUWP the OS must be Windows 10 (or greater) as lesser
+// Windows OS targets are not supported.
+inline bool IsWindowsVistaOrLater() {
+ return true;
+}
+
+inline bool IsWindowsXpOrLater() {
+ return true;
+}
+
+inline bool IsWindows8OrLater() {
+ return true;
+}
+
+inline bool IsWindows10OrLater() {
+ return true;
+}
+
+#endif // !defined(WINUWP)
+
+} // namespace rtc
+
+#endif // RTC_BASE_WIN32_H_
diff --git a/webrtc/rtc_base/zero_memory.cc b/webrtc/rtc_base/zero_memory.cc
new file mode 100644
index 0000000..b9c5b38
--- /dev/null
+++ b/webrtc/rtc_base/zero_memory.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright 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.
+ */
+
+#if defined(WEBRTC_WIN)
+#include <windows.h>
+#else
+#include <string.h>
+#endif
+
+#include "rtc_base/checks.h"
+#include "rtc_base/zero_memory.h"
+
+namespace rtc {
+
+// Code and comment taken from "OPENSSL_cleanse" of BoringSSL.
+void ExplicitZeroMemory(void* ptr, size_t len) {
+ RTC_DCHECK(ptr || !len);
+#if defined(WEBRTC_WIN)
+ SecureZeroMemory(ptr, len);
+#else
+ memset(ptr, 0, len);
+#if !defined(__pnacl__)
+ /* As best as we can tell, this is sufficient to break any optimisations that
+ might try to eliminate "superfluous" memsets. If there's an easy way to
+ detect memset_s, it would be better to use that. */
+ __asm__ __volatile__("" : : "r"(ptr) : "memory"); // NOLINT
+#endif
+#endif // !WEBRTC_WIN
+}
+
+} // namespace rtc
diff --git a/webrtc/rtc_base/zero_memory.h b/webrtc/rtc_base/zero_memory.h
new file mode 100644
index 0000000..b92f52f
--- /dev/null
+++ b/webrtc/rtc_base/zero_memory.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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 RTC_BASE_ZERO_MEMORY_H_
+#define RTC_BASE_ZERO_MEMORY_H_
+
+#include <stddef.h>
+
+#include <type_traits>
+
+#include "api/array_view.h"
+
+namespace rtc {
+
+// Fill memory with zeros in a way that the compiler doesn't optimize it away
+// even if the pointer is not used afterwards.
+void ExplicitZeroMemory(void* ptr, size_t len);
+
+template <typename T,
+ typename std::enable_if<!std::is_const<T>::value &&
+ std::is_trivial<T>::value>::type* = nullptr>
+void ExplicitZeroMemory(rtc::ArrayView<T> a) {
+ ExplicitZeroMemory(a.data(), a.size());
+}
+
+} // namespace rtc
+
+#endif // RTC_BASE_ZERO_MEMORY_H_
diff --git a/webrtc/system_wrappers/BUILD.gn b/webrtc/system_wrappers/BUILD.gn
index 2f68eae..b446648 100644
--- a/webrtc/system_wrappers/BUILD.gn
+++ b/webrtc/system_wrappers/BUILD.gn
@@ -6,218 +6,138 @@
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
-import("//build/config/android/config.gni")
-import("../build/webrtc.gni")
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+import("../webrtc.gni")
-static_library("system_wrappers") {
+rtc_library("system_wrappers") {
+ visibility = [ "*" ]
sources = [
- "include/aligned_array.h",
- "include/aligned_malloc.h",
- "include/atomic32.h",
"include/clock.h",
- "include/condition_variable_wrapper.h",
"include/cpu_features_wrapper.h",
"include/cpu_info.h",
- "include/critical_section_wrapper.h",
- "include/data_log.h",
- "include/data_log_c.h",
- "include/data_log_impl.h",
- "include/event_tracer.h",
- "include/event_wrapper.h",
- "include/field_trial.h",
- "include/file_wrapper.h",
- "include/fix_interlocked_exchange_pointer_win.h",
- "include/logging.h",
- "include/metrics.h",
- "include/ref_count.h",
- "include/rtp_to_ntp.h",
- "include/rw_lock_wrapper.h",
- "include/scoped_vector.h",
+ "include/ntp_time.h",
+ "include/rtp_to_ntp_estimator.h",
"include/sleep.h",
- "include/sort.h",
- "include/static_instance.h",
- "include/stl_util.h",
- "include/stringize_macros.h",
- "include/thread_wrapper.h",
- "include/tick_util.h",
- "include/timestamp_extrapolator.h",
- "include/trace.h",
- "include/utf_util_win.h",
- "source/aligned_malloc.cc",
- "source/atomic32_mac.cc",
- "source/atomic32_win.cc",
"source/clock.cc",
- "source/condition_variable.cc",
- "source/condition_variable_event_win.cc",
- "source/condition_variable_event_win.h",
- "source/condition_variable_native_win.cc",
- "source/condition_variable_native_win.h",
- "source/condition_variable_posix.cc",
- "source/condition_variable_posix.h",
"source/cpu_features.cc",
"source/cpu_info.cc",
- "source/critical_section.cc",
- "source/critical_section_posix.cc",
- "source/critical_section_posix.h",
- "source/critical_section_win.cc",
- "source/critical_section_win.h",
- "source/data_log_c.cc",
- "source/event.cc",
- "source/event_timer_posix.cc",
- "source/event_timer_posix.h",
- "source/event_timer_win.cc",
- "source/event_timer_win.h",
- "source/event_tracer.cc",
- "source/file_impl.cc",
- "source/file_impl.h",
- "source/logging.cc",
- "source/rtp_to_ntp.cc",
- "source/rw_lock.cc",
- "source/rw_lock_generic.cc",
- "source/rw_lock_generic.h",
- "source/rw_lock_posix.cc",
- "source/rw_lock_posix.h",
- "source/rw_lock_win.cc",
- "source/rw_lock_win.h",
+ "source/rtp_to_ntp_estimator.cc",
"source/sleep.cc",
- "source/sort.cc",
- "source/thread.cc",
- "source/thread_posix.cc",
- "source/thread_posix.h",
- "source/thread_win.cc",
- "source/thread_win.h",
- "source/tick_util.cc",
- "source/timestamp_extrapolator.cc",
- "source/trace_impl.cc",
- "source/trace_impl.h",
- "source/trace_posix.cc",
- "source/trace_posix.h",
- "source/trace_win.cc",
- "source/trace_win.h",
]
- configs += [ "..:common_config" ]
-
- public_configs = [ "..:common_inherited_config" ]
-
- if (rtc_enable_data_logging) {
- sources += [ "source/data_log.cc" ]
- } else {
- sources += [ "source/data_log_no_op.cc" ]
- }
-
defines = []
libs = []
deps = [
- "..:webrtc_common",
+ ":field_trial",
+ "../api:array_view",
+ "../api/units:timestamp",
+ "../modules:module_api_public",
+ "../rtc_base:checks",
+ "../rtc_base/synchronization:mutex",
+ "../rtc_base/synchronization:rw_lock_wrapper",
+ "../rtc_base/system:arch",
+ "../rtc_base/system:rtc_export",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
if (is_android) {
- sources += [
- "include/logcat_trace_context.h",
- "source/logcat_trace_context.cc",
- ]
-
- defines += [
- "WEBRTC_THREAD_RR",
-
- # TODO(leozwang): Investigate CLOCK_REALTIME and CLOCK_MONOTONIC
- # support on Android. Keep WEBRTC_CLOCK_TYPE_REALTIME for now,
- # remove it after I verify that CLOCK_MONOTONIC is fully functional
- # with condition and event functions in system_wrappers.
- "WEBRTC_CLOCK_TYPE_REALTIME",
- ]
-
- deps += [ ":cpu_features_android" ]
+ if (build_with_mozilla) {
+ include_dirs = [
+ "/config/external/nspr",
+ "/nsprpub/lib/ds",
+ "/nsprpub/pr/include",
+ ]
+ } else {
+ sources += [ "source/cpu_features_android.cc" ]
+ deps += [ "//third_party/android_sdk:cpu_features" ]
+ }
libs += [ "log" ]
}
- if (is_linux) {
- defines += [
- "WEBRTC_THREAD_RR",
- # TODO(andrew): can we select this automatically?
- # Define this if the Linux system does not support CLOCK_MONOTONIC.
- #"WEBRTC_CLOCK_TYPE_REALTIME",
- ]
+ if (is_linux || is_chromeos) {
+ if (!build_with_chromium) {
+ sources += [ "source/cpu_features_linux.cc" ]
+ }
libs += [ "rt" ]
}
- if (!is_mac && !is_ios) {
- sources += [ "source/atomic32_posix.cc" ]
- }
-
- if (is_ios || is_mac) {
- defines += [
- "WEBRTC_THREAD_RR",
- "WEBRTC_CLOCK_TYPE_REALTIME",
- ]
- }
-
- if (is_ios) {
- sources += [ "source/atomic32_mac.cc" ]
- }
-
if (is_win) {
libs += [ "winmm.lib" ]
- cflags = [
- "/wd4267", # size_t to int truncation.
- "/wd4334", # Ignore warning on shift operator promotion.
- ]
+ # Windows needs ../rtc_base due to include of
+ # webrtc/rtc_base/win32.h in source/clock.cc.
+ deps += [ "../rtc_base:win32" ]
}
- deps += [ "../base:rtc_base_approved" ]
-}
-
-source_set("field_trial_default") {
- sources = [
- "include/field_trial_default.h",
- "source/field_trial_default.cc",
- ]
-
- configs += [ "..:common_config" ]
- public_configs = [ "..:common_inherited_config" ]
-
- deps = [
- ":system_wrappers",
+ deps += [
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base:rtc_numerics",
]
}
-source_set("metrics_default") {
- sources = [
- "source/metrics_default.cc",
- ]
-
- configs += [ "..:common_config" ]
- public_configs = [ "..:common_inherited_config" ]
-
+rtc_library("field_trial") {
+ visibility = [ "*" ]
+ public = [ "include/field_trial.h" ]
+ sources = [ "source/field_trial.cc" ]
+ if (rtc_exclude_field_trial_default) {
+ defines = [ "WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT" ]
+ }
deps = [
- ":system_wrappers",
+ "../rtc_base:checks",
+ "../rtc_base:logging",
+ "../rtc_base:stringutils",
]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
}
-source_set("system_wrappers_default") {
- configs += [ "..:common_config" ]
- public_configs = [ "..:common_inherited_config" ]
-
+rtc_library("metrics") {
+ visibility = [ "*" ]
+ public = [ "include/metrics.h" ]
+ sources = [ "source/metrics.cc" ]
+ if (rtc_exclude_metrics_default) {
+ defines = [ "WEBRTC_EXCLUDE_METRICS_DEFAULT" ]
+ }
deps = [
- ":field_trial_default",
- ":metrics_default",
+ "../rtc_base:checks",
+ "../rtc_base:rtc_base_approved",
+ "../rtc_base/synchronization:mutex",
]
}
-if (is_android) {
- source_set("cpu_features_android") {
+if (rtc_include_tests) {
+ rtc_test("system_wrappers_unittests") {
+ testonly = true
sources = [
- "source/cpu_features_android.c",
+ "source/clock_unittest.cc",
+ "source/field_trial_unittest.cc",
+ "source/metrics_default_unittest.cc",
+ "source/metrics_unittest.cc",
+ "source/ntp_time_unittest.cc",
+ "source/rtp_to_ntp_estimator_unittest.cc",
]
- configs += [ "..:common_config" ]
- public_configs = [ "..:common_inherited_config" ]
deps = [
- "//third_party/android_tools:cpu_features",
+ ":field_trial",
+ ":metrics",
+ ":system_wrappers",
+ "../rtc_base:checks",
+ "../rtc_base:rtc_base_approved",
+ "../test:rtc_expect_death",
+ "../test:test_main",
+ "../test:test_support",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/strings",
]
+
+ if (is_android) {
+ deps += [ "//testing/android/native_test:native_test_support" ]
+
+ shard_timeout = 900
+ }
}
}
diff --git a/webrtc/system_wrappers/include/aligned_array.h b/webrtc/system_wrappers/include/aligned_array.h
deleted file mode 100644
index 7cd182c..0000000
--- a/webrtc/system_wrappers/include/aligned_array.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ALIGNED_ARRAY_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ALIGNED_ARRAY_
-
-#include "webrtc/base/checks.h"
-#include "webrtc/system_wrappers/include/aligned_malloc.h"
-
-namespace webrtc {
-
-// Wrapper class for aligned arrays. Every row (and the first dimension) are
-// aligned to the given byte alignment.
-template<typename T> class AlignedArray {
- public:
- AlignedArray(int rows, size_t cols, int alignment)
- : rows_(rows),
- cols_(cols),
- alignment_(alignment) {
- RTC_CHECK_GT(alignment_, 0);
- head_row_ = static_cast<T**>(AlignedMalloc(rows_ * sizeof(*head_row_),
- alignment_));
- for (int i = 0; i < rows_; ++i) {
- head_row_[i] = static_cast<T*>(AlignedMalloc(cols_ * sizeof(**head_row_),
- alignment_));
- }
- }
-
- ~AlignedArray() {
- for (int i = 0; i < rows_; ++i) {
- AlignedFree(head_row_[i]);
- }
- AlignedFree(head_row_);
- }
-
- T* const* Array() {
- return head_row_;
- }
-
- const T* const* Array() const {
- return head_row_;
- }
-
- T* Row(int row) {
- RTC_CHECK_LE(row, rows_);
- return head_row_[row];
- }
-
- const T* Row(int row) const {
- RTC_CHECK_LE(row, rows_);
- return head_row_[row];
- }
-
- T& At(int row, size_t col) {
- RTC_CHECK_LE(col, cols_);
- return Row(row)[col];
- }
-
- const T& At(int row, size_t col) const {
- RTC_CHECK_LE(col, cols_);
- return Row(row)[col];
- }
-
- int rows() const {
- return rows_;
- }
-
- size_t cols() const {
- return cols_;
- }
-
- private:
- int rows_;
- size_t cols_;
- int alignment_;
- T** head_row_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_ALIGNED_ARRAY_
diff --git a/webrtc/system_wrappers/include/condition_variable_wrapper.h b/webrtc/system_wrappers/include/condition_variable_wrapper.h
deleted file mode 100644
index 37ca30f..0000000
--- a/webrtc/system_wrappers/include/condition_variable_wrapper.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CONDITION_VARIABLE_WRAPPER_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CONDITION_VARIABLE_WRAPPER_H_
-
-namespace webrtc {
-
-class CriticalSectionWrapper;
-
-class ConditionVariableWrapper {
- public:
- // Factory method, constructor disabled.
- static ConditionVariableWrapper* CreateConditionVariable();
-
- virtual ~ConditionVariableWrapper() {}
-
- // Calling thread will atomically release crit_sect and wait until next
- // some other thread calls Wake() or WakeAll().
- virtual void SleepCS(CriticalSectionWrapper& crit_sect) = 0;
-
- // Same as above but with a timeout.
- virtual bool SleepCS(CriticalSectionWrapper& crit_sect,
- unsigned long max_time_in_ms) = 0;
-
- // Wakes one thread calling SleepCS().
- virtual void Wake() = 0;
-
- // Wakes all threads calling SleepCS().
- virtual void WakeAll() = 0;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CONDITION_VARIABLE_WRAPPER_H_
diff --git a/webrtc/system_wrappers/include/cpu_features_wrapper.h b/webrtc/system_wrappers/include/cpu_features_wrapper.h
index 9838d94..612b4a5 100644
--- a/webrtc/system_wrappers/include/cpu_features_wrapper.h
+++ b/webrtc/system_wrappers/include/cpu_features_wrapper.h
@@ -8,44 +8,35 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
+#ifndef SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
+#define SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include <stdint.h>
-#include "webrtc/typedefs.h"
+namespace webrtc {
// List of features in x86.
-typedef enum {
- kSSE2,
- kSSE3
-} CPUFeature;
+typedef enum { kSSE2, kSSE3, kAVX2 } CPUFeature;
// List of features in ARM.
enum {
- kCPUFeatureARMv7 = (1 << 0),
- kCPUFeatureVFPv3 = (1 << 1),
- kCPUFeatureNEON = (1 << 2),
- kCPUFeatureLDREXSTREX = (1 << 3)
+ kCPUFeatureARMv7 = (1 << 0),
+ kCPUFeatureVFPv3 = (1 << 1),
+ kCPUFeatureNEON = (1 << 2),
+ kCPUFeatureLDREXSTREX = (1 << 3)
};
-typedef int (*WebRtc_CPUInfo)(CPUFeature feature);
-
// Returns true if the CPU supports the feature.
-extern WebRtc_CPUInfo WebRtc_GetCPUInfo;
+int GetCPUInfo(CPUFeature feature);
// No CPU feature is available => straight C path.
-extern WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM;
+int GetCPUInfoNoASM(CPUFeature feature);
// Return the features in an ARM device.
// It detects the features in the hardware platform, and returns supported
// values in the above enum definition as a bitmask.
-extern uint64_t WebRtc_GetCPUFeaturesARM(void);
+uint64_t GetCPUFeaturesARM(void);
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+} // namespace webrtc
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
+#endif // SYSTEM_WRAPPERS_INCLUDE_CPU_FEATURES_WRAPPER_H_
diff --git a/webrtc/system_wrappers/include/critical_section_wrapper.h b/webrtc/system_wrappers/include/critical_section_wrapper.h
deleted file mode 100644
index 7dd217e..0000000
--- a/webrtc/system_wrappers/include/critical_section_wrapper.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CRITICAL_SECTION_WRAPPER_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CRITICAL_SECTION_WRAPPER_H_
-
-// If the critical section is heavily contended it may be beneficial to use
-// read/write locks instead.
-
-#include "webrtc/base/thread_annotations.h"
-#include "webrtc/common_types.h"
-
-namespace webrtc {
-class LOCKABLE CriticalSectionWrapper {
- public:
- // Factory method, constructor disabled
- static CriticalSectionWrapper* CreateCriticalSection();
-
- virtual ~CriticalSectionWrapper() {}
-
- // Tries to grab lock, beginning of a critical section. Will wait for the
- // lock to become available if the grab failed.
- virtual void Enter() EXCLUSIVE_LOCK_FUNCTION() = 0;
-
- // Returns a grabbed lock, end of critical section.
- virtual void Leave() UNLOCK_FUNCTION() = 0;
-};
-
-// RAII extension of the critical section. Prevents Enter/Leave mismatches and
-// provides more compact critical section syntax.
-class SCOPED_LOCKABLE CriticalSectionScoped {
- public:
- explicit CriticalSectionScoped(CriticalSectionWrapper* critsec)
- EXCLUSIVE_LOCK_FUNCTION(critsec)
- : ptr_crit_sec_(critsec) {
- ptr_crit_sec_->Enter();
- }
-
- ~CriticalSectionScoped() UNLOCK_FUNCTION() { ptr_crit_sec_->Leave(); }
-
- private:
- CriticalSectionWrapper* ptr_crit_sec_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_CRITICAL_SECTION_WRAPPER_H_
diff --git a/webrtc/system_wrappers/include/event_wrapper.h b/webrtc/system_wrappers/include/event_wrapper.h
deleted file mode 100644
index cc3722b..0000000
--- a/webrtc/system_wrappers/include/event_wrapper.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_INCLUDE_EVENT_WRAPPER_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_EVENT_WRAPPER_H_
-
-namespace webrtc {
-enum EventTypeWrapper {
- kEventSignaled = 1,
- kEventError = 2,
- kEventTimeout = 3
-};
-
-#define WEBRTC_EVENT_INFINITE 0xffffffff
-
-class EventTimerWrapper;
-
-class EventWrapper {
- public:
- // Factory method. Constructor disabled.
- static EventWrapper* Create();
-
- virtual ~EventWrapper() {}
-
- // Releases threads who are calling Wait() and has started waiting. Please
- // note that a thread calling Wait() will not start waiting immediately.
- // assumptions to the contrary is a very common source of issues in
- // multithreaded programming.
- // Set is sticky in the sense that it will release at least one thread
- // either immediately or some time in the future.
- virtual bool Set() = 0;
-
- // Puts the calling thread into a wait state. The thread may be released
- // by a Set() call depending on if other threads are waiting and if so on
- // timing. The thread that was released will reset the event before leaving
- // preventing more threads from being released. If multiple threads
- // are waiting for the same Set(), only one (random) thread is guaranteed to
- // be released. It is possible that multiple (random) threads are released
- // Depending on timing.
- //
- // |max_time| is the maximum time to wait in milliseconds or
- // WEBRTC_EVENT_INFINITE to wait infinitely.
- virtual EventTypeWrapper Wait(unsigned long max_time) = 0;
-};
-
-class EventTimerWrapper : public EventWrapper {
- public:
- static EventTimerWrapper* Create();
-
- // Starts a timer that will call a non-sticky version of Set() either once
- // or periodically. If the timer is periodic it ensures that there is no
- // drift over time relative to the system clock.
- //
- // |time| is in milliseconds.
- virtual bool StartTimer(bool periodic, unsigned long time) = 0;
-
- virtual bool StopTimer() = 0;
-
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_EVENT_WRAPPER_H_
diff --git a/webrtc/system_wrappers/include/field_trial.h b/webrtc/system_wrappers/include/field_trial.h
new file mode 100644
index 0000000..52db33b
--- /dev/null
+++ b/webrtc/system_wrappers/include/field_trial.h
@@ -0,0 +1,102 @@
+//
+// 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 SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_
+#define SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_
+
+#include <string>
+
+// Field trials allow webrtc clients (such as Chrome) to turn on feature code
+// in binaries out in the field and gather information with that.
+//
+// By default WebRTC provides an implementation of field trials that can be
+// found in system_wrappers/source/field_trial.cc. If clients want to provide
+// a custom version, they will have to:
+//
+// 1. Compile WebRTC defining the preprocessor macro
+// WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT (if GN is used this can be achieved
+// by setting the GN arg rtc_exclude_field_trial_default to true).
+// 2. Provide an implementation of:
+// std::string webrtc::field_trial::FindFullName(const std::string& trial).
+//
+// They are designed to wire up directly to chrome field trials and to speed up
+// developers by reducing the need to wire APIs to control whether a feature is
+// on/off. E.g. to experiment with a new method that could lead to a different
+// trade-off between CPU/bandwidth:
+//
+// 1 - Develop the feature with default behaviour off:
+//
+// if (FieldTrial::FindFullName("WebRTCExperimentMethod2") == "Enabled")
+// method2();
+// else
+// method1();
+//
+// 2 - Once the changes are rolled to chrome, the new code path can be
+// controlled as normal chrome field trials.
+//
+// 3 - Evaluate the new feature and clean the code paths.
+//
+// Notes:
+// - NOT every feature is a candidate to be controlled by this mechanism as
+// it may require negotiation between involved parties (e.g. SDP).
+//
+// TODO(andresp): since chrome --force-fieldtrials does not marks the trial
+// as active it does not get propagated to the renderer process. For now one
+// needs to push a config with start_active:true or run a local finch
+// server.
+//
+// TODO(andresp): find out how to get bots to run tests with trials enabled.
+
+namespace webrtc {
+namespace field_trial {
+
+// Returns the group name chosen for the named trial, or the empty string
+// if the trial does not exists.
+//
+// Note: To keep things tidy append all the trial names with WebRTC.
+std::string FindFullName(const std::string& name);
+
+// Convenience method, returns true iff FindFullName(name) return a string that
+// starts with "Enabled".
+// TODO(tommi): Make sure all implementations support this.
+inline bool IsEnabled(const char* name) {
+ return FindFullName(name).find("Enabled") == 0;
+}
+
+// Convenience method, returns true iff FindFullName(name) return a string that
+// starts with "Disabled".
+inline bool IsDisabled(const char* name) {
+ return FindFullName(name).find("Disabled") == 0;
+}
+
+// Optionally initialize field trial from a string.
+// This method can be called at most once before any other call into webrtc.
+// E.g. before the peer connection factory is constructed.
+// Note: trials_string must never be destroyed.
+void InitFieldTrialsFromString(const char* trials_string);
+
+const char* GetFieldTrialString();
+
+#ifndef WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
+// Validates the given field trial string.
+bool FieldTrialsStringIsValid(const char* trials_string);
+
+// Merges two field trial strings.
+//
+// If a key (trial) exists twice with conflicting values (groups), the value
+// in 'second' takes precedence.
+// Shall only be called with valid FieldTrial strings.
+std::string MergeFieldTrialsStrings(const char* first, const char* second);
+#endif // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
+
+} // namespace field_trial
+} // namespace webrtc
+
+#endif // SYSTEM_WRAPPERS_INCLUDE_FIELD_TRIAL_H_
diff --git a/webrtc/system_wrappers/include/file_wrapper.h b/webrtc/system_wrappers/include/file_wrapper.h
deleted file mode 100644
index b32a62f..0000000
--- a/webrtc/system_wrappers/include/file_wrapper.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_INCLUDE_FILE_WRAPPER_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_FILE_WRAPPER_H_
-
-#include <stddef.h>
-#include <stdio.h>
-
-#include "webrtc/common_types.h"
-#include "webrtc/typedefs.h"
-
-// Implementation of an InStream and OutStream that can read (exclusive) or
-// write from/to a file.
-
-namespace webrtc {
-
-class FileWrapper : public InStream, public OutStream {
- public:
- static const size_t kMaxFileNameSize = 1024;
-
- // Factory method. Constructor disabled.
- static FileWrapper* Create();
-
- // Returns true if a file has been opened.
- virtual bool Open() const = 0;
-
- // Opens a file in read or write mode, decided by the read_only parameter.
- virtual int OpenFile(const char* file_name_utf8,
- bool read_only,
- bool loop = false,
- bool text = false) = 0;
-
- // Initializes the wrapper from an existing handle. |read_only| must match in
- // the mode the file was opened in. If |manage_file| is true, the wrapper
- // takes ownership of |handle| and closes it in CloseFile().
- virtual int OpenFromFileHandle(FILE* handle,
- bool manage_file,
- bool read_only,
- bool loop = false) = 0;
-
- virtual int CloseFile() = 0;
-
- // Limits the file size to |bytes|. Writing will fail after the cap
- // is hit. Pass zero to use an unlimited size.
- virtual int SetMaxFileSize(size_t bytes) = 0;
-
- // Flush any pending writes.
- virtual int Flush() = 0;
-
- // Returns the opened file's name in |file_name_utf8|. Provide the size of
- // the buffer in bytes in |size|. The name will be truncated if |size| is
- // too small.
- virtual int FileName(char* file_name_utf8,
- size_t size) const = 0;
-
- // Write |format| to the opened file. Arguments are taken in the same manner
- // as printf. That is, supply a format string containing text and
- // specifiers. Returns the number of characters written or -1 on error.
- virtual int WriteText(const char* format, ...) = 0;
-
- // Inherited from both Instream and OutStream.
- // Rewinds the file to the start. Only available when OpenFile() has been
- // called with |loop| == true or |readOnly| == true.
- // virtual int Rewind() = 0;
- int Rewind() override;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_FILE_WRAPPER_H_
diff --git a/webrtc/system_wrappers/include/fix_interlocked_exchange_pointer_win.h b/webrtc/system_wrappers/include/fix_interlocked_exchange_pointer_win.h
deleted file mode 100644
index 8fb32ef..0000000
--- a/webrtc/system_wrappers/include/fix_interlocked_exchange_pointer_win.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Various inline functions and macros to fix compilation of 32 bit target
-// on MSVC with /Wp64 flag enabled.
-
-// The original code can be found here:
-// http://src.chromium.org/svn/trunk/src/base/fix_wp64.h
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_
-
-#include <windows.h>
-
-// Platform SDK fixes when building with /Wp64 for a 32 bits target.
-#if !defined(_WIN64) && defined(_Wp64)
-
-#ifdef InterlockedExchangePointer
-#undef InterlockedExchangePointer
-// The problem is that the macro provided for InterlockedExchangePointer() is
-// doing a (LONG) C-style cast that triggers invariably the warning C4312 when
-// building on 32 bits.
-inline void* InterlockedExchangePointer(void* volatile* target, void* value) {
- return reinterpret_cast<void*>(static_cast<LONG_PTR>(InterlockedExchange(
- reinterpret_cast<volatile LONG*>(target),
- static_cast<LONG>(reinterpret_cast<LONG_PTR>(value)))));
-}
-#endif // #ifdef InterlockedExchangePointer
-
-#endif // #if !defined(_WIN64) && defined(_Wp64)
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_
diff --git a/webrtc/system_wrappers/include/logging.h b/webrtc/system_wrappers/include/logging.h
deleted file mode 100644
index 2b53f4f..0000000
--- a/webrtc/system_wrappers/include/logging.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// This is a highly stripped-down version of libjingle's talk/base/logging.h.
-// It is a thin wrapper around WEBRTC_TRACE, maintaining the libjingle log
-// semantics to ease a transition to that format.
-
-// NOTE: LS_INFO maps to a new trace level which should be reserved for
-// infrequent, non-verbose logs. The other levels below kTraceWarning have been
-// rendered essentially useless due to their verbosity. Carefully consider the
-// impact of adding a new LS_INFO log. If it will be logged at anything
-// approaching a frame or packet frequency, use LS_VERBOSE if necessary, or
-// preferably, do not log at all.
-
-// LOG(...) an ostream target that can be used to send formatted
-// output to a variety of logging targets, such as debugger console, stderr,
-// file, or any StreamInterface.
-// The severity level passed as the first argument to the LOGging
-// functions is used as a filter, to limit the verbosity of the logging.
-// Static members of LogMessage documented below are used to control the
-// verbosity and target of the output.
-// There are several variations on the LOG macro which facilitate logging
-// of common error conditions, detailed below.
-
-// LOG(sev) logs the given stream at severity "sev", which must be a
-// compile-time constant of the LoggingSeverity type, without the namespace
-// prefix.
-// LOG_V(sev) Like LOG(), but sev is a run-time variable of the LoggingSeverity
-// type (basically, it just doesn't prepend the namespace).
-// LOG_F(sev) Like LOG(), but includes the name of the current function.
-
-// Additional helper macros added by WebRTC:
-// LOG_API is a shortcut for API call logging. Pass in the input parameters of
-// the method. For example:
-// Foo(int bar, int baz) {
-// LOG_API2(bar, baz);
-// }
-//
-// LOG_FERR is a shortcut for logging a failed function call. For example:
-// if (!Foo(bar)) {
-// LOG_FERR1(LS_WARNING, Foo, bar);
-// }
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_LOGGING_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_LOGGING_H_
-
-#include <sstream>
-
-namespace webrtc {
-
-//////////////////////////////////////////////////////////////////////
-
-// Note that the non-standard LoggingSeverity aliases exist because they are
-// still in broad use. The meanings of the levels are:
-// LS_SENSITIVE: Information which should only be logged with the consent
-// of the user, due to privacy concerns.
-// LS_VERBOSE: This level is for data which we do not want to appear in the
-// normal debug log, but should appear in diagnostic logs.
-// LS_INFO: Chatty level used in debugging for all sorts of things, the default
-// in debug builds.
-// LS_WARNING: Something that may warrant investigation.
-// LS_ERROR: Something that should not have occurred.
-enum LoggingSeverity {
- LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR
-};
-
-class LogMessage {
- public:
- LogMessage(const char* file, int line, LoggingSeverity sev);
- ~LogMessage();
-
- static bool Loggable(LoggingSeverity sev);
- std::ostream& stream() { return print_stream_; }
-
- private:
- // The ostream that buffers the formatted message before output
- std::ostringstream print_stream_;
-
- // The severity level of this message
- LoggingSeverity severity_;
-};
-
-//////////////////////////////////////////////////////////////////////
-// Macros which automatically disable logging when WEBRTC_LOGGING == 0
-//////////////////////////////////////////////////////////////////////
-
-#ifndef LOG
-// The following non-obvious technique for implementation of a
-// conditional log stream was stolen from google3/base/logging.h.
-
-// This class is used to explicitly ignore values in the conditional
-// logging macros. This avoids compiler warnings like "value computed
-// is not used" and "statement has no effect".
-
-class LogMessageVoidify {
- public:
- LogMessageVoidify() { }
- // This has to be an operator with a precedence lower than << but
- // higher than ?:
- void operator&(std::ostream&) { }
-};
-
-#if defined(WEBRTC_RESTRICT_LOGGING)
-// This should compile away logs matching the following condition.
-#define RESTRICT_LOGGING_PRECONDITION(sev) \
- sev < webrtc::LS_INFO ? (void) 0 :
-#else
-#define RESTRICT_LOGGING_PRECONDITION(sev)
-#endif
-
-#define LOG_SEVERITY_PRECONDITION(sev) \
- RESTRICT_LOGGING_PRECONDITION(sev) !(webrtc::LogMessage::Loggable(sev)) \
- ? (void) 0 \
- : webrtc::LogMessageVoidify() &
-
-#define LOG(sev) \
- LOG_SEVERITY_PRECONDITION(webrtc::sev) \
- webrtc::LogMessage(__FILE__, __LINE__, webrtc::sev).stream()
-
-// The _V version is for when a variable is passed in. It doesn't do the
-// namespace concatination.
-#define LOG_V(sev) \
- LOG_SEVERITY_PRECONDITION(sev) \
- webrtc::LogMessage(__FILE__, __LINE__, sev).stream()
-
-// The _F version prefixes the message with the current function name.
-#if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F)
-#define LOG_F(sev) LOG(sev) << __PRETTY_FUNCTION__ << ": "
-#else
-#define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": "
-#endif
-
-#define LOG_API0() LOG_F(LS_VERBOSE)
-#define LOG_API1(v1) LOG_API0() << #v1 << "=" << v1
-#define LOG_API2(v1, v2) LOG_API1(v1) \
- << ", " << #v2 << "=" << v2
-#define LOG_API3(v1, v2, v3) LOG_API2(v1, v2) \
- << ", " << #v3 << "=" << v3
-
-#define LOG_FERR0(sev, func) LOG(sev) << #func << " failed"
-#define LOG_FERR1(sev, func, v1) LOG_FERR0(sev, func) \
- << ": " << #v1 << "=" << v1
-#define LOG_FERR2(sev, func, v1, v2) LOG_FERR1(sev, func, v1) \
- << ", " << #v2 << "=" << v2
-#define LOG_FERR3(sev, func, v1, v2, v3) LOG_FERR2(sev, func, v1, v2) \
- << ", " << #v3 << "=" << v3
-#define LOG_FERR4(sev, func, v1, v2, v3, v4) LOG_FERR3(sev, func, v1, v2, v3) \
- << ", " << #v4 << "=" << v4
-
-#endif // LOG
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_LOGGING_H_
diff --git a/webrtc/system_wrappers/include/metrics.h b/webrtc/system_wrappers/include/metrics.h
index 2e6e7b7..8e0f084 100644
--- a/webrtc/system_wrappers/include/metrics.h
+++ b/webrtc/system_wrappers/include/metrics.h
@@ -8,13 +8,51 @@
// be found in the AUTHORS file in the root of the source tree.
//
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
+#ifndef SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
+#define SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
+#include <stddef.h>
+
+#include <map>
+#include <memory>
#include <string>
-#include "webrtc/common_types.h"
+#include "rtc_base/atomic_ops.h"
+#include "rtc_base/checks.h"
+
+#if defined(RTC_DISABLE_METRICS)
+#define RTC_METRICS_ENABLED 0
+#else
+#define RTC_METRICS_ENABLED 1
+#endif
+
+namespace webrtc {
+namespace metrics_impl {
+template <typename... Ts>
+void NoOp(const Ts&...) {}
+}
+}
+
+#if RTC_METRICS_ENABLED
+#define EXPECT_METRIC_EQ(val1, val2) EXPECT_EQ(val1, val2)
+#define EXPECT_METRIC_EQ_WAIT(val1, val2, timeout) \
+ EXPECT_EQ_WAIT(val1, val2, timeout)
+#define EXPECT_METRIC_GT(val1, val2) EXPECT_GT(val1, val2)
+#define EXPECT_METRIC_LE(val1, val2) EXPECT_LE(val1, val2)
+#define EXPECT_METRIC_TRUE(conditon) EXPECT_TRUE(conditon)
+#define EXPECT_METRIC_FALSE(conditon) EXPECT_FALSE(conditon)
+#define EXPECT_METRIC_THAT(value, matcher) EXPECT_THAT(value, matcher)
+#else
+#define EXPECT_METRIC_EQ(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
+#define EXPECT_METRIC_EQ_WAIT(val1, val2, timeout) webrtc::metrics_impl::NoOp(val1, val2, timeout)
+#define EXPECT_METRIC_GT(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
+#define EXPECT_METRIC_LE(val1, val2) webrtc::metrics_impl::NoOp(val1, val2)
+#define EXPECT_METRIC_TRUE(condition) webrtc::metrics_impl::NoOp(condition || true)
+#define EXPECT_METRIC_FALSE(condition) webrtc::metrics_impl::NoOp(condition && false)
+#define EXPECT_METRIC_THAT(value, matcher) webrtc::metrics_impl::NoOp(value, testing::_)
+#endif
+#if RTC_METRICS_ENABLED
// Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate
// statistics.
//
@@ -29,20 +67,21 @@
// The macros use the methods HistogramFactoryGetCounts,
// HistogramFactoryGetEnumeration and HistogramAdd.
//
-// Therefore, WebRTC clients must either:
-//
-// - provide implementations of
-// Histogram* webrtc::metrics::HistogramFactoryGetCounts(
-// const std::string& name, int sample, int min, int max,
-// int bucket_count);
-// Histogram* webrtc::metrics::HistogramFactoryGetEnumeration(
-// const std::string& name, int sample, int boundary);
-// void webrtc::metrics::HistogramAdd(
-// Histogram* histogram_pointer, const std::string& name, int sample);
-//
-// - or link with the default implementations (i.e.
-// system_wrappers/system_wrappers.gyp:metrics_default).
+// By default WebRTC provides implementations of the aforementioned methods
+// that can be found in system_wrappers/source/metrics.cc. If clients want to
+// provide a custom version, they will have to:
//
+// 1. Compile WebRTC defining the preprocessor macro
+// WEBRTC_EXCLUDE_METRICS_DEFAULT (if GN is used this can be achieved
+// by setting the GN arg rtc_exclude_metrics_default to true).
+// 2. Provide implementations of:
+// Histogram* webrtc::metrics::HistogramFactoryGetCounts(
+// const std::string& name, int sample, int min, int max,
+// int bucket_count);
+// Histogram* webrtc::metrics::HistogramFactoryGetEnumeration(
+// const std::string& name, int sample, int boundary);
+// void webrtc::metrics::HistogramAdd(
+// Histogram* histogram_pointer, const std::string& name, int sample);
//
// Example usage:
//
@@ -55,57 +94,270 @@
// };
//
// RTC_HISTOGRAM_ENUMERATION("WebRTC.Types", kTypeX, kBoundary);
-
+//
+// NOTE: It is recommended to do the Chromium review for modifications to
+// histograms.xml before new metrics are committed to WebRTC.
// Macros for adding samples to a named histogram.
+
+// Histogram for counters (exponentially spaced buckets).
+#define RTC_HISTOGRAM_COUNTS_100(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50)
+
+#define RTC_HISTOGRAM_COUNTS_200(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50)
+
+#define RTC_HISTOGRAM_COUNTS_500(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50)
+
+#define RTC_HISTOGRAM_COUNTS_1000(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_10000(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_100000(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50)
+
+#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
+ RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
+ webrtc::metrics::HistogramFactoryGetCounts( \
+ name, min, max, bucket_count))
+
+#define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count) \
+ RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
+ webrtc::metrics::HistogramFactoryGetCountsLinear( \
+ name, min, max, bucket_count))
+
+// Slow metrics: pointer to metric is acquired at each call and is not cached.
//
-// NOTE: this is a temporary solution.
-// The aim is to mimic the behaviour in Chromium's src/base/metrics/histograms.h
-// However as atomics are not supported in webrtc, this is for now a modified
-// and temporary solution. Note that the histogram is constructed/found for
-// each call. Therefore, for now only use this implementation for metrics
-// that do not need to be updated frequently.
-// TODO(asapersson): Change implementation when atomics are supported.
-// Also consider changing string to const char* when switching to atomics.
+#define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100, 50)
-// Histogram for counters.
-#define RTC_HISTOGRAM_COUNTS_100(name, sample) RTC_HISTOGRAM_COUNTS( \
- name, sample, 1, 100, 50)
+#define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 200, 50)
-#define RTC_HISTOGRAM_COUNTS_200(name, sample) RTC_HISTOGRAM_COUNTS( \
- name, sample, 1, 200, 50)
+#define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 500, 50)
-#define RTC_HISTOGRAM_COUNTS_1000(name, sample) RTC_HISTOGRAM_COUNTS( \
- name, sample, 1, 1000, 50)
+#define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 1000, 50)
-#define RTC_HISTOGRAM_COUNTS_10000(name, sample) RTC_HISTOGRAM_COUNTS( \
- name, sample, 1, 10000, 50)
+#define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 10000, 50)
-#define RTC_HISTOGRAM_COUNTS_100000(name, sample) RTC_HISTOGRAM_COUNTS( \
- name, sample, 1, 100000, 50)
+#define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) \
+ RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100000, 50)
-#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
- RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
- webrtc::metrics::HistogramFactoryGetCounts( \
- name, min, max, bucket_count))
+#define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \
+ RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, \
+ webrtc::metrics::HistogramFactoryGetCounts( \
+ name, min, max, bucket_count))
+
+// Histogram for percentage (evenly spaced buckets).
+#define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) \
+ RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 101)
+
+// Histogram for booleans.
+#define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) \
+ RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 2)
+
+// Histogram for enumerators (evenly spaced buckets).
+// |boundary| should be above the max enumerator sample.
+//
+// TODO(qingsi): Refactor the default implementation given by RtcHistogram,
+// which is already sparse, and remove the boundary argument from the macro.
+#define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
+ RTC_HISTOGRAM_COMMON_BLOCK_SLOW( \
+ name, sample, \
+ webrtc::metrics::SparseHistogramFactoryGetEnumeration(name, boundary))
-// Histogram for percentage.
+// Histogram for percentage (evenly spaced buckets).
#define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
- RTC_HISTOGRAM_ENUMERATION(name, sample, 101)
+ RTC_HISTOGRAM_ENUMERATION(name, sample, 101)
-// Histogram for enumerators.
+// Histogram for booleans.
+#define RTC_HISTOGRAM_BOOLEAN(name, sample) \
+ RTC_HISTOGRAM_ENUMERATION(name, sample, 2)
+
+// Histogram for enumerators (evenly spaced buckets).
// |boundary| should be above the max enumerator sample.
#define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
- RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
- webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
+ RTC_HISTOGRAM_COMMON_BLOCK_SLOW( \
+ name, sample, \
+ webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
-#define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \
- factory_get_invocation) \
- do { \
- webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation; \
- webrtc::metrics::HistogramAdd(histogram_pointer, constant_name, sample); \
+// The name of the histogram should not vary.
+// TODO(asapersson): Consider changing string to const char*.
+#define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \
+ factory_get_invocation) \
+ do { \
+ static webrtc::metrics::Histogram* atomic_histogram_pointer = nullptr; \
+ webrtc::metrics::Histogram* histogram_pointer = \
+ rtc::AtomicOps::AcquireLoadPtr(&atomic_histogram_pointer); \
+ if (!histogram_pointer) { \
+ histogram_pointer = factory_get_invocation; \
+ webrtc::metrics::Histogram* prev_pointer = \
+ rtc::AtomicOps::CompareAndSwapPtr( \
+ &atomic_histogram_pointer, \
+ static_cast<webrtc::metrics::Histogram*>(nullptr), \
+ histogram_pointer); \
+ RTC_DCHECK(prev_pointer == nullptr || \
+ prev_pointer == histogram_pointer); \
+ } \
+ if (histogram_pointer) { \
+ webrtc::metrics::HistogramAdd(histogram_pointer, sample); \
+ } \
+ } while (0)
+
+// The histogram is constructed/found for each call.
+// May be used for histograms with infrequent updates.`
+#define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
+ do { \
+ webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation; \
+ if (histogram_pointer) { \
+ webrtc::metrics::HistogramAdd(histogram_pointer, sample); \
+ } \
} while (0)
+// Helper macros.
+// Macros for calling a histogram with varying name (e.g. when using a metric
+// in different modes such as real-time vs screenshare). Fast, because pointer
+// is cached. |index| should be different for different names. Allowed |index|
+// values are 0, 1, and 2.
+#define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 500, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50))
+
+#define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50))
+
+#define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_ENUMERATION(name, sample, boundary))
+
+#define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) \
+ RTC_HISTOGRAMS_COMMON(index, name, sample, \
+ RTC_HISTOGRAM_PERCENTAGE(name, sample))
+
+#define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \
+ do { \
+ switch (index) { \
+ case 0: \
+ macro_invocation; \
+ break; \
+ case 1: \
+ macro_invocation; \
+ break; \
+ case 2: \
+ macro_invocation; \
+ break; \
+ default: \
+ RTC_NOTREACHED(); \
+ } \
+ } while (0)
+
+#else
+
+////////////////////////////////////////////////////////////////////////////////
+// This section defines no-op alternatives to the metrics macros when
+// RTC_METRICS_ENABLED is defined.
+
+#define RTC_HISTOGRAM_COUNTS_100(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_200(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_500(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_1000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_10000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_100000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
+ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
+
+#define RTC_HISTOGRAM_COUNTS_LINEAR(name, sample, min, max, bucket_count) \
+ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_200(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_500(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_1000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_10000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE_100000(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \
+ webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
+
+#define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_BOOLEAN_SPARSE(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
+ webrtc::metrics_impl::NoOp(name, sample, boundary)
+
+#define RTC_HISTOGRAM_PERCENTAGE(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_BOOLEAN(name, sample) webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
+ webrtc::metrics_impl::NoOp(name, sample, boundary)
+
+#define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \
+ factory_get_invocation) \
+ webrtc::metrics_impl::NoOp(constant_name, sample, factory_get_invocation)
+
+#define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
+ webrtc::metrics_impl::NoOp(name, sample, factory_get_invocation)
+
+#define RTC_HISTOGRAMS_COUNTS_100(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_200(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_500(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_1000(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_10000(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COUNTS_100000(index, name, sample) \
+ webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_ENUMERATION(index, name, sample, boundary) \
+ webrtc::metrics_impl::NoOp(index, name, sample, boundary)
+
+#define RTC_HISTOGRAMS_PERCENTAGE(index, name, sample) webrtc::metrics_impl::NoOp(index, name, sample)
+
+#define RTC_HISTOGRAMS_COMMON(index, name, sample, macro_invocation) \
+ webrtc::metrics_impl::NoOp(index, name, sample, macro_invocation)
+
+#endif // RTC_METRICS_ENABLED
namespace webrtc {
namespace metrics {
@@ -119,21 +371,68 @@ class Histogram;
// histogram).
// Get histogram for counters.
-Histogram* HistogramFactoryGetCounts(
- const std::string& name, int min, int max, int bucket_count);
+Histogram* HistogramFactoryGetCounts(const std::string& name,
+ int min,
+ int max,
+ int bucket_count);
+
+// Get histogram for counters with linear bucket spacing.
+Histogram* HistogramFactoryGetCountsLinear(const std::string& name,
+ int min,
+ int max,
+ int bucket_count);
// Get histogram for enumerators.
// |boundary| should be above the max enumerator sample.
-Histogram* HistogramFactoryGetEnumeration(
- const std::string& name, int boundary);
+Histogram* HistogramFactoryGetEnumeration(const std::string& name,
+ int boundary);
+
+// Get sparse histogram for enumerators.
+// |boundary| should be above the max enumerator sample.
+Histogram* SparseHistogramFactoryGetEnumeration(const std::string& name,
+ int boundary);
// Function for adding a |sample| to a histogram.
-// |name| can be used to verify that it matches the histogram name.
-void HistogramAdd(
- Histogram* histogram_pointer, const std::string& name, int sample);
+void HistogramAdd(Histogram* histogram_pointer, int sample);
+
+struct SampleInfo {
+ SampleInfo(const std::string& name, int min, int max, size_t bucket_count);
+ ~SampleInfo();
+
+ const std::string name;
+ const int min;
+ const int max;
+ const size_t bucket_count;
+ std::map<int, int> samples; // <value, # of events>
+};
+
+// Enables collection of samples.
+// This method should be called before any other call into webrtc.
+void Enable();
+
+// Gets histograms and clears all samples.
+void GetAndReset(
+ std::map<std::string, std::unique_ptr<SampleInfo>>* histograms);
+
+// Functions below are mainly for testing.
+
+// Clears all samples.
+void Reset();
+
+// Returns the number of times the |sample| has been added to the histogram.
+int NumEvents(const std::string& name, int sample);
+
+// Returns the total number of added samples to the histogram.
+int NumSamples(const std::string& name);
+
+// Returns the minimum sample value (or -1 if the histogram has no samples).
+int MinSample(const std::string& name);
+
+// Returns a map with keys the samples with at least one event and values the
+// number of events for that sample.
+std::map<int, int> Samples(const std::string& name);
} // namespace metrics
} // namespace webrtc
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
-
+#endif // SYSTEM_WRAPPERS_INCLUDE_METRICS_H_
diff --git a/webrtc/system_wrappers/include/scoped_vector.h b/webrtc/system_wrappers/include/scoped_vector.h
deleted file mode 100644
index 7336d98..0000000
--- a/webrtc/system_wrappers/include/scoped_vector.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Borrowed from Chromium's src/base/memory/scoped_vector.h.
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_SCOPED_VECTOR_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_SCOPED_VECTOR_H_
-
-#include <vector>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/system_wrappers/include/stl_util.h"
-
-namespace webrtc {
-
-// ScopedVector wraps a vector deleting the elements from its
-// destructor.
-template <class T>
-class ScopedVector {
- public:
- typedef typename std::vector<T*>::allocator_type allocator_type;
- typedef typename std::vector<T*>::size_type size_type;
- typedef typename std::vector<T*>::difference_type difference_type;
- typedef typename std::vector<T*>::pointer pointer;
- typedef typename std::vector<T*>::const_pointer const_pointer;
- typedef typename std::vector<T*>::reference reference;
- typedef typename std::vector<T*>::const_reference const_reference;
- typedef typename std::vector<T*>::value_type value_type;
- typedef typename std::vector<T*>::iterator iterator;
- typedef typename std::vector<T*>::const_iterator const_iterator;
- typedef typename std::vector<T*>::reverse_iterator reverse_iterator;
- typedef typename std::vector<T*>::const_reverse_iterator
- const_reverse_iterator;
-
- ScopedVector() {}
- ~ScopedVector() { clear(); }
-
- // Move construction and assignment.
- ScopedVector(ScopedVector&& other) {
- *this = static_cast<ScopedVector&&>(other);
- }
- ScopedVector& operator=(ScopedVector&& other) {
- std::swap(v_, other.v_); // The arguments are std::vectors, so std::swap
- // is the one that we want.
- other.clear();
- return *this;
- }
-
- // Deleted copy constructor and copy assignment, to make the type move-only.
- ScopedVector(const ScopedVector& other) = delete;
- ScopedVector& operator=(const ScopedVector& other) = delete;
-
- // Get an rvalue reference. (sv.Pass() does the same thing as std::move(sv).)
- ScopedVector&& Pass() { return static_cast<ScopedVector&&>(*this); }
-
- reference operator[](size_t index) { return v_[index]; }
- const_reference operator[](size_t index) const { return v_[index]; }
-
- bool empty() const { return v_.empty(); }
- size_t size() const { return v_.size(); }
-
- reverse_iterator rbegin() { return v_.rbegin(); }
- const_reverse_iterator rbegin() const { return v_.rbegin(); }
- reverse_iterator rend() { return v_.rend(); }
- const_reverse_iterator rend() const { return v_.rend(); }
-
- iterator begin() { return v_.begin(); }
- const_iterator begin() const { return v_.begin(); }
- iterator end() { return v_.end(); }
- const_iterator end() const { return v_.end(); }
-
- const_reference front() const { return v_.front(); }
- reference front() { return v_.front(); }
- const_reference back() const { return v_.back(); }
- reference back() { return v_.back(); }
-
- void push_back(T* elem) { v_.push_back(elem); }
-
- void pop_back() {
- RTC_DCHECK(!empty());
- delete v_.back();
- v_.pop_back();
- }
-
- std::vector<T*>& get() { return v_; }
- const std::vector<T*>& get() const { return v_; }
- void swap(std::vector<T*>& other) { v_.swap(other); }
- void swap(ScopedVector<T>& other) { v_.swap(other.v_); }
- void release(std::vector<T*>* out) {
- out->swap(v_);
- v_.clear();
- }
-
- void reserve(size_t capacity) { v_.reserve(capacity); }
-
- // Resize, deleting elements in the disappearing range if we are shrinking.
- void resize(size_t new_size) {
- if (v_.size() > new_size)
- STLDeleteContainerPointers(v_.begin() + new_size, v_.end());
- v_.resize(new_size);
- }
-
- template<typename InputIterator>
- void assign(InputIterator begin, InputIterator end) {
- v_.assign(begin, end);
- }
-
- void clear() { STLDeleteElements(&v_); }
-
- // Like |clear()|, but doesn't delete any elements.
- void weak_clear() { v_.clear(); }
-
- // Lets the ScopedVector take ownership of |x|.
- iterator insert(iterator position, T* x) {
- return v_.insert(position, x);
- }
-
- // Lets the ScopedVector take ownership of elements in [first,last).
- template<typename InputIterator>
- void insert(iterator position, InputIterator first, InputIterator last) {
- v_.insert(position, first, last);
- }
-
- iterator erase(iterator position) {
- delete *position;
- return v_.erase(position);
- }
-
- iterator erase(iterator first, iterator last) {
- STLDeleteContainerPointers(first, last);
- return v_.erase(first, last);
- }
-
- // Like |erase()|, but doesn't delete the element at |position|.
- iterator weak_erase(iterator position) {
- return v_.erase(position);
- }
-
- // Like |erase()|, but doesn't delete the elements in [first, last).
- iterator weak_erase(iterator first, iterator last) {
- return v_.erase(first, last);
- }
-
- private:
- std::vector<T*> v_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_SCOPED_VECTOR_H_
diff --git a/webrtc/system_wrappers/include/sleep.h b/webrtc/system_wrappers/include/sleep.h
index e7ed8b3..3bf8df2 100644
--- a/webrtc/system_wrappers/include/sleep.h
+++ b/webrtc/system_wrappers/include/sleep.h
@@ -9,8 +9,8 @@
*/
// An OS-independent sleep function.
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
+#ifndef SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
+#define SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
namespace webrtc {
@@ -21,4 +21,4 @@ void SleepMs(int msecs);
} // namespace webrtc
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
+#endif // SYSTEM_WRAPPERS_INCLUDE_SLEEP_H_
diff --git a/webrtc/system_wrappers/include/static_instance.h b/webrtc/system_wrappers/include/static_instance.h
deleted file mode 100644
index 41946d9..0000000
--- a/webrtc/system_wrappers/include/static_instance.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_
-
-#include <assert.h>
-
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#ifdef _WIN32
-#include "webrtc/system_wrappers/include/fix_interlocked_exchange_pointer_win.h"
-#endif
-
-namespace webrtc {
-
-enum CountOperation {
- kRelease,
- kAddRef,
- kAddRefNoCreate
-};
-enum CreateOperation {
- kInstanceExists,
- kCreate,
- kDestroy
-};
-
-template <class T>
-// Construct On First Use idiom. Avoids
-// "static initialization order fiasco".
-static T* GetStaticInstance(CountOperation count_operation) {
- // TODO (hellner): use atomic wrapper instead.
- static volatile long instance_count = 0;
- static T* volatile instance = NULL;
- CreateOperation state = kInstanceExists;
-#ifndef _WIN32
- // This memory is staticly allocated once. The application does not try to
- // free this memory. This approach is taken to avoid issues with
- // destruction order for statically allocated memory. The memory will be
- // reclaimed by the OS and memory leak tools will not recognize memory
- // reachable from statics leaked so no noise is added by doing this.
- static CriticalSectionWrapper* crit_sect(
- CriticalSectionWrapper::CreateCriticalSection());
- CriticalSectionScoped lock(crit_sect);
-
- if (count_operation ==
- kAddRefNoCreate && instance_count == 0) {
- return NULL;
- }
- if (count_operation ==
- kAddRef ||
- count_operation == kAddRefNoCreate) {
- instance_count++;
- if (instance_count == 1) {
- state = kCreate;
- }
- } else {
- instance_count--;
- if (instance_count == 0) {
- state = kDestroy;
- }
- }
- if (state == kCreate) {
- instance = T::CreateInstance();
- } else if (state == kDestroy) {
- T* old_instance = instance;
- instance = NULL;
- // The state will not change past this point. Release the critical
- // section while deleting the object in case it would be blocking on
- // access back to this object. (This is the case for the tracing class
- // since the thread owned by the tracing class also traces).
- // TODO(hellner): this is a bit out of place but here goes, de-couple
- // thread implementation with trace implementation.
- crit_sect->Leave();
- if (old_instance) {
- delete old_instance;
- }
- // Re-acquire the lock since the scoped critical section will release
- // it.
- crit_sect->Enter();
- return NULL;
- }
-#else // _WIN32
- if (count_operation ==
- kAddRefNoCreate && instance_count == 0) {
- return NULL;
- }
- if (count_operation == kAddRefNoCreate) {
- if (1 == InterlockedIncrement(&instance_count)) {
- // The instance has been destroyed by some other thread. Rollback.
- InterlockedDecrement(&instance_count);
- assert(false);
- return NULL;
- }
- // Sanity to catch corrupt state.
- if (instance == NULL) {
- assert(false);
- InterlockedDecrement(&instance_count);
- return NULL;
- }
- } else if (count_operation == kAddRef) {
- if (instance_count == 0) {
- state = kCreate;
- } else {
- if (1 == InterlockedIncrement(&instance_count)) {
- // InterlockedDecrement because reference count should not be
- // updated just yet (that's done when the instance is created).
- InterlockedDecrement(&instance_count);
- state = kCreate;
- }
- }
- } else {
- int new_value = InterlockedDecrement(&instance_count);
- if (new_value == 0) {
- state = kDestroy;
- }
- }
-
- if (state == kCreate) {
- // Create instance and let whichever thread finishes first assign its
- // local copy to the global instance. All other threads reclaim their
- // local copy.
- T* new_instance = T::CreateInstance();
- if (1 == InterlockedIncrement(&instance_count)) {
- InterlockedExchangePointer(reinterpret_cast<void * volatile*>(&instance),
- new_instance);
- } else {
- InterlockedDecrement(&instance_count);
- if (new_instance) {
- delete static_cast<T*>(new_instance);
- }
- }
- } else if (state == kDestroy) {
- T* old_value = static_cast<T*>(InterlockedExchangePointer(
- reinterpret_cast<void * volatile*>(&instance), NULL));
- if (old_value) {
- delete static_cast<T*>(old_value);
- }
- return NULL;
- }
-#endif // #ifndef _WIN32
- return instance;
-}
-
-} // namspace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_
diff --git a/webrtc/system_wrappers/include/stl_util.h b/webrtc/system_wrappers/include/stl_util.h
deleted file mode 100644
index b7a7021..0000000
--- a/webrtc/system_wrappers/include/stl_util.h
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Borrowed from Chromium's src/base/stl_util.h.
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STL_UTIL_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STL_UTIL_H_
-
-#include <assert.h>
-#include <algorithm>
-#include <functional>
-#include <iterator>
-#include <string>
-#include <vector>
-
-namespace webrtc {
-
-// Clears internal memory of an STL object.
-// STL clear()/reserve(0) does not always free internal memory allocated
-// This function uses swap/destructor to ensure the internal memory is freed.
-template<class T>
-void STLClearObject(T* obj) {
- T tmp;
- tmp.swap(*obj);
- // Sometimes "T tmp" allocates objects with memory (arena implementation?).
- // Hence using additional reserve(0) even if it doesn't always work.
- obj->reserve(0);
-}
-
-// For a range within a container of pointers, calls delete (non-array version)
-// on these pointers.
-// NOTE: for these three functions, we could just implement a DeleteObject
-// functor and then call for_each() on the range and functor, but this
-// requires us to pull in all of algorithm.h, which seems expensive.
-// For hash_[multi]set, it is important that this deletes behind the iterator
-// because the hash_set may call the hash function on the iterator when it is
-// advanced, which could result in the hash function trying to deference a
-// stale pointer.
-template <class ForwardIterator>
-void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) {
- while (begin != end) {
- ForwardIterator temp = begin;
- ++begin;
- delete *temp;
- }
-}
-
-// For a range within a container of pairs, calls delete (non-array version) on
-// BOTH items in the pairs.
-// NOTE: Like STLDeleteContainerPointers, it is important that this deletes
-// behind the iterator because if both the key and value are deleted, the
-// container may call the hash function on the iterator when it is advanced,
-// which could result in the hash function trying to dereference a stale
-// pointer.
-template <class ForwardIterator>
-void STLDeleteContainerPairPointers(ForwardIterator begin,
- ForwardIterator end) {
- while (begin != end) {
- ForwardIterator temp = begin;
- ++begin;
- delete temp->first;
- delete temp->second;
- }
-}
-
-// For a range within a container of pairs, calls delete (non-array version) on
-// the FIRST item in the pairs.
-// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
-template <class ForwardIterator>
-void STLDeleteContainerPairFirstPointers(ForwardIterator begin,
- ForwardIterator end) {
- while (begin != end) {
- ForwardIterator temp = begin;
- ++begin;
- delete temp->first;
- }
-}
-
-// For a range within a container of pairs, calls delete.
-// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
-// Deleting the value does not always invalidate the iterator, but it may
-// do so if the key is a pointer into the value object.
-template <class ForwardIterator>
-void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
- ForwardIterator end) {
- while (begin != end) {
- ForwardIterator temp = begin;
- ++begin;
- delete temp->second;
- }
-}
-
-// To treat a possibly-empty vector as an array, use these functions.
-// If you know the array will never be empty, you can use &*v.begin()
-// directly, but that is undefined behaviour if |v| is empty.
-template<typename T>
-inline T* vector_as_array(std::vector<T>* v) {
- return v->empty() ? NULL : &*v->begin();
-}
-
-template<typename T>
-inline const T* vector_as_array(const std::vector<T>* v) {
- return v->empty() ? NULL : &*v->begin();
-}
-
-// Return a mutable char* pointing to a string's internal buffer,
-// which may not be null-terminated. Writing through this pointer will
-// modify the string.
-//
-// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
-// next call to a string method that invalidates iterators.
-//
-// As of 2006-04, there is no standard-blessed way of getting a
-// mutable reference to a string's internal buffer. However, issue 530
-// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
-// proposes this as the method. According to Matt Austern, this should
-// already work on all current implementations.
-inline char* string_as_array(std::string* str) {
- // DO NOT USE const_cast<char*>(str->data())
- return str->empty() ? NULL : &*str->begin();
-}
-
-// The following functions are useful for cleaning up STL containers whose
-// elements point to allocated memory.
-
-// STLDeleteElements() deletes all the elements in an STL container and clears
-// the container. This function is suitable for use with a vector, set,
-// hash_set, or any other STL container which defines sensible begin(), end(),
-// and clear() methods.
-//
-// If container is NULL, this function is a no-op.
-//
-// As an alternative to calling STLDeleteElements() directly, consider
-// STLElementDeleter (defined below), which ensures that your container's
-// elements are deleted when the STLElementDeleter goes out of scope.
-template <class T>
-void STLDeleteElements(T* container) {
- if (!container)
- return;
- STLDeleteContainerPointers(container->begin(), container->end());
- container->clear();
-}
-
-// Given an STL container consisting of (key, value) pairs, STLDeleteValues
-// deletes all the "value" components and clears the container. Does nothing
-// in the case it's given a NULL pointer.
-template <class T>
-void STLDeleteValues(T* container) {
- if (!container)
- return;
- for (typename T::iterator i(container->begin()); i != container->end(); ++i)
- delete i->second;
- container->clear();
-}
-
-
-// The following classes provide a convenient way to delete all elements or
-// values from STL containers when they goes out of scope. This greatly
-// simplifies code that creates temporary objects and has multiple return
-// statements. Example:
-//
-// vector<MyProto *> tmp_proto;
-// STLElementDeleter<vector<MyProto *> > d(&tmp_proto);
-// if (...) return false;
-// ...
-// return success;
-
-// Given a pointer to an STL container this class will delete all the element
-// pointers when it goes out of scope.
-template<class T>
-class STLElementDeleter {
- public:
- STLElementDeleter<T>(T* container) : container_(container) {}
- ~STLElementDeleter<T>() { STLDeleteElements(container_); }
-
- private:
- T* container_;
-};
-
-// Given a pointer to an STL container this class will delete all the value
-// pointers when it goes out of scope.
-template<class T>
-class STLValueDeleter {
- public:
- STLValueDeleter<T>(T* container) : container_(container) {}
- ~STLValueDeleter<T>() { STLDeleteValues(container_); }
-
- private:
- T* container_;
-};
-
-// Test to see if a set, map, hash_set or hash_map contains a particular key.
-// Returns true if the key is in the collection.
-template <typename Collection, typename Key>
-bool ContainsKey(const Collection& collection, const Key& key) {
- return collection.find(key) != collection.end();
-}
-
-// Returns true if the container is sorted.
-template <typename Container>
-bool STLIsSorted(const Container& cont) {
- // Note: Use reverse iterator on container to ensure we only require
- // value_type to implement operator<.
- return std::adjacent_find(cont.rbegin(), cont.rend(),
- std::less<typename Container::value_type>())
- == cont.rend();
-}
-
-// Returns a new ResultType containing the difference of two sorted containers.
-template <typename ResultType, typename Arg1, typename Arg2>
-ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
- assert(STLIsSorted(a1));
- assert(STLIsSorted(a2));
- ResultType difference;
- std::set_difference(a1.begin(), a1.end(),
- a2.begin(), a2.end(),
- std::inserter(difference, difference.end()));
- return difference;
-}
-
-// Returns a new ResultType containing the union of two sorted containers.
-template <typename ResultType, typename Arg1, typename Arg2>
-ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
- assert(STLIsSorted(a1));
- assert(STLIsSorted(a2));
- ResultType result;
- std::set_union(a1.begin(), a1.end(),
- a2.begin(), a2.end(),
- std::inserter(result, result.end()));
- return result;
-}
-
-// Returns a new ResultType containing the intersection of two sorted
-// containers.
-template <typename ResultType, typename Arg1, typename Arg2>
-ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
- assert(STLIsSorted(a1));
- assert(STLIsSorted(a2));
- ResultType result;
- std::set_intersection(a1.begin(), a1.end(),
- a2.begin(), a2.end(),
- std::inserter(result, result.end()));
- return result;
-}
-
-// Returns true if the sorted container |a1| contains all elements of the sorted
-// container |a2|.
-template <typename Arg1, typename Arg2>
-bool STLIncludes(const Arg1& a1, const Arg2& a2) {
- assert(STLIsSorted(a1));
- assert(STLIsSorted(a2));
- return std::includes(a1.begin(), a1.end(),
- a2.begin(), a2.end());
-}
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STL_UTIL_H_
diff --git a/webrtc/system_wrappers/include/thread_wrapper.h b/webrtc/system_wrappers/include/thread_wrapper.h
deleted file mode 100644
index d475302..0000000
--- a/webrtc/system_wrappers/include/thread_wrapper.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.
- */
-
-// System independant wrapper for spawning threads
-// Note: the spawned thread will loop over the callback function until stopped.
-// Note: The callback function is expected to return every 2 seconds or more
-// often.
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_THREAD_WRAPPER_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_THREAD_WRAPPER_H_
-
-#if defined(WEBRTC_WIN)
-#include <windows.h>
-#endif
-
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/common_types.h"
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-// Callback function that the spawned thread will enter once spawned.
-// A return value of false is interpreted as that the function has no
-// more work to do and that the thread can be released.
-typedef bool(*ThreadRunFunction)(void*);
-
-enum ThreadPriority {
-#ifdef WEBRTC_WIN
- kLowPriority = THREAD_PRIORITY_BELOW_NORMAL,
- kNormalPriority = THREAD_PRIORITY_NORMAL,
- kHighPriority = THREAD_PRIORITY_ABOVE_NORMAL,
- kHighestPriority = THREAD_PRIORITY_HIGHEST,
- kRealtimePriority = THREAD_PRIORITY_TIME_CRITICAL
-#else
- kLowPriority = 1,
- kNormalPriority = 2,
- kHighPriority = 3,
- kHighestPriority = 4,
- kRealtimePriority = 5
-#endif
-};
-
-// Represents a simple worker thread. The implementation must be assumed
-// to be single threaded, meaning that all methods of the class, must be
-// called from the same thread, including instantiation.
-// TODO(tommi): There's no need for this to be a virtual interface since there's
-// only ever a single implementation of it.
-class ThreadWrapper {
- public:
- virtual ~ThreadWrapper() {}
-
- // Factory method. Constructor disabled.
- //
- // func Pointer to a, by user, specified callback function.
- // obj Object associated with the thread. Passed in the callback
- // function.
- // prio Thread priority. May require root/admin rights.
- // thread_name NULL terminated thread name, will be visable in the Windows
- // debugger.
- static rtc::scoped_ptr<ThreadWrapper> CreateThread(ThreadRunFunction func,
- void* obj, const char* thread_name);
-
- // Get the current thread's thread ID.
- // NOTE: This is a static method. It returns the id of the calling thread,
- // *not* the id of the worker thread that a ThreadWrapper instance represents.
- // TODO(tommi): Move outside of the ThreadWrapper class to avoid confusion.
- static uint32_t GetThreadId();
-
- // Tries to spawns a thread and returns true if that was successful.
- // Additionally, it tries to set thread priority according to the priority
- // from when CreateThread was called. However, failure to set priority will
- // not result in a false return value.
- virtual bool Start() = 0;
-
- // Stops the spawned thread and waits for it to be reclaimed with a timeout
- // of two seconds. Will return false if the thread was not reclaimed.
- // Multiple tries to Stop are allowed (e.g. to wait longer than 2 seconds).
- // It's ok to call Stop() even if the spawned thread has been reclaimed.
- virtual bool Stop() = 0;
-
- // Set the priority of the worker thread. Must be called when thread
- // is running.
- virtual bool SetPriority(ThreadPriority priority) = 0;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_THREAD_WRAPPER_H_
diff --git a/webrtc/system_wrappers/include/trace.h b/webrtc/system_wrappers/include/trace.h
deleted file mode 100644
index 25a3d74..0000000
--- a/webrtc/system_wrappers/include/trace.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- *
- * System independent wrapper for logging runtime information to file.
- * Note: All log messages will be written to the same trace file.
- * Note: If too many messages are written to file there will be a build up of
- * messages. Apply filtering to avoid that.
- */
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_TRACE_H_
-#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_TRACE_H_
-
-#include "webrtc/common_types.h"
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-#if defined(WEBRTC_RESTRICT_LOGGING)
-// Disable all TRACE macros. The LOG macro is still functional.
-#define WEBRTC_TRACE true ? (void) 0 : Trace::Add
-#else
-#define WEBRTC_TRACE Trace::Add
-#endif
-
-class Trace {
- public:
- // The length of the trace text preceeding the log message.
- static const int kBoilerplateLength;
- // The position of the timestamp text within a trace.
- static const int kTimestampPosition;
- // The length of the timestamp (without "delta" field).
- static const int kTimestampLength;
-
- // Increments the reference count to the trace.
- static void CreateTrace();
- // Decrements the reference count to the trace.
- static void ReturnTrace();
- // Note: any instance that writes to the trace file should increment and
- // decrement the reference count on construction and destruction,
- // respectively.
-
- // Specifies what type of messages should be written to the trace file. The
- // filter parameter is a bitmask where each message type is enumerated by the
- // TraceLevel enumerator. TODO(hellner): why is the TraceLevel enumerator not
- // defined in this file?
- static void set_level_filter(int filter);
-
- // Returns what type of messages are written to the trace file.
- static int level_filter();
-
- // Sets the file name. If add_file_counter is false the same file will be
- // reused when it fills up. If it's true a new file with incremented name
- // will be used.
- static int32_t SetTraceFile(const char* file_name,
- const bool add_file_counter = false);
-
- // Returns the name of the file that the trace is currently writing to.
- static int32_t TraceFile(char file_name[1024]);
-
- // Registers callback to receive trace messages.
- // TODO(hellner): Why not use OutStream instead? Why is TraceCallback not
- // defined in this file?
- static int32_t SetTraceCallback(TraceCallback* callback);
-
- // Adds a trace message for writing to file. The message is put in a queue
- // for writing to file whenever possible for performance reasons. I.e. there
- // is a crash it is possible that the last, vital logs are not logged yet.
- // level is the type of message to log. If that type of messages is
- // filtered it will not be written to file. module is an identifier for what
- // part of the code the message is coming.
- // id is an identifier that should be unique for that set of classes that
- // are associated (e.g. all instances owned by an engine).
- // msg and the ellipsis are the same as e.g. sprintf.
- // TODO(hellner) Why is TraceModule not defined in this file?
- static void Add(const TraceLevel level,
- const TraceModule module,
- const int32_t id,
- const char* msg, ...);
-
- private:
- static volatile int level_filter_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_TRACE_H_
diff --git a/webrtc/system_wrappers/meson.build b/webrtc/system_wrappers/meson.build
index c8cb9ed..22a9a1b 100644
--- a/webrtc/system_wrappers/meson.build
+++ b/webrtc/system_wrappers/meson.build
@@ -1,47 +1,18 @@
system_wrappers_sources = [
- 'source/aligned_malloc.cc',
'source/cpu_features.cc',
- 'source/event.cc',
- 'source/file_impl.cc',
- 'source/critical_section.cc',
- 'source/logging.cc',
- 'source/metrics_default.cc',
- 'source/rw_lock.cc',
+ 'source/field_trial.cc',
+ 'source/metrics.cc',
'source/sleep.cc',
- 'source/thread.cc',
- 'source/trace_impl.cc',
]
-if have_posix
- system_wrappers_sources += [
- 'source/critical_section_posix.cc',
- 'source/event_timer_posix.cc',
- 'source/rw_lock_posix.cc',
- 'source/thread_posix.cc',
- 'source/trace_posix.cc',
- ]
-endif
-
-if have_win
- system_wrappers_sources += [
- 'source/critical_section_win.cc',
- 'source/condition_variable.cc',
- 'source/condition_variable_event_win.cc',
- 'source/condition_variable_native_win.cc',
- 'source/event_timer_win.cc',
- 'source/rw_lock_win.cc',
- 'source/rw_lock_generic.cc',
- 'source/thread_win.cc',
- 'source/trace_win.cc',
- ]
-endif
-
system_headers = [
- 'include/trace.h',
+ 'include/cpu_features_wrapper.h',
+ 'include/metrics.h',
+ 'include/sleep.h',
]
install_headers(system_headers,
- subdir: 'webrtc_audio_processing/webrtc/system_wrappers/include'
+ subdir: 'webrtc_audio_processing/system_wrappers/include'
)
libsystem_wrappers = static_library('system_wrappers',
diff --git a/webrtc/system_wrappers/source/condition_variable.cc b/webrtc/system_wrappers/source/condition_variable.cc
deleted file mode 100644
index f5ae93a..0000000
--- a/webrtc/system_wrappers/source/condition_variable.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 "webrtc/system_wrappers/include/condition_variable_wrapper.h"
-
-#if defined(_WIN32)
-#include <windows.h>
-#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
-#include "webrtc/system_wrappers/source/condition_variable_native_win.h"
-#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
-#include <pthread.h>
-#include "webrtc/system_wrappers/source/condition_variable_posix.h"
-#endif
-
-namespace webrtc {
-
-ConditionVariableWrapper* ConditionVariableWrapper::CreateConditionVariable() {
-#if defined(_WIN32)
- // Try to create native condition variable implementation.
- ConditionVariableWrapper* ret_val = ConditionVariableNativeWin::Create();
- if (!ret_val) {
- // Native condition variable implementation does not exist. Create generic
- // condition variable based on events.
- ret_val = new ConditionVariableEventWin();
- }
- return ret_val;
-#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
- return ConditionVariablePosix::Create();
-#else
- return NULL;
-#endif
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/condition_variable_event_win.cc b/webrtc/system_wrappers/source/condition_variable_event_win.cc
deleted file mode 100644
index 41b019d..0000000
--- a/webrtc/system_wrappers/source/condition_variable_event_win.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-Source:
-http://www1.cse.wustl.edu/~schmidt/ACE-copying.html
-
-License:
-Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM),
-and CoSMIC(TM)
-
-ACE(TM), TAO(TM), CIAO(TM), DAnCE>(TM), and CoSMIC(TM) (henceforth referred to
-as "DOC software") are copyrighted by Douglas C. Schmidt and his research
-group at Washington University, University of California, Irvine, and
-Vanderbilt University, Copyright (c) 1993-2009, all rights reserved. Since DOC
-software is open-source, freely available software, you are free to use,
-modify, copy, and distribute--perpetually and irrevocably--the DOC software
-source code and object code produced from the source, as well as copy and
-distribute modified versions of this software. You must, however, include this
-copyright statement along with any code built using DOC software that you
-release. No copyright statement needs to be provided if you just ship binary
-executables of your software products.
-You can use DOC software in commercial and/or binary software releases and are
-under no obligation to redistribute any of your source code that is built
-using DOC software. Note, however, that you may not misappropriate the DOC
-software code, such as copyrighting it yourself or claiming authorship of the
-DOC software code, in a way that will prevent DOC software from being
-distributed freely using an open-source development model. You needn't inform
-anyone that you're using DOC software in your software, though we encourage
-you to let us know so we can promote your project in the DOC software success
-stories.
-
-The ACE, TAO, CIAO, DAnCE, and CoSMIC web sites are maintained by the DOC
-Group at the Institute for Software Integrated Systems (ISIS) and the Center
-for Distributed Object Computing of Washington University, St. Louis for the
-development of open-source software as part of the open-source software
-community. Submissions are provided by the submitter ``as is'' with no
-warranties whatsoever, including any warranty of merchantability,
-noninfringement of third party intellectual property, or fitness for any
-particular purpose. In no event shall the submitter be liable for any direct,
-indirect, special, exemplary, punitive, or consequential damages, including
-without limitation, lost profits, even if advised of the possibility of such
-damages. Likewise, DOC software is provided as is with no warranties of any
-kind, including the warranties of design, merchantability, and fitness for a
-particular purpose, noninfringement, or arising from a course of dealing,
-usage or trade practice. Washington University, UC Irvine, Vanderbilt
-University, their employees, and students shall have no liability with respect
-to the infringement of copyrights, trade secrets or any patents by DOC
-software or any part thereof. Moreover, in no event will Washington
-University, UC Irvine, or Vanderbilt University, their employees, or students
-be liable for any lost revenue or profits or other special, indirect and
-consequential damages.
-
-DOC software is provided with no support and without any obligation on the
-part of Washington University, UC Irvine, Vanderbilt University, their
-employees, or students to assist in its use, correction, modification, or
-enhancement. A number of companies around the world provide commercial support
-for DOC software, however. DOC software is Y2K-compliant, as long as the
-underlying OS platform is Y2K-compliant. Likewise, DOC software is compliant
-with the new US daylight savings rule passed by Congress as "The Energy Policy
-Act of 2005," which established new daylight savings times (DST) rules for the
-United States that expand DST as of March 2007. Since DOC software obtains
-time/date and calendaring information from operating systems users will not be
-affected by the new DST rules as long as they upgrade their operating systems
-accordingly.
-
-The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), Washington
-University, UC Irvine, and Vanderbilt University, may not be used to endorse
-or promote products or services derived from this source without express
-written permission from Washington University, UC Irvine, or Vanderbilt
-University. This license grants no permission to call products or services
-derived from this source ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM),
-nor does it grant permission for the name Washington University, UC Irvine, or
-Vanderbilt University to appear in their names.
-*/
-
-/*
- * This source code contain modifications to the original source code
- * which can be found here:
- * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (section 3.2).
- * Modifications:
- * 1) Dynamic detection of native support for condition variables.
- * 2) Use of WebRTC defined types and classes. Renaming of some functions.
- * 3) Introduction of a second event for wake all functionality. This prevents
- * a thread from spinning on the same condition variable, preventing other
- * threads from waking up.
- */
-
-#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
-#include "webrtc/system_wrappers/source/critical_section_win.h"
-
-namespace webrtc {
-
-ConditionVariableEventWin::ConditionVariableEventWin() : eventID_(WAKEALL_0) {
- memset(&num_waiters_[0], 0, sizeof(num_waiters_));
-
- InitializeCriticalSection(&num_waiters_crit_sect_);
-
- events_[WAKEALL_0] = CreateEvent(NULL, // no security attributes
- TRUE, // manual-reset, sticky event
- FALSE, // initial state non-signaled
- NULL); // no name for event
-
- events_[WAKEALL_1] = CreateEvent(NULL, // no security attributes
- TRUE, // manual-reset, sticky event
- FALSE, // initial state non-signaled
- NULL); // no name for event
-
- events_[WAKE] = CreateEvent(NULL, // no security attributes
- FALSE, // auto-reset, sticky event
- FALSE, // initial state non-signaled
- NULL); // no name for event
-}
-
-ConditionVariableEventWin::~ConditionVariableEventWin() {
- CloseHandle(events_[WAKE]);
- CloseHandle(events_[WAKEALL_1]);
- CloseHandle(events_[WAKEALL_0]);
-
- DeleteCriticalSection(&num_waiters_crit_sect_);
-}
-
-void ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect) {
- SleepCS(crit_sect, INFINITE);
-}
-
-bool ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect,
- unsigned long max_time_in_ms) {
- EnterCriticalSection(&num_waiters_crit_sect_);
-
- // Get the eventID for the event that will be triggered by next
- // WakeAll() call and start waiting for it.
- const EventWakeUpType eventID =
- (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
-
- ++(num_waiters_[eventID]);
- LeaveCriticalSection(&num_waiters_crit_sect_);
-
- CriticalSectionWindows* cs =
- static_cast<CriticalSectionWindows*>(&crit_sect);
- LeaveCriticalSection(&cs->crit);
- HANDLE events[2];
- events[0] = events_[WAKE];
- events[1] = events_[eventID];
- const DWORD result = WaitForMultipleObjects(2, // Wait on 2 events.
- events,
- FALSE, // Wait for either.
- max_time_in_ms);
-
- const bool ret_val = (result != WAIT_TIMEOUT);
-
- EnterCriticalSection(&num_waiters_crit_sect_);
- --(num_waiters_[eventID]);
-
- // Last waiter should only be true for WakeAll(). WakeAll() correspond
- // to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1)
- const bool last_waiter = (result == WAIT_OBJECT_0 + 1) &&
- (num_waiters_[eventID] == 0);
- LeaveCriticalSection(&num_waiters_crit_sect_);
-
- if (last_waiter) {
- // Reset/unset the WakeAll() event since all threads have been
- // released.
- ResetEvent(events_[eventID]);
- }
-
- EnterCriticalSection(&cs->crit);
- return ret_val;
-}
-
-void ConditionVariableEventWin::Wake() {
- EnterCriticalSection(&num_waiters_crit_sect_);
- const bool have_waiters = (num_waiters_[WAKEALL_0] > 0) ||
- (num_waiters_[WAKEALL_1] > 0);
- LeaveCriticalSection(&num_waiters_crit_sect_);
-
- if (have_waiters) {
- SetEvent(events_[WAKE]);
- }
-}
-
-void ConditionVariableEventWin::WakeAll() {
- EnterCriticalSection(&num_waiters_crit_sect_);
-
- // Update current WakeAll() event
- eventID_ = (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
-
- // Trigger current event
- const EventWakeUpType eventID = eventID_;
- const bool have_waiters = num_waiters_[eventID] > 0;
- LeaveCriticalSection(&num_waiters_crit_sect_);
-
- if (have_waiters) {
- SetEvent(events_[eventID]);
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/condition_variable_event_win.h b/webrtc/system_wrappers/source/condition_variable_event_win.h
deleted file mode 100644
index cdcef7d..0000000
--- a/webrtc/system_wrappers/source/condition_variable_event_win.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_
-
-#include <windows.h>
-
-#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
-
-namespace webrtc {
-
-class ConditionVariableEventWin : public ConditionVariableWrapper {
- public:
- ConditionVariableEventWin();
- virtual ~ConditionVariableEventWin();
-
- void SleepCS(CriticalSectionWrapper& crit_sect);
- bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS);
- void Wake();
- void WakeAll();
-
- private:
- enum EventWakeUpType {
- WAKEALL_0 = 0,
- WAKEALL_1 = 1,
- WAKE = 2,
- EVENT_COUNT = 3
- };
-
- unsigned int num_waiters_[2];
- EventWakeUpType eventID_;
- CRITICAL_SECTION num_waiters_crit_sect_;
- HANDLE events_[EVENT_COUNT];
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_
diff --git a/webrtc/system_wrappers/source/condition_variable_native_win.cc b/webrtc/system_wrappers/source/condition_variable_native_win.cc
deleted file mode 100644
index 45225f2..0000000
--- a/webrtc/system_wrappers/source/condition_variable_native_win.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/include/trace.h"
-#include "webrtc/system_wrappers/source/condition_variable_native_win.h"
-#include "webrtc/system_wrappers/source/critical_section_win.h"
-
-namespace webrtc {
-
-static HMODULE library = NULL;
-static bool win_support_condition_variables_primitive = false;
-
-PInitializeConditionVariable PInitializeConditionVariable_;
-PSleepConditionVariableCS PSleepConditionVariableCS_;
-PWakeConditionVariable PWakeConditionVariable_;
-PWakeAllConditionVariable PWakeAllConditionVariable_;
-
-typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE);
-typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE,
- PCRITICAL_SECTION, DWORD);
-typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE);
-typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE);
-
-ConditionVariableNativeWin::ConditionVariableNativeWin() {
-}
-
-ConditionVariableNativeWin::~ConditionVariableNativeWin() {
-}
-
-ConditionVariableWrapper* ConditionVariableNativeWin::Create() {
- ConditionVariableNativeWin* ret_val = new ConditionVariableNativeWin();
- if (!ret_val->Init()) {
- delete ret_val;
- return NULL;
- }
- return ret_val;
-}
-
-bool ConditionVariableNativeWin::Init() {
- if (!library) {
- // Native implementation is supported on Vista+.
- library = LoadLibrary(TEXT("Kernel32.dll"));
- // TODO(henrike): this code results in an attempt to load the above dll
- // every time the previous attempt failed. Only try to load once.
- if (library) {
- // TODO(henrike): not thread safe as reading and writing to library is not
- // serialized. Fix.
- WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll");
-
- PInitializeConditionVariable_ =
- (PInitializeConditionVariable) GetProcAddress(
- library, "InitializeConditionVariable");
- PSleepConditionVariableCS_ = (PSleepConditionVariableCS) GetProcAddress(
- library, "SleepConditionVariableCS");
- PWakeConditionVariable_ = (PWakeConditionVariable) GetProcAddress(
- library, "WakeConditionVariable");
- PWakeAllConditionVariable_ = (PWakeAllConditionVariable) GetProcAddress(
- library, "WakeAllConditionVariable");
-
- if (PInitializeConditionVariable_ && PSleepConditionVariableCS_
- && PWakeConditionVariable_ && PWakeAllConditionVariable_) {
- WEBRTC_TRACE(
- kTraceStateInfo, kTraceUtility, -1,
- "Loaded native condition variables");
- win_support_condition_variables_primitive = true;
- }
- }
- }
- if (!win_support_condition_variables_primitive) {
- return false;
- }
- PInitializeConditionVariable_(&condition_variable_);
- return true;
-}
-
-void ConditionVariableNativeWin::SleepCS(CriticalSectionWrapper& crit_sect) {
- SleepCS(crit_sect, INFINITE);
-}
-
-bool ConditionVariableNativeWin::SleepCS(CriticalSectionWrapper& crit_sect,
- unsigned long max_time_in_ms) {
- CriticalSectionWindows* cs =
- static_cast<CriticalSectionWindows*>(&crit_sect);
- BOOL ret_val = PSleepConditionVariableCS_(&condition_variable_,
- &(cs->crit), max_time_in_ms);
- return ret_val != 0;
-}
-
-void ConditionVariableNativeWin::Wake() {
- PWakeConditionVariable_(&condition_variable_);
-}
-
-void ConditionVariableNativeWin::WakeAll() {
- PWakeAllConditionVariable_(&condition_variable_);
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/condition_variable_native_win.h b/webrtc/system_wrappers/source/condition_variable_native_win.h
deleted file mode 100644
index c22787f..0000000
--- a/webrtc/system_wrappers/source/condition_variable_native_win.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_
-
-#include <windows.h>
-
-#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
-
-namespace webrtc {
-
-#if !defined CONDITION_VARIABLE_INIT
-typedef struct RTL_CONDITION_VARIABLE_ {
- void* Ptr;
-} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE;
-
-typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
-#endif
-
-typedef void (WINAPI* PInitializeConditionVariable)(PCONDITION_VARIABLE);
-typedef BOOL (WINAPI* PSleepConditionVariableCS)(PCONDITION_VARIABLE,
- PCRITICAL_SECTION, DWORD);
-typedef void (WINAPI* PWakeConditionVariable)(PCONDITION_VARIABLE);
-typedef void (WINAPI* PWakeAllConditionVariable)(PCONDITION_VARIABLE);
-
-class ConditionVariableNativeWin : public ConditionVariableWrapper {
- public:
- static ConditionVariableWrapper* Create();
- virtual ~ConditionVariableNativeWin();
-
- void SleepCS(CriticalSectionWrapper& crit_sect);
- bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS);
- void Wake();
- void WakeAll();
-
- private:
- ConditionVariableNativeWin();
-
- bool Init();
-
- CONDITION_VARIABLE condition_variable_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_
diff --git a/webrtc/system_wrappers/source/cpu_features.cc b/webrtc/system_wrappers/source/cpu_features.cc
index 49840eb..0f81212 100644
--- a/webrtc/system_wrappers/source/cpu_features.cc
+++ b/webrtc/system_wrappers/source/cpu_features.cc
@@ -10,13 +10,15 @@
// Parts of this file derived from Chromium's base/cpu.cc.
-#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
+#include "rtc_base/system/arch.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+#include "system_wrappers/include/field_trial.h"
#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER)
#include <intrin.h>
#endif
-#include "webrtc/typedefs.h"
+namespace webrtc {
// No CPU feature is available => straight C path.
int GetCPUInfoNoASM(CPUFeature feature) {
@@ -25,23 +27,40 @@ int GetCPUInfoNoASM(CPUFeature feature) {
}
#if defined(WEBRTC_ARCH_X86_FAMILY)
+
+#if defined(WEBRTC_ENABLE_AVX2)
+// xgetbv returns the value of an Intel Extended Control Register (XCR).
+// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
+static uint64_t xgetbv(uint32_t xcr) {
+#if defined(_MSC_VER)
+ return _xgetbv(xcr);
+#else
+ uint32_t eax, edx;
+
+ __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
+ return (static_cast<uint64_t>(edx) << 32) | eax;
+#endif // _MSC_VER
+}
+#endif // WEBRTC_ENABLE_AVX2
+
#ifndef _MSC_VER
// Intrinsic for "cpuid".
#if defined(__pic__) && defined(__i386__)
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile(
- "mov %%ebx, %%edi\n"
- "cpuid\n"
- "xchg %%edi, %%ebx\n"
- : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
- : "a"(info_type));
+ "mov %%ebx, %%edi\n"
+ "cpuid\n"
+ "xchg %%edi, %%ebx\n"
+ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]),
+ "=d"(cpu_info[3])
+ : "a"(info_type));
}
#else
static inline void __cpuid(int cpu_info[4], int info_type) {
- __asm__ volatile(
- "cpuid\n"
- : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
- : "a"(info_type));
+ __asm__ volatile("cpuid\n"
+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
+ "=d"(cpu_info[3])
+ : "a"(info_type), "c"(0));
}
#endif
#endif // _MSC_VER
@@ -49,7 +68,7 @@ static inline void __cpuid(int cpu_info[4], int info_type) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
// Actual feature detection for x86.
-static int GetCPUInfo(CPUFeature feature) {
+int GetCPUInfo(CPUFeature feature) {
int cpu_info[4];
__cpuid(cpu_info, 1);
if (feature == kSSE2) {
@@ -58,15 +77,39 @@ static int GetCPUInfo(CPUFeature feature) {
if (feature == kSSE3) {
return 0 != (cpu_info[2] & 0x00000001);
}
+#if defined(WEBRTC_ENABLE_AVX2)
+ if (feature == kAVX2 &&
+ !webrtc::field_trial::IsEnabled("WebRTC-Avx2SupportKillSwitch")) {
+ int cpu_info7[4];
+ __cpuid(cpu_info7, 0);
+ int num_ids = cpu_info7[0];
+ if (num_ids < 7) {
+ return 0;
+ }
+ // Interpret CPU feature information.
+ __cpuid(cpu_info7, 7);
+
+ // AVX instructions can be used when
+ // a) AVX are supported by the CPU,
+ // b) XSAVE is supported by the CPU,
+ // c) XSAVE is enabled by the kernel.
+ // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
+ // AVX2 support needs (avx_support && (cpu_info7[1] & 0x00000020) != 0;).
+ return (cpu_info[2] & 0x10000000) != 0 &&
+ (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
+ (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
+ (xgetbv(0) & 0x00000006) == 6 /* XSAVE enabled by kernel */ &&
+ (cpu_info7[1] & 0x00000020) != 0;
+ }
+#endif // WEBRTC_ENABLE_AVX2
return 0;
}
#else
// Default to straight C for other platforms.
-static int GetCPUInfo(CPUFeature feature) {
+int GetCPUInfo(CPUFeature feature) {
(void)feature;
return 0;
}
#endif
-WebRtc_CPUInfo WebRtc_GetCPUInfo = GetCPUInfo;
-WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM = GetCPUInfoNoASM;
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/critical_section.cc b/webrtc/system_wrappers/source/critical_section.cc
deleted file mode 100644
index c586588..0000000
--- a/webrtc/system_wrappers/source/critical_section.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.
- */
-
-#if defined(_WIN32)
-#include <windows.h>
-#include "webrtc/system_wrappers/source/critical_section_win.h"
-#else
-#include "webrtc/system_wrappers/source/critical_section_posix.h"
-#endif
-
-namespace webrtc {
-
-CriticalSectionWrapper* CriticalSectionWrapper::CreateCriticalSection() {
-#ifdef _WIN32
- return new CriticalSectionWindows();
-#else
- return new CriticalSectionPosix();
-#endif
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/critical_section_posix.cc b/webrtc/system_wrappers/source/critical_section_posix.cc
deleted file mode 100644
index 41b7732..0000000
--- a/webrtc/system_wrappers/source/critical_section_posix.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// General note: return values for the various pthread synchronization APIs
-// are explicitly ignored here. In Chromium, the same thing is done for release.
-// However, in debugging, failure in these APIs are logged.
-// TODO(henrike): add logging when pthread synchronization APIs are failing.
-
-#include "webrtc/system_wrappers/source/critical_section_posix.h"
-
-namespace webrtc {
-
-CriticalSectionPosix::CriticalSectionPosix() {
- pthread_mutexattr_t attr;
- (void) pthread_mutexattr_init(&attr);
- (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
- (void) pthread_mutex_init(&mutex_, &attr);
-}
-
-CriticalSectionPosix::~CriticalSectionPosix() {
- (void) pthread_mutex_destroy(&mutex_);
-}
-
-void
-CriticalSectionPosix::Enter() {
- (void) pthread_mutex_lock(&mutex_);
-}
-
-void
-CriticalSectionPosix::Leave() {
- (void) pthread_mutex_unlock(&mutex_);
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/critical_section_posix.h b/webrtc/system_wrappers/source/critical_section_posix.h
deleted file mode 100644
index 099f74c..0000000
--- a/webrtc/system_wrappers/source/critical_section_posix.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
-
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-
-#include <pthread.h>
-
-namespace webrtc {
-
-class CriticalSectionPosix : public CriticalSectionWrapper {
- public:
- CriticalSectionPosix();
-
- ~CriticalSectionPosix() override;
-
- void Enter() override;
- void Leave() override;
-
- private:
- pthread_mutex_t mutex_;
- friend class ConditionVariablePosix;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
diff --git a/webrtc/system_wrappers/source/critical_section_win.cc b/webrtc/system_wrappers/source/critical_section_win.cc
deleted file mode 100644
index b5149d1..0000000
--- a/webrtc/system_wrappers/source/critical_section_win.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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 "webrtc/system_wrappers/source/critical_section_win.h"
-
-namespace webrtc {
-
-CriticalSectionWindows::CriticalSectionWindows() {
- InitializeCriticalSection(&crit);
-}
-
-CriticalSectionWindows::~CriticalSectionWindows() {
- DeleteCriticalSection(&crit);
-}
-
-void
-CriticalSectionWindows::Enter() {
- EnterCriticalSection(&crit);
-}
-
-void
-CriticalSectionWindows::Leave() {
- LeaveCriticalSection(&crit);
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/critical_section_win.h b/webrtc/system_wrappers/source/critical_section_win.h
deleted file mode 100644
index 8268bc3..0000000
--- a/webrtc/system_wrappers/source/critical_section_win.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_
-
-#include <windows.h>
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-class CriticalSectionWindows : public CriticalSectionWrapper {
- public:
- CriticalSectionWindows();
-
- virtual ~CriticalSectionWindows();
-
- virtual void Enter();
- virtual void Leave();
-
- private:
- CRITICAL_SECTION crit;
-
- friend class ConditionVariableEventWin;
- friend class ConditionVariableNativeWin;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_
diff --git a/webrtc/system_wrappers/source/event.cc b/webrtc/system_wrappers/source/event.cc
deleted file mode 100644
index 05f918f..0000000
--- a/webrtc/system_wrappers/source/event.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 "webrtc/system_wrappers/include/event_wrapper.h"
-
-#if defined(_WIN32)
-#include <windows.h>
-#include "webrtc/system_wrappers/source/event_timer_win.h"
-#elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
-#include <ApplicationServices/ApplicationServices.h>
-#include <pthread.h>
-#include "webrtc/system_wrappers/source/event_timer_posix.h"
-#else
-#include <pthread.h>
-#include "webrtc/system_wrappers/source/event_timer_posix.h"
-#endif
-
-#include "webrtc/base/event.h"
-
-namespace webrtc {
-
-class EventWrapperImpl : public EventWrapper {
- public:
- EventWrapperImpl() : event_(false, false) {}
- ~EventWrapperImpl() override {}
-
- bool Set() override {
- event_.Set();
- return true;
- }
-
- EventTypeWrapper Wait(unsigned long max_time) override {
- int to_wait = max_time == WEBRTC_EVENT_INFINITE ?
- rtc::Event::kForever : static_cast<int>(max_time);
- return event_.Wait(to_wait) ? kEventSignaled : kEventTimeout;
- }
-
- private:
- rtc::Event event_;
-};
-
-// static
-EventWrapper* EventWrapper::Create() {
- return new EventWrapperImpl();
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/event_timer_posix.cc b/webrtc/system_wrappers/source/event_timer_posix.cc
deleted file mode 100644
index 99eebcb..0000000
--- a/webrtc/system_wrappers/source/event_timer_posix.cc
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * 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 "webrtc/system_wrappers/source/event_timer_posix.h"
-
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-#include "webrtc/base/checks.h"
-
-namespace webrtc {
-
-// static
-EventTimerWrapper* EventTimerWrapper::Create() {
- return new EventTimerPosix();
-}
-
-const long int E6 = 1000000;
-const long int E9 = 1000 * E6;
-
-EventTimerPosix::EventTimerPosix()
- : event_set_(false),
- timer_thread_(nullptr),
- created_at_(),
- periodic_(false),
- time_(0),
- count_(0) {
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&mutex_, &attr);
-#ifdef WEBRTC_CLOCK_TYPE_REALTIME
- pthread_cond_init(&cond_, 0);
-#else
- pthread_condattr_t cond_attr;
- pthread_condattr_init(&cond_attr);
- pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
- pthread_cond_init(&cond_, &cond_attr);
- pthread_condattr_destroy(&cond_attr);
-#endif
-}
-
-EventTimerPosix::~EventTimerPosix() {
- StopTimer();
- pthread_cond_destroy(&cond_);
- pthread_mutex_destroy(&mutex_);
-}
-
-// TODO(pbos): Make this void.
-bool EventTimerPosix::Set() {
- RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
- event_set_ = true;
- pthread_cond_signal(&cond_);
- pthread_mutex_unlock(&mutex_);
- return true;
-}
-
-EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout) {
- int ret_val = 0;
- RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
-
- if (!event_set_) {
- if (WEBRTC_EVENT_INFINITE != timeout) {
- timespec end_at;
-#ifndef WEBRTC_MAC
-#ifdef WEBRTC_CLOCK_TYPE_REALTIME
- clock_gettime(CLOCK_REALTIME, &end_at);
-#else
- clock_gettime(CLOCK_MONOTONIC, &end_at);
-#endif
-#else
- timeval value;
- struct timezone time_zone;
- time_zone.tz_minuteswest = 0;
- time_zone.tz_dsttime = 0;
- gettimeofday(&value, &time_zone);
- TIMEVAL_TO_TIMESPEC(&value, &end_at);
-#endif
- end_at.tv_sec += timeout / 1000;
- end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
-
- if (end_at.tv_nsec >= E9) {
- end_at.tv_sec++;
- end_at.tv_nsec -= E9;
- }
- while (ret_val == 0 && !event_set_)
- ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
- } else {
- while (ret_val == 0 && !event_set_)
- ret_val = pthread_cond_wait(&cond_, &mutex_);
- }
- }
-
- RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
-
- // Reset and signal if set, regardless of why the thread woke up.
- if (event_set_) {
- ret_val = 0;
- event_set_ = false;
- }
- pthread_mutex_unlock(&mutex_);
-
- return ret_val == 0 ? kEventSignaled : kEventTimeout;
-}
-
-EventTypeWrapper EventTimerPosix::Wait(timespec* end_at) {
- int ret_val = 0;
- RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
-
- while (ret_val == 0 && !event_set_)
- ret_val = pthread_cond_timedwait(&cond_, &mutex_, end_at);
-
- RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
-
- // Reset and signal if set, regardless of why the thread woke up.
- if (event_set_) {
- ret_val = 0;
- event_set_ = false;
- }
- pthread_mutex_unlock(&mutex_);
-
- return ret_val == 0 ? kEventSignaled : kEventTimeout;
-}
-
-bool EventTimerPosix::StartTimer(bool periodic, unsigned long time) {
- pthread_mutex_lock(&mutex_);
- if (timer_thread_) {
- if (periodic_) {
- // Timer already started.
- pthread_mutex_unlock(&mutex_);
- return false;
- } else {
- // New one shot timer
- time_ = time;
- created_at_.tv_sec = 0;
- timer_event_->Set();
- pthread_mutex_unlock(&mutex_);
- return true;
- }
- }
-
- // Start the timer thread
- timer_event_.reset(new EventTimerPosix());
- const char* thread_name = "WebRtc_event_timer_thread";
- timer_thread_ = ThreadWrapper::CreateThread(Run, this, thread_name);
- periodic_ = periodic;
- time_ = time;
- bool started = timer_thread_->Start();
- timer_thread_->SetPriority(kRealtimePriority);
- pthread_mutex_unlock(&mutex_);
-
- return started;
-}
-
-bool EventTimerPosix::Run(void* obj) {
- return static_cast<EventTimerPosix*>(obj)->Process();
-}
-
-bool EventTimerPosix::Process() {
- pthread_mutex_lock(&mutex_);
- if (created_at_.tv_sec == 0) {
-#ifndef WEBRTC_MAC
-#ifdef WEBRTC_CLOCK_TYPE_REALTIME
- clock_gettime(CLOCK_REALTIME, &created_at_);
-#else
- clock_gettime(CLOCK_MONOTONIC, &created_at_);
-#endif
-#else
- timeval value;
- struct timezone time_zone;
- time_zone.tz_minuteswest = 0;
- time_zone.tz_dsttime = 0;
- gettimeofday(&value, &time_zone);
- TIMEVAL_TO_TIMESPEC(&value, &created_at_);
-#endif
- count_ = 0;
- }
-
- timespec end_at;
- unsigned long long time = time_ * ++count_;
- end_at.tv_sec = created_at_.tv_sec + time / 1000;
- end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
-
- if (end_at.tv_nsec >= E9) {
- end_at.tv_sec++;
- end_at.tv_nsec -= E9;
- }
-
- pthread_mutex_unlock(&mutex_);
- if (timer_event_->Wait(&end_at) == kEventSignaled)
- return true;
-
- pthread_mutex_lock(&mutex_);
- if (periodic_ || count_ == 1)
- Set();
- pthread_mutex_unlock(&mutex_);
-
- return true;
-}
-
-bool EventTimerPosix::StopTimer() {
- if (timer_event_) {
- timer_event_->Set();
- }
- if (timer_thread_) {
- if (!timer_thread_->Stop()) {
- return false;
- }
- timer_thread_.reset();
- }
- timer_event_.reset();
-
- // Set time to zero to force new reference time for the timer.
- memset(&created_at_, 0, sizeof(created_at_));
- count_ = 0;
- return true;
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/event_timer_posix.h b/webrtc/system_wrappers/source/event_timer_posix.h
deleted file mode 100644
index 21c4ac7..0000000
--- a/webrtc/system_wrappers/source/event_timer_posix.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
-
-#include "webrtc/system_wrappers/include/event_wrapper.h"
-
-#include <pthread.h>
-#include <time.h>
-
-#include "webrtc/system_wrappers/include/thread_wrapper.h"
-
-namespace webrtc {
-
-enum State {
- kUp = 1,
- kDown = 2
-};
-
-class EventTimerPosix : public EventTimerWrapper {
- public:
- EventTimerPosix();
- ~EventTimerPosix() override;
-
- EventTypeWrapper Wait(unsigned long max_time) override;
- bool Set() override;
-
- bool StartTimer(bool periodic, unsigned long time) override;
- bool StopTimer() override;
-
- private:
- static bool Run(void* obj);
- bool Process();
- EventTypeWrapper Wait(timespec* end_at);
-
- private:
- pthread_cond_t cond_;
- pthread_mutex_t mutex_;
- bool event_set_;
-
- rtc::scoped_ptr<ThreadWrapper> timer_thread_;
- rtc::scoped_ptr<EventTimerPosix> timer_event_;
- timespec created_at_;
-
- bool periodic_;
- unsigned long time_; // In ms
- unsigned long count_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
diff --git a/webrtc/system_wrappers/source/event_timer_win.cc b/webrtc/system_wrappers/source/event_timer_win.cc
deleted file mode 100644
index 4c58698..0000000
--- a/webrtc/system_wrappers/source/event_timer_win.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/source/event_timer_win.h"
-
-#include "Mmsystem.h"
-
-namespace webrtc {
-
-// static
-EventTimerWrapper* EventTimerWrapper::Create() {
- return new EventTimerWin();
-}
-
-EventTimerWin::EventTimerWin()
- : event_(::CreateEvent(NULL, // security attributes
- FALSE, // manual reset
- FALSE, // initial state
- NULL)), // name of event
- timerID_(NULL) {
-}
-
-EventTimerWin::~EventTimerWin() {
- StopTimer();
- CloseHandle(event_);
-}
-
-bool EventTimerWin::Set() {
- // Note: setting an event that is already set has no effect.
- return SetEvent(event_) == 1;
-}
-
-EventTypeWrapper EventTimerWin::Wait(unsigned long max_time) {
- unsigned long res = WaitForSingleObject(event_, max_time);
- switch (res) {
- case WAIT_OBJECT_0:
- return kEventSignaled;
- case WAIT_TIMEOUT:
- return kEventTimeout;
- default:
- return kEventError;
- }
-}
-
-bool EventTimerWin::StartTimer(bool periodic, unsigned long time) {
- if (timerID_ != NULL) {
- timeKillEvent(timerID_);
- timerID_ = NULL;
- }
-
- if (periodic) {
- timerID_ = timeSetEvent(time, 0, (LPTIMECALLBACK)HANDLE(event_), 0,
- TIME_PERIODIC | TIME_CALLBACK_EVENT_PULSE);
- } else {
- timerID_ = timeSetEvent(time, 0, (LPTIMECALLBACK)HANDLE(event_), 0,
- TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
- }
-
- return timerID_ != NULL;
-}
-
-bool EventTimerWin::StopTimer() {
- if (timerID_ != NULL) {
- timeKillEvent(timerID_);
- timerID_ = NULL;
- }
-
- return true;
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/event_timer_win.h b/webrtc/system_wrappers/source/event_timer_win.h
deleted file mode 100644
index 163cdde..0000000
--- a/webrtc/system_wrappers/source/event_timer_win.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
-
-#include <windows.h>
-
-#include "webrtc/system_wrappers/include/event_wrapper.h"
-
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-class EventTimerWin : public EventTimerWrapper {
- public:
- EventTimerWin();
- virtual ~EventTimerWin();
-
- virtual EventTypeWrapper Wait(unsigned long max_time);
- virtual bool Set();
-
- virtual bool StartTimer(bool periodic, unsigned long time);
- virtual bool StopTimer();
-
- private:
- HANDLE event_;
- uint32_t timerID_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
diff --git a/webrtc/system_wrappers/source/field_trial.cc b/webrtc/system_wrappers/source/field_trial.cc
new file mode 100644
index 0000000..f1dccc9
--- /dev/null
+++ b/webrtc/system_wrappers/source/field_trial.cc
@@ -0,0 +1,155 @@
+// 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 "system_wrappers/include/field_trial.h"
+
+#include <stddef.h>
+
+#include <map>
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/string_encode.h"
+
+// Simple field trial implementation, which allows client to
+// specify desired flags in InitFieldTrialsFromString.
+namespace webrtc {
+namespace field_trial {
+
+static const char* trials_init_string = NULL;
+
+#ifndef WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
+namespace {
+constexpr char kPersistentStringSeparator = '/';
+// Validates the given field trial string.
+// E.g.:
+// "WebRTC-experimentFoo/Enabled/WebRTC-experimentBar/Enabled100kbps/"
+// Assigns the process to group "Enabled" on WebRTCExperimentFoo trial
+// and to group "Enabled100kbps" on WebRTCExperimentBar.
+//
+// E.g. invalid config:
+// "WebRTC-experiment1/Enabled" (note missing / separator at the end).
+bool FieldTrialsStringIsValidInternal(const absl::string_view trials) {
+ if (trials.empty())
+ return true;
+
+ size_t next_item = 0;
+ std::map<absl::string_view, absl::string_view> field_trials;
+ while (next_item < trials.length()) {
+ size_t name_end = trials.find(kPersistentStringSeparator, next_item);
+ if (name_end == trials.npos || next_item == name_end)
+ return false;
+ size_t group_name_end =
+ trials.find(kPersistentStringSeparator, name_end + 1);
+ if (group_name_end == trials.npos || name_end + 1 == group_name_end)
+ return false;
+ absl::string_view name = trials.substr(next_item, name_end - next_item);
+ absl::string_view group_name =
+ trials.substr(name_end + 1, group_name_end - name_end - 1);
+
+ next_item = group_name_end + 1;
+
+ // Fail if duplicate with different group name.
+ if (field_trials.find(name) != field_trials.end() &&
+ field_trials.find(name)->second != group_name) {
+ return false;
+ }
+
+ field_trials[name] = group_name;
+ }
+
+ return true;
+}
+} // namespace
+
+bool FieldTrialsStringIsValid(const char* trials_string) {
+ return FieldTrialsStringIsValidInternal(trials_string);
+}
+
+void InsertOrReplaceFieldTrialStringsInMap(
+ std::map<std::string, std::string>* fieldtrial_map,
+ const absl::string_view trials_string) {
+ if (FieldTrialsStringIsValidInternal(trials_string)) {
+ std::vector<std::string> tokens;
+ rtc::split(std::string(trials_string), '/', &tokens);
+ // Skip last token which is empty due to trailing '/'.
+ for (size_t idx = 0; idx < tokens.size() - 1; idx += 2) {
+ (*fieldtrial_map)[tokens[idx]] = tokens[idx + 1];
+ }
+ } else {
+ RTC_DCHECK(false) << "Invalid field trials string:" << trials_string;
+ }
+}
+
+std::string MergeFieldTrialsStrings(const char* first, const char* second) {
+ std::map<std::string, std::string> fieldtrial_map;
+ InsertOrReplaceFieldTrialStringsInMap(&fieldtrial_map, first);
+ InsertOrReplaceFieldTrialStringsInMap(&fieldtrial_map, second);
+
+ // Merge into fieldtrial string.
+ std::string merged = "";
+ for (auto const& fieldtrial : fieldtrial_map) {
+ merged += fieldtrial.first + '/' + fieldtrial.second + '/';
+ }
+ return merged;
+}
+
+std::string FindFullName(const std::string& name) {
+ if (trials_init_string == NULL)
+ return std::string();
+
+ std::string trials_string(trials_init_string);
+ if (trials_string.empty())
+ return std::string();
+
+ size_t next_item = 0;
+ while (next_item < trials_string.length()) {
+ // Find next name/value pair in field trial configuration string.
+ size_t field_name_end =
+ trials_string.find(kPersistentStringSeparator, next_item);
+ if (field_name_end == trials_string.npos || field_name_end == next_item)
+ break;
+ size_t field_value_end =
+ trials_string.find(kPersistentStringSeparator, field_name_end + 1);
+ if (field_value_end == trials_string.npos ||
+ field_value_end == field_name_end + 1)
+ break;
+ std::string field_name(trials_string, next_item,
+ field_name_end - next_item);
+ std::string field_value(trials_string, field_name_end + 1,
+ field_value_end - field_name_end - 1);
+ next_item = field_value_end + 1;
+
+ if (name == field_name)
+ return field_value;
+ }
+ return std::string();
+}
+#endif // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
+
+// Optionally initialize field trial from a string.
+void InitFieldTrialsFromString(const char* trials_string) {
+ RTC_LOG(LS_INFO) << "Setting field trial string:" << trials_string;
+#ifndef WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
+ if (trials_string) {
+ RTC_DCHECK(FieldTrialsStringIsValidInternal(trials_string))
+ << "Invalid field trials string:" << trials_string;
+ };
+#endif // WEBRTC_EXCLUDE_FIELD_TRIAL_DEFAULT
+ trials_init_string = trials_string;
+}
+
+const char* GetFieldTrialString() {
+ return trials_init_string;
+}
+
+} // namespace field_trial
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/file_impl.cc b/webrtc/system_wrappers/source/file_impl.cc
deleted file mode 100644
index 0ee0dea..0000000
--- a/webrtc/system_wrappers/source/file_impl.cc
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/source/file_impl.h"
-
-#include <assert.h>
-
-#ifdef _WIN32
-#include <Windows.h>
-#else
-#include <stdarg.h>
-#include <string.h>
-#endif
-
-#include "webrtc/base/checks.h"
-#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
-
-namespace webrtc {
-
-FileWrapper* FileWrapper::Create() {
- return new FileWrapperImpl();
-}
-
-FileWrapperImpl::FileWrapperImpl()
- : rw_lock_(RWLockWrapper::CreateRWLock()),
- id_(NULL),
- managed_file_handle_(true),
- open_(false),
- looping_(false),
- read_only_(false),
- max_size_in_bytes_(0),
- size_in_bytes_(0) {
- memset(file_name_utf8_, 0, kMaxFileNameSize);
-}
-
-FileWrapperImpl::~FileWrapperImpl() {
- if (id_ != NULL && managed_file_handle_) {
- fclose(id_);
- }
-}
-
-int FileWrapperImpl::CloseFile() {
- WriteLockScoped write(*rw_lock_);
- return CloseFileImpl();
-}
-
-int FileWrapperImpl::Rewind() {
- WriteLockScoped write(*rw_lock_);
- if (looping_ || !read_only_) {
- if (id_ != NULL) {
- size_in_bytes_ = 0;
- return fseek(id_, 0, SEEK_SET);
- }
- }
- return -1;
-}
-
-int FileWrapperImpl::SetMaxFileSize(size_t bytes) {
- WriteLockScoped write(*rw_lock_);
- max_size_in_bytes_ = bytes;
- return 0;
-}
-
-int FileWrapperImpl::Flush() {
- WriteLockScoped write(*rw_lock_);
- return FlushImpl();
-}
-
-int FileWrapperImpl::FileName(char* file_name_utf8, size_t size) const {
- ReadLockScoped read(*rw_lock_);
- size_t length = strlen(file_name_utf8_);
- if (length > kMaxFileNameSize) {
- assert(false);
- return -1;
- }
- if (length < 1) {
- return -1;
- }
-
- // Make sure to NULL terminate
- if (size < length) {
- length = size - 1;
- }
- memcpy(file_name_utf8, file_name_utf8_, length);
- file_name_utf8[length] = 0;
- return 0;
-}
-
-bool FileWrapperImpl::Open() const {
- ReadLockScoped read(*rw_lock_);
- return open_;
-}
-
-int FileWrapperImpl::OpenFile(const char* file_name_utf8, bool read_only,
- bool loop, bool text) {
- WriteLockScoped write(*rw_lock_);
- if (id_ != NULL && !managed_file_handle_)
- return -1;
- size_t length = strlen(file_name_utf8);
- if (length > kMaxFileNameSize - 1) {
- return -1;
- }
-
- read_only_ = read_only;
-
- FILE* tmp_id = NULL;
-#if defined _WIN32
- wchar_t wide_file_name[kMaxFileNameSize];
- wide_file_name[0] = 0;
-
- MultiByteToWideChar(CP_UTF8,
- 0, // UTF8 flag
- file_name_utf8,
- -1, // Null terminated string
- wide_file_name,
- kMaxFileNameSize);
- if (text) {
- if (read_only) {
- tmp_id = _wfopen(wide_file_name, L"rt");
- } else {
- tmp_id = _wfopen(wide_file_name, L"wt");
- }
- } else {
- if (read_only) {
- tmp_id = _wfopen(wide_file_name, L"rb");
- } else {
- tmp_id = _wfopen(wide_file_name, L"wb");
- }
- }
-#else
- if (text) {
- if (read_only) {
- tmp_id = fopen(file_name_utf8, "rt");
- } else {
- tmp_id = fopen(file_name_utf8, "wt");
- }
- } else {
- if (read_only) {
- tmp_id = fopen(file_name_utf8, "rb");
- } else {
- tmp_id = fopen(file_name_utf8, "wb");
- }
- }
-#endif
-
- if (tmp_id != NULL) {
- // +1 comes from copying the NULL termination character.
- memcpy(file_name_utf8_, file_name_utf8, length + 1);
- if (id_ != NULL) {
- fclose(id_);
- }
- id_ = tmp_id;
- managed_file_handle_ = true;
- looping_ = loop;
- open_ = true;
- return 0;
- }
- return -1;
-}
-
-int FileWrapperImpl::OpenFromFileHandle(FILE* handle,
- bool manage_file,
- bool read_only,
- bool loop) {
- WriteLockScoped write(*rw_lock_);
- if (!handle)
- return -1;
-
- if (id_ != NULL) {
- if (managed_file_handle_)
- fclose(id_);
- else
- return -1;
- }
-
- id_ = handle;
- managed_file_handle_ = manage_file;
- read_only_ = read_only;
- looping_ = loop;
- open_ = true;
- return 0;
-}
-
-int FileWrapperImpl::Read(void* buf, size_t length) {
- WriteLockScoped write(*rw_lock_);
- if (id_ == NULL)
- return -1;
-
- size_t bytes_read = fread(buf, 1, length, id_);
- if (bytes_read != length && !looping_) {
- CloseFileImpl();
- }
- return static_cast<int>(bytes_read);
-}
-
-int FileWrapperImpl::WriteText(const char* format, ...) {
- WriteLockScoped write(*rw_lock_);
- if (format == NULL)
- return -1;
-
- if (read_only_)
- return -1;
-
- if (id_ == NULL)
- return -1;
-
- va_list args;
- va_start(args, format);
- int num_chars = vfprintf(id_, format, args);
- va_end(args);
-
- if (num_chars >= 0) {
- return num_chars;
- } else {
- CloseFileImpl();
- return -1;
- }
-}
-
-bool FileWrapperImpl::Write(const void* buf, size_t length) {
- WriteLockScoped write(*rw_lock_);
- if (buf == NULL)
- return false;
-
- if (read_only_)
- return false;
-
- if (id_ == NULL)
- return false;
-
- // Check if it's time to stop writing.
- if (max_size_in_bytes_ > 0 &&
- (size_in_bytes_ + length) > max_size_in_bytes_) {
- FlushImpl();
- return false;
- }
-
- size_t num_bytes = fwrite(buf, 1, length, id_);
- if (num_bytes > 0) {
- size_in_bytes_ += num_bytes;
- return true;
- }
-
- CloseFileImpl();
- return false;
-}
-
-int FileWrapperImpl::CloseFileImpl() {
- if (id_ != NULL) {
- if (managed_file_handle_)
- fclose(id_);
- id_ = NULL;
- }
- memset(file_name_utf8_, 0, kMaxFileNameSize);
- open_ = false;
- return 0;
-}
-
-int FileWrapperImpl::FlushImpl() {
- if (id_ != NULL) {
- return fflush(id_);
- }
- return -1;
-}
-
-int FileWrapper::Rewind() {
- RTC_DCHECK(false);
- return -1;
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/file_impl.h b/webrtc/system_wrappers/source/file_impl.h
deleted file mode 100644
index 06ba582..0000000
--- a/webrtc/system_wrappers/source/file_impl.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_
-
-#include <stdio.h>
-
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/system_wrappers/include/file_wrapper.h"
-
-namespace webrtc {
-
-class RWLockWrapper;
-
-class FileWrapperImpl : public FileWrapper {
- public:
- FileWrapperImpl();
- ~FileWrapperImpl() override;
-
- int FileName(char* file_name_utf8, size_t size) const override;
-
- bool Open() const override;
-
- int OpenFile(const char* file_name_utf8,
- bool read_only,
- bool loop = false,
- bool text = false) override;
-
- int OpenFromFileHandle(FILE* handle,
- bool manage_file,
- bool read_only,
- bool loop = false) override;
-
- int CloseFile() override;
- int SetMaxFileSize(size_t bytes) override;
- int Flush() override;
-
- int Read(void* buf, size_t length) override;
- bool Write(const void* buf, size_t length) override;
- int WriteText(const char* format, ...) override;
- int Rewind() override;
-
- private:
- int CloseFileImpl();
- int FlushImpl();
-
- rtc::scoped_ptr<RWLockWrapper> rw_lock_;
-
- FILE* id_;
- bool managed_file_handle_;
- bool open_;
- bool looping_;
- bool read_only_;
- size_t max_size_in_bytes_; // -1 indicates file size limitation is off
- size_t size_in_bytes_;
- char file_name_utf8_[kMaxFileNameSize];
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_
diff --git a/webrtc/system_wrappers/source/logging.cc b/webrtc/system_wrappers/source/logging.cc
deleted file mode 100644
index 6b50d6a..0000000
--- a/webrtc/system_wrappers/source/logging.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/include/logging.h"
-
-#include <string.h>
-
-#include <sstream>
-
-#include "webrtc/common_types.h"
-#include "webrtc/system_wrappers/include/trace.h"
-
-namespace webrtc {
-namespace {
-
-TraceLevel WebRtcSeverity(LoggingSeverity sev) {
- switch (sev) {
- // TODO(ajm): SENSITIVE doesn't have a corresponding webrtc level.
- case LS_SENSITIVE: return kTraceInfo;
- case LS_VERBOSE: return kTraceInfo;
- case LS_INFO: return kTraceTerseInfo;
- case LS_WARNING: return kTraceWarning;
- case LS_ERROR: return kTraceError;
- default: return kTraceNone;
- }
-}
-
-// Return the filename portion of the string (that following the last slash).
-const char* FilenameFromPath(const char* file) {
- const char* end1 = ::strrchr(file, '/');
- const char* end2 = ::strrchr(file, '\\');
- if (!end1 && !end2)
- return file;
- else
- return (end1 > end2) ? end1 + 1 : end2 + 1;
-}
-
-} // namespace
-
-LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
- : severity_(sev) {
- print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
-}
-
-bool LogMessage::Loggable(LoggingSeverity sev) {
- // |level_filter| is a bitmask, unlike libjingle's minimum severity value.
- return WebRtcSeverity(sev) & Trace::level_filter() ? true : false;
-}
-
-LogMessage::~LogMessage() {
- const std::string& str = print_stream_.str();
- Trace::Add(WebRtcSeverity(severity_), kTraceUndefined, 0, "%s", str.c_str());
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/metrics.cc b/webrtc/system_wrappers/source/metrics.cc
new file mode 100644
index 0000000..d428336
--- /dev/null
+++ b/webrtc/system_wrappers/source/metrics.cc
@@ -0,0 +1,328 @@
+// 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 "system_wrappers/include/metrics.h"
+
+#include <algorithm>
+
+#include "rtc_base/constructor_magic.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
+
+// Default implementation of histogram methods for WebRTC clients that do not
+// want to provide their own implementation.
+
+namespace webrtc {
+namespace metrics {
+class Histogram;
+
+namespace {
+// Limit for the maximum number of sample values that can be stored.
+// TODO(asapersson): Consider using bucket count (and set up
+// linearly/exponentially spaced buckets) if samples are logged more frequently.
+const int kMaxSampleMapSize = 300;
+
+class RtcHistogram {
+ public:
+ RtcHistogram(const std::string& name, int min, int max, int bucket_count)
+ : min_(min), max_(max), info_(name, min, max, bucket_count) {
+ RTC_DCHECK_GT(bucket_count, 0);
+ }
+
+ void Add(int sample) {
+ sample = std::min(sample, max_);
+ sample = std::max(sample, min_ - 1); // Underflow bucket.
+
+ MutexLock lock(&mutex_);
+ if (info_.samples.size() == kMaxSampleMapSize &&
+ info_.samples.find(sample) == info_.samples.end()) {
+ return;
+ }
+ ++info_.samples[sample];
+ }
+
+ // Returns a copy (or nullptr if there are no samples) and clears samples.
+ std::unique_ptr<SampleInfo> GetAndReset() {
+ MutexLock lock(&mutex_);
+ if (info_.samples.empty())
+ return nullptr;
+
+ SampleInfo* copy =
+ new SampleInfo(info_.name, info_.min, info_.max, info_.bucket_count);
+
+ std::swap(info_.samples, copy->samples);
+
+ return std::unique_ptr<SampleInfo>(copy);
+ }
+
+ const std::string& name() const { return info_.name; }
+
+ // Functions only for testing.
+ void Reset() {
+ MutexLock lock(&mutex_);
+ info_.samples.clear();
+ }
+
+ int NumEvents(int sample) const {
+ MutexLock lock(&mutex_);
+ const auto it = info_.samples.find(sample);
+ return (it == info_.samples.end()) ? 0 : it->second;
+ }
+
+ int NumSamples() const {
+ int num_samples = 0;
+ MutexLock lock(&mutex_);
+ for (const auto& sample : info_.samples) {
+ num_samples += sample.second;
+ }
+ return num_samples;
+ }
+
+ int MinSample() const {
+ MutexLock lock(&mutex_);
+ return (info_.samples.empty()) ? -1 : info_.samples.begin()->first;
+ }
+
+ std::map<int, int> Samples() const {
+ MutexLock lock(&mutex_);
+ return info_.samples;
+ }
+
+ private:
+ mutable Mutex mutex_;
+ const int min_;
+ const int max_;
+ SampleInfo info_ RTC_GUARDED_BY(mutex_);
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogram);
+};
+
+class RtcHistogramMap {
+ public:
+ RtcHistogramMap() {}
+ ~RtcHistogramMap() {}
+
+ Histogram* GetCountsHistogram(const std::string& name,
+ int min,
+ int max,
+ int bucket_count) {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ if (it != map_.end())
+ return reinterpret_cast<Histogram*>(it->second.get());
+
+ RtcHistogram* hist = new RtcHistogram(name, min, max, bucket_count);
+ map_[name].reset(hist);
+ return reinterpret_cast<Histogram*>(hist);
+ }
+
+ Histogram* GetEnumerationHistogram(const std::string& name, int boundary) {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ if (it != map_.end())
+ return reinterpret_cast<Histogram*>(it->second.get());
+
+ RtcHistogram* hist = new RtcHistogram(name, 1, boundary, boundary + 1);
+ map_[name].reset(hist);
+ return reinterpret_cast<Histogram*>(hist);
+ }
+
+ void GetAndReset(
+ std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) {
+ MutexLock lock(&mutex_);
+ for (const auto& kv : map_) {
+ std::unique_ptr<SampleInfo> info = kv.second->GetAndReset();
+ if (info)
+ histograms->insert(std::make_pair(kv.first, std::move(info)));
+ }
+ }
+
+ // Functions only for testing.
+ void Reset() {
+ MutexLock lock(&mutex_);
+ for (const auto& kv : map_)
+ kv.second->Reset();
+ }
+
+ int NumEvents(const std::string& name, int sample) const {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? 0 : it->second->NumEvents(sample);
+ }
+
+ int NumSamples(const std::string& name) const {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? 0 : it->second->NumSamples();
+ }
+
+ int MinSample(const std::string& name) const {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? -1 : it->second->MinSample();
+ }
+
+ std::map<int, int> Samples(const std::string& name) const {
+ MutexLock lock(&mutex_);
+ const auto& it = map_.find(name);
+ return (it == map_.end()) ? std::map<int, int>() : it->second->Samples();
+ }
+
+ private:
+ mutable Mutex mutex_;
+ std::map<std::string, std::unique_ptr<RtcHistogram>> map_
+ RTC_GUARDED_BY(mutex_);
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogramMap);
+};
+
+// RtcHistogramMap is allocated upon call to Enable().
+// The histogram getter functions, which return pointer values to the histograms
+// in the map, are cached in WebRTC. Therefore, this memory is not freed by the
+// application (the memory will be reclaimed by the OS).
+static RtcHistogramMap* volatile g_rtc_histogram_map = nullptr;
+
+void CreateMap() {
+ RtcHistogramMap* map = rtc::AtomicOps::AcquireLoadPtr(&g_rtc_histogram_map);
+ if (map == nullptr) {
+ RtcHistogramMap* new_map = new RtcHistogramMap();
+ RtcHistogramMap* old_map = rtc::AtomicOps::CompareAndSwapPtr(
+ &g_rtc_histogram_map, static_cast<RtcHistogramMap*>(nullptr), new_map);
+ if (old_map != nullptr)
+ delete new_map;
+ }
+}
+
+// Set the first time we start using histograms. Used to make sure Enable() is
+// not called thereafter.
+#if RTC_DCHECK_IS_ON
+static volatile int g_rtc_histogram_called = 0;
+#endif
+
+// Gets the map (or nullptr).
+RtcHistogramMap* GetMap() {
+#if RTC_DCHECK_IS_ON
+ rtc::AtomicOps::ReleaseStore(&g_rtc_histogram_called, 1);
+#endif
+ return g_rtc_histogram_map;
+}
+} // namespace
+
+#ifndef WEBRTC_EXCLUDE_METRICS_DEFAULT
+// Implementation of histogram methods in
+// webrtc/system_wrappers/interface/metrics.h.
+
+// Histogram with exponentially spaced buckets.
+// Creates (or finds) histogram.
+// The returned histogram pointer is cached (and used for adding samples in
+// subsequent calls).
+Histogram* HistogramFactoryGetCounts(const std::string& name,
+ int min,
+ int max,
+ int bucket_count) {
+ // TODO(asapersson): Alternative implementation will be needed if this
+ // histogram type should be truly exponential.
+ return HistogramFactoryGetCountsLinear(name, min, max, bucket_count);
+}
+
+// Histogram with linearly spaced buckets.
+// Creates (or finds) histogram.
+// The returned histogram pointer is cached (and used for adding samples in
+// subsequent calls).
+Histogram* HistogramFactoryGetCountsLinear(const std::string& name,
+ int min,
+ int max,
+ int bucket_count) {
+ RtcHistogramMap* map = GetMap();
+ if (!map)
+ return nullptr;
+
+ return map->GetCountsHistogram(name, min, max, bucket_count);
+}
+
+// Histogram with linearly spaced buckets.
+// Creates (or finds) histogram.
+// The returned histogram pointer is cached (and used for adding samples in
+// subsequent calls).
+Histogram* HistogramFactoryGetEnumeration(const std::string& name,
+ int boundary) {
+ RtcHistogramMap* map = GetMap();
+ if (!map)
+ return nullptr;
+
+ return map->GetEnumerationHistogram(name, boundary);
+}
+
+// Our default implementation reuses the non-sparse histogram.
+Histogram* SparseHistogramFactoryGetEnumeration(const std::string& name,
+ int boundary) {
+ return HistogramFactoryGetEnumeration(name, boundary);
+}
+
+// Fast path. Adds |sample| to cached |histogram_pointer|.
+void HistogramAdd(Histogram* histogram_pointer, int sample) {
+ RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer);
+ ptr->Add(sample);
+}
+
+#endif // WEBRTC_EXCLUDE_METRICS_DEFAULT
+
+SampleInfo::SampleInfo(const std::string& name,
+ int min,
+ int max,
+ size_t bucket_count)
+ : name(name), min(min), max(max), bucket_count(bucket_count) {}
+
+SampleInfo::~SampleInfo() {}
+
+// Implementation of global functions in metrics.h.
+void Enable() {
+ RTC_DCHECK(g_rtc_histogram_map == nullptr);
+#if RTC_DCHECK_IS_ON
+ RTC_DCHECK_EQ(0, rtc::AtomicOps::AcquireLoad(&g_rtc_histogram_called));
+#endif
+ CreateMap();
+}
+
+void GetAndReset(
+ std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) {
+ histograms->clear();
+ RtcHistogramMap* map = GetMap();
+ if (map)
+ map->GetAndReset(histograms);
+}
+
+void Reset() {
+ RtcHistogramMap* map = GetMap();
+ if (map)
+ map->Reset();
+}
+
+int NumEvents(const std::string& name, int sample) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->NumEvents(name, sample) : 0;
+}
+
+int NumSamples(const std::string& name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->NumSamples(name) : 0;
+}
+
+int MinSample(const std::string& name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->MinSample(name) : -1;
+}
+
+std::map<int, int> Samples(const std::string& name) {
+ RtcHistogramMap* map = GetMap();
+ return map ? map->Samples(name) : std::map<int, int>();
+}
+
+} // namespace metrics
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/metrics_default.cc b/webrtc/system_wrappers/source/metrics_default.cc
deleted file mode 100644
index 48c9111..0000000
--- a/webrtc/system_wrappers/source/metrics_default.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-//
-
-#include "webrtc/system_wrappers/include/metrics.h"
-
-// Default implementation of histogram methods for WebRTC clients that do not
-// want to provide their own implementation.
-
-namespace webrtc {
-namespace metrics {
-
-Histogram* HistogramFactoryGetCounts(const std::string& name, int min, int max,
- int bucket_count) { return NULL; }
-
-Histogram* HistogramFactoryGetEnumeration(const std::string& name,
- int boundary) { return NULL; }
-
-void HistogramAdd(
- Histogram* histogram_pointer, const std::string& name, int sample) {}
-
-} // namespace metrics
-} // namespace webrtc
-
diff --git a/webrtc/system_wrappers/source/rw_lock_generic.cc b/webrtc/system_wrappers/source/rw_lock_generic.cc
deleted file mode 100644
index 9786155..0000000
--- a/webrtc/system_wrappers/source/rw_lock_generic.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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 "webrtc/system_wrappers/source/rw_lock_generic.h"
-
-#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-
-namespace webrtc {
-
-RWLockGeneric::RWLockGeneric()
- : readers_active_(0),
- writer_active_(false),
- readers_waiting_(0),
- writers_waiting_(0) {
- critical_section_ = CriticalSectionWrapper::CreateCriticalSection();
- read_condition_ = ConditionVariableWrapper::CreateConditionVariable();
- write_condition_ = ConditionVariableWrapper::CreateConditionVariable();
-}
-
-RWLockGeneric::~RWLockGeneric() {
- delete write_condition_;
- delete read_condition_;
- delete critical_section_;
-}
-
-void RWLockGeneric::AcquireLockExclusive() {
- CriticalSectionScoped cs(critical_section_);
- if (writer_active_ || readers_active_ > 0) {
- ++writers_waiting_;
- while (writer_active_ || readers_active_ > 0) {
- write_condition_->SleepCS(*critical_section_);
- }
- --writers_waiting_;
- }
- writer_active_ = true;
-}
-
-void RWLockGeneric::ReleaseLockExclusive() {
- CriticalSectionScoped cs(critical_section_);
- writer_active_ = false;
- if (writers_waiting_ > 0) {
- write_condition_->Wake();
- } else if (readers_waiting_ > 0) {
- read_condition_->WakeAll();
- }
-}
-
-void RWLockGeneric::AcquireLockShared() {
- CriticalSectionScoped cs(critical_section_);
- if (writer_active_ || writers_waiting_ > 0) {
- ++readers_waiting_;
-
- while (writer_active_ || writers_waiting_ > 0) {
- read_condition_->SleepCS(*critical_section_);
- }
- --readers_waiting_;
- }
- ++readers_active_;
-}
-
-void RWLockGeneric::ReleaseLockShared() {
- CriticalSectionScoped cs(critical_section_);
- --readers_active_;
- if (readers_active_ == 0 && writers_waiting_ > 0) {
- write_condition_->Wake();
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rw_lock_generic.h b/webrtc/system_wrappers/source/rw_lock_generic.h
deleted file mode 100644
index f0d4456..0000000
--- a/webrtc/system_wrappers/source/rw_lock_generic.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_
-
-#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-class CriticalSectionWrapper;
-class ConditionVariableWrapper;
-
-class RWLockGeneric : public RWLockWrapper {
- public:
- RWLockGeneric();
- ~RWLockGeneric() override;
-
- void AcquireLockExclusive() override;
- void ReleaseLockExclusive() override;
-
- void AcquireLockShared() override;
- void ReleaseLockShared() override;
-
- private:
- CriticalSectionWrapper* critical_section_;
- ConditionVariableWrapper* read_condition_;
- ConditionVariableWrapper* write_condition_;
-
- int readers_active_;
- bool writer_active_;
- int readers_waiting_;
- int writers_waiting_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_
diff --git a/webrtc/system_wrappers/source/rw_lock_win.cc b/webrtc/system_wrappers/source/rw_lock_win.cc
deleted file mode 100644
index 2372b9b..0000000
--- a/webrtc/system_wrappers/source/rw_lock_win.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/source/rw_lock_win.h"
-
-#include "webrtc/system_wrappers/include/trace.h"
-
-namespace webrtc {
-
-static bool native_rw_locks_supported = false;
-static bool module_load_attempted = false;
-static HMODULE library = NULL;
-
-typedef void (WINAPI* InitializeSRWLock)(PSRWLOCK);
-
-typedef void (WINAPI* AcquireSRWLockExclusive)(PSRWLOCK);
-typedef void (WINAPI* ReleaseSRWLockExclusive)(PSRWLOCK);
-
-typedef void (WINAPI* AcquireSRWLockShared)(PSRWLOCK);
-typedef void (WINAPI* ReleaseSRWLockShared)(PSRWLOCK);
-
-InitializeSRWLock initialize_srw_lock;
-AcquireSRWLockExclusive acquire_srw_lock_exclusive;
-AcquireSRWLockShared acquire_srw_lock_shared;
-ReleaseSRWLockShared release_srw_lock_shared;
-ReleaseSRWLockExclusive release_srw_lock_exclusive;
-
-RWLockWin::RWLockWin() {
- initialize_srw_lock(&lock_);
-}
-
-RWLockWin* RWLockWin::Create() {
- if (!LoadModule()) {
- return NULL;
- }
- return new RWLockWin();
-}
-
-void RWLockWin::AcquireLockExclusive() {
- acquire_srw_lock_exclusive(&lock_);
-}
-
-void RWLockWin::ReleaseLockExclusive() {
- release_srw_lock_exclusive(&lock_);
-}
-
-void RWLockWin::AcquireLockShared() {
- acquire_srw_lock_shared(&lock_);
-}
-
-void RWLockWin::ReleaseLockShared() {
- release_srw_lock_shared(&lock_);
-}
-
-bool RWLockWin::LoadModule() {
- if (module_load_attempted) {
- return native_rw_locks_supported;
- }
- module_load_attempted = true;
- // Use native implementation if supported (i.e Vista+)
- library = LoadLibrary(TEXT("Kernel32.dll"));
- if (!library) {
- return false;
- }
- WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll");
-
- initialize_srw_lock =
- (InitializeSRWLock)GetProcAddress(library, "InitializeSRWLock");
-
- acquire_srw_lock_exclusive =
- (AcquireSRWLockExclusive)GetProcAddress(library,
- "AcquireSRWLockExclusive");
- release_srw_lock_exclusive =
- (ReleaseSRWLockExclusive)GetProcAddress(library,
- "ReleaseSRWLockExclusive");
- acquire_srw_lock_shared =
- (AcquireSRWLockShared)GetProcAddress(library, "AcquireSRWLockShared");
- release_srw_lock_shared =
- (ReleaseSRWLockShared)GetProcAddress(library, "ReleaseSRWLockShared");
-
- if (initialize_srw_lock && acquire_srw_lock_exclusive &&
- release_srw_lock_exclusive && acquire_srw_lock_shared &&
- release_srw_lock_shared) {
- WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Native RW Lock");
- native_rw_locks_supported = true;
- }
- return native_rw_locks_supported;
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/sleep.cc b/webrtc/system_wrappers/source/sleep.cc
index 181381f..e2fa486 100644
--- a/webrtc/system_wrappers/source/sleep.cc
+++ b/webrtc/system_wrappers/source/sleep.cc
@@ -9,7 +9,7 @@
*/
// An OS-independent sleep function.
-#include "webrtc/system_wrappers/include/sleep.h"
+#include "system_wrappers/include/sleep.h"
#ifdef _WIN32
// For Sleep()
diff --git a/webrtc/system_wrappers/source/thread.cc b/webrtc/system_wrappers/source/thread.cc
deleted file mode 100644
index 7da1e3d..0000000
--- a/webrtc/system_wrappers/source/thread.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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 "webrtc/system_wrappers/include/thread_wrapper.h"
-
-#if defined(_WIN32)
-#include "webrtc/system_wrappers/source/thread_win.h"
-#else
-#include "webrtc/system_wrappers/source/thread_posix.h"
-#endif
-
-namespace webrtc {
-
-#if defined(_WIN32)
-typedef ThreadWindows ThreadType;
-#else
-typedef ThreadPosix ThreadType;
-#endif
-
-rtc::scoped_ptr<ThreadWrapper> ThreadWrapper::CreateThread(
- ThreadRunFunction func, void* obj, const char* thread_name) {
- return rtc::scoped_ptr<ThreadWrapper>(
- new ThreadType(func, obj, thread_name)).Pass();
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/thread_posix.cc b/webrtc/system_wrappers/source/thread_posix.cc
deleted file mode 100644
index 32ab13c..0000000
--- a/webrtc/system_wrappers/source/thread_posix.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/source/thread_posix.h"
-
-#include <algorithm>
-
-#include <errno.h>
-#include <unistd.h>
-#ifdef WEBRTC_LINUX
-#include <linux/unistd.h>
-#include <sched.h>
-#include <sys/types.h>
-#endif
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/platform_thread.h"
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/include/event_wrapper.h"
-#include "webrtc/system_wrappers/include/sleep.h"
-#include "webrtc/system_wrappers/include/trace.h"
-
-namespace webrtc {
-namespace {
-struct ThreadAttributes {
- ThreadAttributes() { pthread_attr_init(&attr); }
- ~ThreadAttributes() { pthread_attr_destroy(&attr); }
- pthread_attr_t* operator&() { return &attr; }
- pthread_attr_t attr;
-};
-} // namespace
-
-int ConvertToSystemPriority(ThreadPriority priority, int min_prio,
- int max_prio) {
- RTC_DCHECK(max_prio - min_prio > 2);
- const int top_prio = max_prio - 1;
- const int low_prio = min_prio + 1;
-
- switch (priority) {
- case kLowPriority:
- return low_prio;
- case kNormalPriority:
- // The -1 ensures that the kHighPriority is always greater or equal to
- // kNormalPriority.
- return (low_prio + top_prio - 1) / 2;
- case kHighPriority:
- return std::max(top_prio - 2, low_prio);
- case kHighestPriority:
- return std::max(top_prio - 1, low_prio);
- case kRealtimePriority:
- return top_prio;
- }
- RTC_DCHECK(false);
- return low_prio;
-}
-
-// static
-void* ThreadPosix::StartThread(void* param) {
- static_cast<ThreadPosix*>(param)->Run();
- return 0;
-}
-
-ThreadPosix::ThreadPosix(ThreadRunFunction func, void* obj,
- const char* thread_name)
- : run_function_(func),
- obj_(obj),
- stop_event_(false, false),
- name_(thread_name ? thread_name : "webrtc"),
- thread_(0) {
- RTC_DCHECK(name_.length() < 64);
-}
-
-uint32_t ThreadWrapper::GetThreadId() {
- return rtc::CurrentThreadId();
-}
-
-ThreadPosix::~ThreadPosix() {
- RTC_DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-// TODO(pbos): Make Start void, calling code really doesn't support failures
-// here.
-bool ThreadPosix::Start() {
- RTC_DCHECK(thread_checker_.CalledOnValidThread());
- RTC_DCHECK(!thread_) << "Thread already started?";
-
- ThreadAttributes attr;
- // Set the stack stack size to 1M.
- pthread_attr_setstacksize(&attr, 1024 * 1024);
- RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this));
- return true;
-}
-
-bool ThreadPosix::Stop() {
- RTC_DCHECK(thread_checker_.CalledOnValidThread());
- if (!thread_)
- return true;
-
- stop_event_.Set();
- RTC_CHECK_EQ(0, pthread_join(thread_, nullptr));
- thread_ = 0;
-
- return true;
-}
-
-bool ThreadPosix::SetPriority(ThreadPriority priority) {
- RTC_DCHECK(thread_checker_.CalledOnValidThread());
- if (!thread_)
- return false;
-#if defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
- // TODO(tommi): Switch to the same mechanism as Chromium uses for
- // changing thread priorities.
- return true;
-#else
-#ifdef WEBRTC_THREAD_RR
- const int policy = SCHED_RR;
-#else
- const int policy = SCHED_FIFO;
-#endif
- const int min_prio = sched_get_priority_min(policy);
- const int max_prio = sched_get_priority_max(policy);
- if (min_prio == -1 || max_prio == -1) {
- WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
- "unable to retreive min or max priority for threads");
- return false;
- }
-
- if (max_prio - min_prio <= 2)
- return false;
-
- sched_param param;
- param.sched_priority = ConvertToSystemPriority(priority, min_prio, max_prio);
- if (pthread_setschedparam(thread_, policy, &param) != 0) {
- WEBRTC_TRACE(
- kTraceError, kTraceUtility, -1, "unable to set thread priority");
- return false;
- }
-
- return true;
-#endif // defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
-}
-
-void ThreadPosix::Run() {
- if (!name_.empty()) {
- // Setting the thread name may fail (harmlessly) if running inside a
- // sandbox. Ignore failures if they happen.
- rtc::SetCurrentThreadName(name_.substr(0, 63).c_str());
- }
-
- // It's a requirement that for successful thread creation that the run
- // function be called at least once (see RunFunctionIsCalled unit test),
- // so to fullfill that requirement, we use a |do| loop and not |while|.
- do {
- if (!run_function_(obj_))
- break;
- } while (!stop_event_.Wait(0));
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/thread_posix.h b/webrtc/system_wrappers/source/thread_posix.h
deleted file mode 100644
index bcdd732..0000000
--- a/webrtc/system_wrappers/source/thread_posix.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_
-
-#include "webrtc/base/event.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/base/thread_checker.h"
-#include "webrtc/system_wrappers/include/thread_wrapper.h"
-
-#include <pthread.h>
-
-namespace webrtc {
-
-int ConvertToSystemPriority(ThreadPriority priority, int min_prio,
- int max_prio);
-
-class ThreadPosix : public ThreadWrapper {
- public:
- ThreadPosix(ThreadRunFunction func, void* obj, const char* thread_name);
- ~ThreadPosix() override;
-
- // From ThreadWrapper.
- bool Start() override;
- bool Stop() override;
-
- bool SetPriority(ThreadPriority priority) override;
-
- private:
- static void* StartThread(void* param);
-
- void Run();
-
- rtc::ThreadChecker thread_checker_;
- ThreadRunFunction const run_function_;
- void* const obj_;
- rtc::Event stop_event_;
- const std::string name_;
-
- pthread_t thread_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_
diff --git a/webrtc/system_wrappers/source/thread_win.cc b/webrtc/system_wrappers/source/thread_win.cc
deleted file mode 100644
index c421967..0000000
--- a/webrtc/system_wrappers/source/thread_win.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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 "webrtc/system_wrappers/source/thread_win.h"
-
-#include <process.h>
-#include <stdio.h>
-#include <windows.h>
-
-#include "webrtc/base/checks.h"
-#include "webrtc/base/platform_thread.h"
-#include "webrtc/system_wrappers/include/trace.h"
-
-namespace webrtc {
-namespace {
-void CALLBACK RaiseFlag(ULONG_PTR param) {
- *reinterpret_cast<bool*>(param) = true;
-}
-}
-
-ThreadWindows::ThreadWindows(ThreadRunFunction func, void* obj,
- const char* thread_name)
- : run_function_(func),
- obj_(obj),
- stop_(false),
- thread_(NULL),
- name_(thread_name ? thread_name : "webrtc") {
- RTC_DCHECK(func);
-}
-
-ThreadWindows::~ThreadWindows() {
- RTC_DCHECK(main_thread_.CalledOnValidThread());
- RTC_DCHECK(!thread_);
-}
-
-// static
-uint32_t ThreadWrapper::GetThreadId() {
- return GetCurrentThreadId();
-}
-
-// static
-DWORD WINAPI ThreadWindows::StartThread(void* param) {
- static_cast<ThreadWindows*>(param)->Run();
- return 0;
-}
-
-bool ThreadWindows::Start() {
- RTC_DCHECK(main_thread_.CalledOnValidThread());
- RTC_DCHECK(!thread_);
-
- stop_ = false;
-
- // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
- // Set the reserved stack stack size to 1M, which is the default on Windows
- // and Linux.
- DWORD thread_id;
- thread_ = ::CreateThread(NULL, 1024 * 1024, &StartThread, this,
- STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id);
- if (!thread_ ) {
- RTC_DCHECK(false) << "CreateThread failed";
- return false;
- }
-
- return true;
-}
-
-bool ThreadWindows::Stop() {
- RTC_DCHECK(main_thread_.CalledOnValidThread());
- if (thread_) {
- // Set stop_ to |true| on the worker thread.
- QueueUserAPC(&RaiseFlag, thread_, reinterpret_cast<ULONG_PTR>(&stop_));
- WaitForSingleObject(thread_, INFINITE);
- CloseHandle(thread_);
- thread_ = nullptr;
- }
-
- return true;
-}
-
-bool ThreadWindows::SetPriority(ThreadPriority priority) {
- RTC_DCHECK(main_thread_.CalledOnValidThread());
- return thread_ && SetThreadPriority(thread_, priority);
-}
-
-void ThreadWindows::Run() {
- if (!name_.empty())
- rtc::SetCurrentThreadName(name_.c_str());
-
- do {
- // The interface contract of Start/Stop is that for a successfull call to
- // Start, there should be at least one call to the run function. So we
- // call the function before checking |stop_|.
- if (!run_function_(obj_))
- break;
- // Alertable sleep to permit RaiseFlag to run and update |stop_|.
- SleepEx(0, true);
- } while (!stop_);
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/thread_win.h b/webrtc/system_wrappers/source/thread_win.h
deleted file mode 100644
index 34edd6d..0000000
--- a/webrtc/system_wrappers/source/thread_win.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_
-
-#include "webrtc/system_wrappers/include/thread_wrapper.h"
-
-#include <windows.h>
-
-#include "webrtc/base/thread_checker.h"
-
-namespace webrtc {
-
-class ThreadWindows : public ThreadWrapper {
- public:
- ThreadWindows(ThreadRunFunction func, void* obj, const char* thread_name);
- ~ThreadWindows() override;
-
- bool Start() override;
- bool Stop() override;
-
- bool SetPriority(ThreadPriority priority) override;
-
- protected:
- void Run();
-
- private:
- static DWORD WINAPI StartThread(void* param);
-
- ThreadRunFunction const run_function_;
- void* const obj_;
- bool stop_;
- HANDLE thread_;
- const std::string name_;
- rtc::ThreadChecker main_thread_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_
diff --git a/webrtc/system_wrappers/source/trace_impl.cc b/webrtc/system_wrappers/source/trace_impl.cc
deleted file mode 100644
index ffe79b9..0000000
--- a/webrtc/system_wrappers/source/trace_impl.cc
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/source/trace_impl.h"
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "webrtc/base/atomicops.h"
-#ifdef _WIN32
-#include "webrtc/system_wrappers/source/trace_win.h"
-#else
-#include "webrtc/system_wrappers/source/trace_posix.h"
-#endif // _WIN32
-
-#define KEY_LEN_CHARS 31
-
-#ifdef _WIN32
-#pragma warning(disable:4355)
-#endif // _WIN32
-
-namespace webrtc {
-
-const int Trace::kBoilerplateLength = 71;
-const int Trace::kTimestampPosition = 13;
-const int Trace::kTimestampLength = 12;
-volatile int Trace::level_filter_ = kTraceDefault;
-
-// Construct On First Use idiom. Avoids "static initialization order fiasco".
-TraceImpl* TraceImpl::StaticInstance(CountOperation count_operation,
- const TraceLevel level) {
- // Sanities to avoid taking lock unless absolutely necessary (for
- // performance reasons). count_operation == kAddRefNoCreate implies that a
- // message will be written to file.
- if ((level != kTraceAll) && (count_operation == kAddRefNoCreate)) {
- if (!(level & level_filter())) {
- return NULL;
- }
- }
- TraceImpl* impl =
- GetStaticInstance<TraceImpl>(count_operation);
- return impl;
-}
-
-TraceImpl* TraceImpl::GetTrace(const TraceLevel level) {
- return StaticInstance(kAddRefNoCreate, level);
-}
-
-TraceImpl* TraceImpl::CreateInstance() {
-#if defined(_WIN32)
- return new TraceWindows();
-#else
- return new TracePosix();
-#endif
-}
-
-TraceImpl::TraceImpl()
- : callback_(NULL),
- row_count_text_(0),
- file_count_text_(0),
- trace_file_(FileWrapper::Create()) {
-}
-
-TraceImpl::~TraceImpl() {
- trace_file_->Flush();
- trace_file_->CloseFile();
-}
-
-int32_t TraceImpl::AddThreadId(char* trace_message) const {
- uint32_t thread_id = ThreadWrapper::GetThreadId();
- // Messages is 12 characters.
- return sprintf(trace_message, "%10u; ", thread_id);
-}
-
-int32_t TraceImpl::AddLevel(char* sz_message, const TraceLevel level) const {
- const int kMessageLength = 12;
- switch (level) {
- case kTraceTerseInfo:
- // Add the appropriate amount of whitespace.
- memset(sz_message, ' ', kMessageLength);
- sz_message[kMessageLength] = '\0';
- break;
- case kTraceStateInfo:
- sprintf(sz_message, "STATEINFO ; ");
- break;
- case kTraceWarning:
- sprintf(sz_message, "WARNING ; ");
- break;
- case kTraceError:
- sprintf(sz_message, "ERROR ; ");
- break;
- case kTraceCritical:
- sprintf(sz_message, "CRITICAL ; ");
- break;
- case kTraceInfo:
- sprintf(sz_message, "DEBUGINFO ; ");
- break;
- case kTraceModuleCall:
- sprintf(sz_message, "MODULECALL; ");
- break;
- case kTraceMemory:
- sprintf(sz_message, "MEMORY ; ");
- break;
- case kTraceTimer:
- sprintf(sz_message, "TIMER ; ");
- break;
- case kTraceStream:
- sprintf(sz_message, "STREAM ; ");
- break;
- case kTraceApiCall:
- sprintf(sz_message, "APICALL ; ");
- break;
- case kTraceDebug:
- sprintf(sz_message, "DEBUG ; ");
- break;
- default:
- assert(false);
- return 0;
- }
- // All messages are 12 characters.
- return kMessageLength;
-}
-
-int32_t TraceImpl::AddModuleAndId(char* trace_message,
- const TraceModule module,
- const int32_t id) const {
- // Use long int to prevent problems with different definitions of
- // int32_t.
- // TODO(hellner): is this actually a problem? If so, it should be better to
- // clean up int32_t
- const long int idl = id;
- const int kMessageLength = 25;
- if (idl != -1) {
- const unsigned long int id_engine = id >> 16;
- const unsigned long int id_channel = id & 0xffff;
-
- switch (module) {
- case kTraceUndefined:
- // Add the appropriate amount of whitespace.
- memset(trace_message, ' ', kMessageLength);
- trace_message[kMessageLength] = '\0';
- break;
- case kTraceVoice:
- sprintf(trace_message, " VOICE:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceVideo:
- sprintf(trace_message, " VIDEO:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceUtility:
- sprintf(trace_message, " UTILITY:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceRtpRtcp:
- sprintf(trace_message, " RTP/RTCP:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceTransport:
- sprintf(trace_message, " TRANSPORT:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceAudioCoding:
- sprintf(trace_message, "AUDIO CODING:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceSrtp:
- sprintf(trace_message, " SRTP:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceAudioMixerServer:
- sprintf(trace_message, " AUDIO MIX/S:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceAudioMixerClient:
- sprintf(trace_message, " AUDIO MIX/C:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceVideoCoding:
- sprintf(trace_message, "VIDEO CODING:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceVideoMixer:
- // Print sleep time and API call
- sprintf(trace_message, " VIDEO MIX:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceFile:
- sprintf(trace_message, " FILE:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceAudioProcessing:
- sprintf(trace_message, " AUDIO PROC:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceAudioDevice:
- sprintf(trace_message, "AUDIO DEVICE:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceVideoRenderer:
- sprintf(trace_message, "VIDEO RENDER:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceVideoCapture:
- sprintf(trace_message, "VIDEO CAPTUR:%5ld %5ld;", id_engine,
- id_channel);
- break;
- case kTraceRemoteBitrateEstimator:
- sprintf(trace_message, " BWE RBE:%5ld %5ld;", id_engine,
- id_channel);
- break;
- }
- } else {
- switch (module) {
- case kTraceUndefined:
- // Add the appropriate amount of whitespace.
- memset(trace_message, ' ', kMessageLength);
- trace_message[kMessageLength] = '\0';
- break;
- case kTraceVoice:
- sprintf(trace_message, " VOICE:%11ld;", idl);
- break;
- case kTraceVideo:
- sprintf(trace_message, " VIDEO:%11ld;", idl);
- break;
- case kTraceUtility:
- sprintf(trace_message, " UTILITY:%11ld;", idl);
- break;
- case kTraceRtpRtcp:
- sprintf(trace_message, " RTP/RTCP:%11ld;", idl);
- break;
- case kTraceTransport:
- sprintf(trace_message, " TRANSPORT:%11ld;", idl);
- break;
- case kTraceAudioCoding:
- sprintf(trace_message, "AUDIO CODING:%11ld;", idl);
- break;
- case kTraceSrtp:
- sprintf(trace_message, " SRTP:%11ld;", idl);
- break;
- case kTraceAudioMixerServer:
- sprintf(trace_message, " AUDIO MIX/S:%11ld;", idl);
- break;
- case kTraceAudioMixerClient:
- sprintf(trace_message, " AUDIO MIX/C:%11ld;", idl);
- break;
- case kTraceVideoCoding:
- sprintf(trace_message, "VIDEO CODING:%11ld;", idl);
- break;
- case kTraceVideoMixer:
- sprintf(trace_message, " VIDEO MIX:%11ld;", idl);
- break;
- case kTraceFile:
- sprintf(trace_message, " FILE:%11ld;", idl);
- break;
- case kTraceAudioProcessing:
- sprintf(trace_message, " AUDIO PROC:%11ld;", idl);
- break;
- case kTraceAudioDevice:
- sprintf(trace_message, "AUDIO DEVICE:%11ld;", idl);
- break;
- case kTraceVideoRenderer:
- sprintf(trace_message, "VIDEO RENDER:%11ld;", idl);
- break;
- case kTraceVideoCapture:
- sprintf(trace_message, "VIDEO CAPTUR:%11ld;", idl);
- break;
- case kTraceRemoteBitrateEstimator:
- sprintf(trace_message, " BWE RBE:%11ld;", idl);
- break;
- }
- }
- return kMessageLength;
-}
-
-int32_t TraceImpl::SetTraceFileImpl(const char* file_name_utf8,
- const bool add_file_counter) {
- rtc::CritScope lock(&crit_);
-
- trace_file_->Flush();
- trace_file_->CloseFile();
-
- if (file_name_utf8) {
- if (add_file_counter) {
- file_count_text_ = 1;
-
- char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize];
- CreateFileName(file_name_utf8, file_name_with_counter_utf8,
- file_count_text_);
- if (trace_file_->OpenFile(file_name_with_counter_utf8, false, false,
- true) == -1) {
- return -1;
- }
- } else {
- file_count_text_ = 0;
- if (trace_file_->OpenFile(file_name_utf8, false, false, true) == -1) {
- return -1;
- }
- }
- }
- row_count_text_ = 0;
- return 0;
-}
-
-int32_t TraceImpl::TraceFileImpl(
- char file_name_utf8[FileWrapper::kMaxFileNameSize]) {
- rtc::CritScope lock(&crit_);
- return trace_file_->FileName(file_name_utf8, FileWrapper::kMaxFileNameSize);
-}
-
-int32_t TraceImpl::SetTraceCallbackImpl(TraceCallback* callback) {
- rtc::CritScope lock(&crit_);
- callback_ = callback;
- return 0;
-}
-
-int32_t TraceImpl::AddMessage(
- char* trace_message,
- const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
- const uint16_t written_so_far) const {
- int length = 0;
- if (written_so_far >= WEBRTC_TRACE_MAX_MESSAGE_SIZE) {
- return -1;
- }
- // - 2 to leave room for newline and NULL termination.
-#ifdef _WIN32
- length = _snprintf(trace_message,
- WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
- "%s", msg);
- if (length < 0) {
- length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
- trace_message[length] = 0;
- }
-#else
- length = snprintf(trace_message,
- WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
- "%s", msg);
- if (length < 0 ||
- length > WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2) {
- length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
- trace_message[length] = 0;
- }
-#endif
- // Length with NULL termination.
- return length + 1;
-}
-
-void TraceImpl::AddMessageToList(
- const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
- const uint16_t length,
- const TraceLevel level) {
- rtc::CritScope lock(&crit_);
- if (callback_)
- callback_->Print(level, trace_message, length);
- WriteToFile(trace_message, length);
-}
-
-void TraceImpl::WriteToFile(const char* msg, uint16_t length) {
- if (!trace_file_->Open())
- return;
-
- if (row_count_text_ > WEBRTC_TRACE_MAX_FILE_SIZE) {
- // wrap file
- row_count_text_ = 0;
- trace_file_->Flush();
-
- if (file_count_text_ == 0) {
- trace_file_->Rewind();
- } else {
- char old_file_name[FileWrapper::kMaxFileNameSize];
- char new_file_name[FileWrapper::kMaxFileNameSize];
-
- // get current name
- trace_file_->FileName(old_file_name, FileWrapper::kMaxFileNameSize);
- trace_file_->CloseFile();
-
- file_count_text_++;
-
- UpdateFileName(old_file_name, new_file_name, file_count_text_);
-
- if (trace_file_->OpenFile(new_file_name, false, false, true) == -1) {
- return;
- }
- }
- }
- if (row_count_text_ == 0) {
- char message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
- int32_t length = AddDateTimeInfo(message);
- if (length != -1) {
- message[length] = 0;
- message[length - 1] = '\n';
- trace_file_->Write(message, length);
- row_count_text_++;
- }
- }
-
- char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
- memcpy(trace_message, msg, length);
- trace_message[length] = 0;
- trace_message[length - 1] = '\n';
- trace_file_->Write(trace_message, length);
- row_count_text_++;
-}
-
-void TraceImpl::AddImpl(const TraceLevel level,
- const TraceModule module,
- const int32_t id,
- const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE]) {
- if (!TraceCheck(level))
- return;
-
- char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
- char* message_ptr = &trace_message[0];
- int32_t len = AddLevel(message_ptr, level);
- if (len == -1)
- return;
-
- message_ptr += len;
- int32_t ack_len = len;
-
- len = AddTime(message_ptr, level);
- if (len == -1)
- return;
-
- message_ptr += len;
- ack_len += len;
-
- len = AddModuleAndId(message_ptr, module, id);
- if (len == -1)
- return;
-
- message_ptr += len;
- ack_len += len;
-
- len = AddThreadId(message_ptr);
- if (len < 0)
- return;
-
- message_ptr += len;
- ack_len += len;
-
- len = AddMessage(message_ptr, msg, static_cast<uint16_t>(ack_len));
- if (len == -1)
- return;
-
- ack_len += len;
- AddMessageToList(trace_message, static_cast<uint16_t>(ack_len), level);
-}
-
-bool TraceImpl::TraceCheck(const TraceLevel level) const {
- return (level & level_filter()) ? true : false;
-}
-
-bool TraceImpl::UpdateFileName(
- const char file_name_utf8[FileWrapper::kMaxFileNameSize],
- char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
- const uint32_t new_count) const {
- int32_t length = (int32_t)strlen(file_name_utf8);
- if (length < 0) {
- return false;
- }
-
- int32_t length_without_file_ending = length - 1;
- while (length_without_file_ending > 0) {
- if (file_name_utf8[length_without_file_ending] == '.') {
- break;
- } else {
- length_without_file_ending--;
- }
- }
- if (length_without_file_ending == 0) {
- length_without_file_ending = length;
- }
- int32_t length_to_ = length_without_file_ending - 1;
- while (length_to_ > 0) {
- if (file_name_utf8[length_to_] == '_') {
- break;
- } else {
- length_to_--;
- }
- }
-
- memcpy(file_name_with_counter_utf8, file_name_utf8, length_to_);
- sprintf(file_name_with_counter_utf8 + length_to_, "_%lu%s",
- static_cast<long unsigned int>(new_count),
- file_name_utf8 + length_without_file_ending);
- return true;
-}
-
-bool TraceImpl::CreateFileName(
- const char file_name_utf8[FileWrapper::kMaxFileNameSize],
- char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
- const uint32_t new_count) const {
- int32_t length = (int32_t)strlen(file_name_utf8);
- if (length < 0) {
- return false;
- }
-
- int32_t length_without_file_ending = length - 1;
- while (length_without_file_ending > 0) {
- if (file_name_utf8[length_without_file_ending] == '.') {
- break;
- } else {
- length_without_file_ending--;
- }
- }
- if (length_without_file_ending == 0) {
- length_without_file_ending = length;
- }
- memcpy(file_name_with_counter_utf8, file_name_utf8,
- length_without_file_ending);
- sprintf(file_name_with_counter_utf8 + length_without_file_ending, "_%lu%s",
- static_cast<long unsigned int>(new_count),
- file_name_utf8 + length_without_file_ending);
- return true;
-}
-
-// static
-void Trace::CreateTrace() {
- TraceImpl::StaticInstance(kAddRef);
-}
-
-// static
-void Trace::ReturnTrace() {
- TraceImpl::StaticInstance(kRelease);
-}
-
-// static
-int32_t Trace::TraceFile(char file_name[FileWrapper::kMaxFileNameSize]) {
- TraceImpl* trace = TraceImpl::GetTrace();
- if (trace) {
- int ret_val = trace->TraceFileImpl(file_name);
- ReturnTrace();
- return ret_val;
- }
- return -1;
-}
-
-// static
-void Trace::set_level_filter(int filter) {
- rtc::AtomicOps::ReleaseStore(&level_filter_, filter);
-}
-
-// static
-int Trace::level_filter() {
- return rtc::AtomicOps::AcquireLoad(&level_filter_);
-}
-
-// static
-int32_t Trace::SetTraceFile(const char* file_name,
- const bool add_file_counter) {
- TraceImpl* trace = TraceImpl::GetTrace();
- if (trace) {
- int ret_val = trace->SetTraceFileImpl(file_name, add_file_counter);
- ReturnTrace();
- return ret_val;
- }
- return -1;
-}
-
-int32_t Trace::SetTraceCallback(TraceCallback* callback) {
- TraceImpl* trace = TraceImpl::GetTrace();
- if (trace) {
- int ret_val = trace->SetTraceCallbackImpl(callback);
- ReturnTrace();
- return ret_val;
- }
- return -1;
-}
-
-void Trace::Add(const TraceLevel level, const TraceModule module,
- const int32_t id, const char* msg, ...) {
- TraceImpl* trace = TraceImpl::GetTrace(level);
- if (trace) {
- if (trace->TraceCheck(level)) {
- char temp_buff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
- char* buff = 0;
- if (msg) {
- va_list args;
- va_start(args, msg);
-#ifdef _WIN32
- _vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
-#else
- vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
-#endif
- va_end(args);
- buff = temp_buff;
- }
- trace->AddImpl(level, module, id, buff);
- }
- ReturnTrace();
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/trace_impl.h b/webrtc/system_wrappers/source/trace_impl.h
deleted file mode 100644
index ed49d9d..0000000
--- a/webrtc/system_wrappers/source/trace_impl.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_
-
-#include "webrtc/base/criticalsection.h"
-#include "webrtc/base/scoped_ptr.h"
-#include "webrtc/system_wrappers/include/event_wrapper.h"
-#include "webrtc/system_wrappers/include/file_wrapper.h"
-#include "webrtc/system_wrappers/include/static_instance.h"
-#include "webrtc/system_wrappers/include/thread_wrapper.h"
-#include "webrtc/system_wrappers/include/trace.h"
-
-namespace webrtc {
-
-#define WEBRTC_TRACE_MAX_MESSAGE_SIZE 1024
-// Total buffer size is WEBRTC_TRACE_NUM_ARRAY (number of buffer partitions) *
-// WEBRTC_TRACE_MAX_QUEUE (number of lines per buffer partition) *
-// WEBRTC_TRACE_MAX_MESSAGE_SIZE (number of 1 byte charachters per line) =
-// 1 or 4 Mbyte.
-
-#define WEBRTC_TRACE_MAX_FILE_SIZE 100*1000
-// Number of rows that may be written to file. On average 110 bytes per row (max
-// 256 bytes per row). So on average 110*100*1000 = 11 Mbyte, max 256*100*1000 =
-// 25.6 Mbyte
-
-class TraceImpl : public Trace {
- public:
- virtual ~TraceImpl();
-
- static TraceImpl* CreateInstance();
- static TraceImpl* GetTrace(const TraceLevel level = kTraceAll);
-
- int32_t SetTraceFileImpl(const char* file_name, const bool add_file_counter);
- int32_t TraceFileImpl(char file_name[FileWrapper::kMaxFileNameSize]);
-
- int32_t SetTraceCallbackImpl(TraceCallback* callback);
-
- void AddImpl(const TraceLevel level, const TraceModule module,
- const int32_t id, const char* msg);
-
- bool TraceCheck(const TraceLevel level) const;
-
- protected:
- TraceImpl();
-
- static TraceImpl* StaticInstance(CountOperation count_operation,
- const TraceLevel level = kTraceAll);
-
- int32_t AddThreadId(char* trace_message) const;
-
- // OS specific implementations.
- virtual int32_t AddTime(char* trace_message,
- const TraceLevel level) const = 0;
-
- virtual int32_t AddDateTimeInfo(char* trace_message) const = 0;
-
- private:
- friend class Trace;
-
- int32_t AddLevel(char* sz_message, const TraceLevel level) const;
-
- int32_t AddModuleAndId(char* trace_message, const TraceModule module,
- const int32_t id) const;
-
- int32_t AddMessage(char* trace_message,
- const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
- const uint16_t written_so_far) const;
-
- void AddMessageToList(
- const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
- const uint16_t length,
- const TraceLevel level);
-
- bool UpdateFileName(
- const char file_name_utf8[FileWrapper::kMaxFileNameSize],
- char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
- const uint32_t new_count) const;
-
- bool CreateFileName(
- const char file_name_utf8[FileWrapper::kMaxFileNameSize],
- char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
- const uint32_t new_count) const;
-
- void WriteToFile(const char* msg, uint16_t length)
- EXCLUSIVE_LOCKS_REQUIRED(crit_);
-
- TraceCallback* callback_ GUARDED_BY(crit_);
- uint32_t row_count_text_ GUARDED_BY(crit_);
- uint32_t file_count_text_ GUARDED_BY(crit_);
-
- const rtc::scoped_ptr<FileWrapper> trace_file_ GUARDED_BY(crit_);
- rtc::CriticalSection crit_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_
diff --git a/webrtc/system_wrappers/source/trace_posix.cc b/webrtc/system_wrappers/source/trace_posix.cc
deleted file mode 100644
index cb702d8..0000000
--- a/webrtc/system_wrappers/source/trace_posix.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/source/trace_posix.h"
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-
-namespace webrtc {
-
-TracePosix::TracePosix()
- : crit_sect_(*CriticalSectionWrapper::CreateCriticalSection()) {
- struct timeval system_time_high_res;
- gettimeofday(&system_time_high_res, 0);
- prev_api_tick_count_ = prev_tick_count_ = system_time_high_res.tv_sec;
-}
-
-TracePosix::~TracePosix() {
- delete &crit_sect_;
-}
-
-int32_t TracePosix::AddTime(char* trace_message, const TraceLevel level) const {
- struct timeval system_time_high_res;
- if (gettimeofday(&system_time_high_res, 0) == -1) {
- return -1;
- }
- struct tm buffer;
- const struct tm* system_time =
- localtime_r(&system_time_high_res.tv_sec, &buffer);
-
- const uint32_t ms_time = system_time_high_res.tv_usec / 1000;
- uint32_t prev_tickCount = 0;
- {
- CriticalSectionScoped lock(&crit_sect_);
- if (level == kTraceApiCall) {
- prev_tickCount = prev_tick_count_;
- prev_tick_count_ = ms_time;
- } else {
- prev_tickCount = prev_api_tick_count_;
- prev_api_tick_count_ = ms_time;
- }
- }
-
- uint32_t dw_delta_time = ms_time - prev_tickCount;
- if (prev_tickCount == 0) {
- dw_delta_time = 0;
- }
- if (dw_delta_time > 0x0fffffff) {
- // Either wraparound or data race.
- dw_delta_time = 0;
- }
- if (dw_delta_time > 99999) {
- dw_delta_time = 99999;
- }
-
- sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5lu) ", system_time->tm_hour,
- system_time->tm_min, system_time->tm_sec, ms_time,
- static_cast<unsigned long>(dw_delta_time));
- // Messages are 22 characters.
- return 22;
-}
-
-int32_t TracePosix::AddDateTimeInfo(char* trace_message) const {
- time_t t;
- time(&t);
- char buffer[26]; // man ctime says buffer should have room for >=26 bytes.
- sprintf(trace_message, "Local Date: %s", ctime_r(&t, buffer));
- int32_t len = static_cast<int32_t>(strlen(trace_message));
-
- if ('\n' == trace_message[len - 1]) {
- trace_message[len - 1] = '\0';
- --len;
- }
-
- // Messages is 12 characters.
- return len + 1;
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/trace_posix.h b/webrtc/system_wrappers/source/trace_posix.h
deleted file mode 100644
index 25dfeec..0000000
--- a/webrtc/system_wrappers/source/trace_posix.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_
-
-#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/source/trace_impl.h"
-
-namespace webrtc {
-
-class TracePosix : public TraceImpl {
- public:
- TracePosix();
- ~TracePosix() override;
-
- // This method can be called on several different threads different from
- // the creating thread.
- int32_t AddTime(char* trace_message, const TraceLevel level) const override;
-
- int32_t AddDateTimeInfo(char* trace_message) const override;
-
- private:
- volatile mutable uint32_t prev_api_tick_count_;
- volatile mutable uint32_t prev_tick_count_;
-
- CriticalSectionWrapper& crit_sect_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_
diff --git a/webrtc/system_wrappers/source/trace_win.cc b/webrtc/system_wrappers/source/trace_win.cc
deleted file mode 100644
index 4caedfc..0000000
--- a/webrtc/system_wrappers/source/trace_win.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/source/trace_win.h"
-
-#include <assert.h>
-#include <stdarg.h>
-
-#include "Mmsystem.h"
-
-namespace webrtc {
-TraceWindows::TraceWindows()
- : prev_api_tick_count_(0),
- prev_tick_count_(0) {
-}
-
-TraceWindows::~TraceWindows() {
-}
-
-int32_t TraceWindows::AddTime(char* trace_message,
- const TraceLevel level) const {
- uint32_t dw_current_time = timeGetTime();
- SYSTEMTIME system_time;
- GetSystemTime(&system_time);
-
- if (level == kTraceApiCall) {
- uint32_t dw_delta_time = dw_current_time - prev_tick_count_;
- prev_tick_count_ = dw_current_time;
-
- if (prev_tick_count_ == 0) {
- dw_delta_time = 0;
- }
- if (dw_delta_time > 0x0fffffff) {
- // Either wrap-around or data race.
- dw_delta_time = 0;
- }
- if (dw_delta_time > 99999) {
- dw_delta_time = 99999;
- }
-
- sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5u) ", system_time.wHour,
- system_time.wMinute, system_time.wSecond,
- system_time.wMilliseconds, dw_delta_time);
- } else {
- uint32_t dw_delta_time = dw_current_time - prev_api_tick_count_;
- prev_api_tick_count_ = dw_current_time;
-
- if (prev_api_tick_count_ == 0) {
- dw_delta_time = 0;
- }
- if (dw_delta_time > 0x0fffffff) {
- // Either wraparound or data race.
- dw_delta_time = 0;
- }
- if (dw_delta_time > 99999) {
- dw_delta_time = 99999;
- }
- sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5u) ", system_time.wHour,
- system_time.wMinute, system_time.wSecond,
- system_time.wMilliseconds, dw_delta_time);
- }
- return 22;
-}
-
-int32_t TraceWindows::AddDateTimeInfo(char* trace_message) const {
- prev_api_tick_count_ = timeGetTime();
- prev_tick_count_ = prev_api_tick_count_;
-
- SYSTEMTIME sys_time;
- GetLocalTime(&sys_time);
-
- TCHAR sz_date_str[20];
- TCHAR sz_time_str[20];
-
- // Create date string (e.g. Apr 04 2002)
- GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &sys_time, TEXT("MMM dd yyyy"),
- sz_date_str, 20);
-
- // Create time string (e.g. 15:32:08)
- GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &sys_time, TEXT("HH':'mm':'ss"),
- sz_time_str, 20);
-
- sprintf(trace_message, "Local Date: %ls Local Time: %ls", sz_date_str,
- sz_time_str);
-
- // Include NULL termination (hence + 1).
- return static_cast<int32_t>(strlen(trace_message) + 1);
-}
-
-} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/trace_win.h b/webrtc/system_wrappers/source/trace_win.h
deleted file mode 100644
index 1311b23..0000000
--- a/webrtc/system_wrappers/source/trace_win.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_
-#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_
-
-#include <stdio.h>
-#include <windows.h>
-
-#include "webrtc/system_wrappers/source/trace_impl.h"
-
-namespace webrtc {
-
-class TraceWindows : public TraceImpl {
- public:
- TraceWindows();
- virtual ~TraceWindows();
-
- virtual int32_t AddTime(char* trace_message, const TraceLevel level) const;
-
- virtual int32_t AddDateTimeInfo(char* trace_message) const;
- private:
- volatile mutable uint32_t prev_api_tick_count_;
- volatile mutable uint32_t prev_tick_count_;
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_
diff --git a/webrtc/third_party/pffft/BUILD.gn b/webrtc/third_party/pffft/BUILD.gn
new file mode 100644
index 0000000..7d6c537
--- /dev/null
+++ b/webrtc/third_party/pffft/BUILD.gn
@@ -0,0 +1,110 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/arm.gni")
+import("//testing/libfuzzer/fuzzer_test.gni")
+import("//testing/test.gni")
+
+config("common_config") {
+ if (is_win) {
+ defines = [
+ # Required to use math constants from math.h.
+ "_USE_MATH_DEFINES",
+ ]
+ }
+
+ # PFFFT doesn't support SIMD on some cpus, so build a scalar version.
+ if ((current_cpu == "arm" && !arm_use_neon) || current_cpu == "mipsel" ||
+ current_cpu == "mips64el" || current_cpu == "ppc64" ||
+ current_cpu == "s390x") {
+ defines = [ "PFFFT_SIMD_DISABLE" ]
+ }
+}
+
+static_library("pffft") {
+ configs += [ ":common_config" ]
+ sources = [
+ "src/pffft.c",
+ "src/pffft.h",
+ ]
+}
+
+# Fuzzing.
+
+group("fuzzers") {
+ testonly = true
+ deps = [
+ ":pffft_complex_fuzzer",
+ ":pffft_real_fuzzer",
+ ]
+}
+
+fuzzer_testdata_dir = "$target_gen_dir/testdata"
+
+action("generate_pffft_fuzzer_corpus") {
+ script = "generate_seed_corpus.py"
+ sources = [ "generate_seed_corpus.py" ]
+ args = [ rebase_path(fuzzer_testdata_dir, root_build_dir) ]
+ outputs = [ fuzzer_testdata_dir ]
+}
+
+fuzzer_test("pffft_complex_fuzzer") {
+ sources = [ "pffft_fuzzer.cc" ]
+ cflags = [ "-DTRANSFORM_COMPLEX" ]
+ deps = [ ":pffft" ]
+ seed_corpus = fuzzer_testdata_dir
+ seed_corpus_deps = [ ":generate_pffft_fuzzer_corpus" ]
+}
+
+fuzzer_test("pffft_real_fuzzer") {
+ sources = [ "pffft_fuzzer.cc" ]
+ cflags = [ "-DTRANSFORM_REAL" ]
+ deps = [ ":pffft" ]
+ seed_corpus = fuzzer_testdata_dir
+ seed_corpus_deps = [ ":generate_pffft_fuzzer_corpus" ]
+}
+
+# Unit tests and benchmark.
+
+# This target must be used only for testing and benchmark purposes.
+static_library("fftpack") {
+ testonly = true
+ configs += [ ":common_config" ]
+ sources = [
+ "src/fftpack.c",
+ "src/fftpack.h",
+ ]
+ visibility = [ ":*" ]
+}
+
+config("pffft_benchmark_internal_config") {
+ cflags = [
+ # test_pffft.c contains an `exit(1)` following a `break` statement.
+ "-Wno-unreachable-code",
+ ]
+}
+
+executable("pffft_benchmark") {
+ testonly = true
+ configs += [
+ ":common_config",
+ ":pffft_benchmark_internal_config",
+ ]
+ sources = [ "src/test_pffft.c" ]
+ deps = [
+ ":fftpack",
+ ":pffft",
+ ]
+}
+
+test("pffft_unittest") {
+ testonly = true
+ sources = [ "pffft_unittest.cc" ]
+ deps = [
+ ":fftpack",
+ ":pffft",
+ "//testing/gtest",
+ "//testing/gtest:gtest_main",
+ ]
+}
diff --git a/webrtc/third_party/pffft/LICENSE b/webrtc/third_party/pffft/LICENSE
new file mode 100644
index 0000000..b37aae8
--- /dev/null
+++ b/webrtc/third_party/pffft/LICENSE
@@ -0,0 +1 @@
+Q29weXJpZ2h0IChjKSAyMDEzICBKdWxpZW4gUG9tbWllciAoIHBvbW1pZXJAbW9kYXJ0dC5jb20gKQoKQmFzZWQgb24gb3JpZ2luYWwgZm9ydHJhbiA3NyBjb2RlIGZyb20gRkZUUEFDS3Y0IGZyb20gTkVUTElCLAphdXRob3JlZCBieSBEciBQYXVsIFN3YXJ6dHJhdWJlciBvZiBOQ0FSLCBpbiAxOTg1LgoKQXMgY29uZmlybWVkIGJ5IHRoZSBOQ0FSIGZmdHBhY2sgc29mdHdhcmUgY3VyYXRvcnMsIHRoZSBmb2xsb3dpbmcKRkZUUEFDS3Y1IGxpY2Vuc2UgYXBwbGllcyB0byBGRlRQQUNLdjQgc291cmNlcy4gTXkgY2hhbmdlcyBhcmUKcmVsZWFzZWQgdW5kZXIgdGhlIHNhbWUgdGVybXMuCgpGRlRQQUNLIGxpY2Vuc2U6CgpodHRwOi8vd3d3LmNpc2wudWNhci5lZHUvY3NzL3NvZnR3YXJlL2ZmdHBhY2s1L2Z0cGsuaHRtbAoKQ29weXJpZ2h0IChjKSAyMDA0IHRoZSBVbml2ZXJzaXR5IENvcnBvcmF0aW9uIGZvciBBdG1vc3BoZXJpYwpSZXNlYXJjaCAoIlVDQVIiKS4gQWxsIHJpZ2h0cyByZXNlcnZlZC4gRGV2ZWxvcGVkIGJ5IE5DQVIncwpDb21wdXRhdGlvbmFsIGFuZCBJbmZvcm1hdGlvbiBTeXN0ZW1zIExhYm9yYXRvcnksIFVDQVIsCnd3dy5jaXNsLnVjYXIuZWR1LgoKUmVkaXN0cmlidXRpb24gYW5kIHVzZSBvZiB0aGUgU29mdHdhcmUgaW4gc291cmNlIGFuZCBiaW5hcnkgZm9ybXMsCndpdGggb3Igd2l0aG91dCBtb2RpZmljYXRpb24sIGlzIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZQpmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUgbWV0OgoKLSBOZWl0aGVyIHRoZSBuYW1lcyBvZiBOQ0FSJ3MgQ29tcHV0YXRpb25hbCBhbmQgSW5mb3JtYXRpb24gU3lzdGVtcwpMYWJvcmF0b3J5LCB0aGUgVW5pdmVyc2l0eSBDb3Jwb3JhdGlvbiBmb3IgQXRtb3NwaGVyaWMgUmVzZWFyY2gsCm5vciB0aGUgbmFtZXMgb2YgaXRzIHNwb25zb3JzIG9yIGNvbnRyaWJ1dG9ycyBtYXkgYmUgdXNlZCB0bwplbmRvcnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZCBmcm9tIHRoaXMgU29mdHdhcmUgd2l0aG91dApzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgotIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0Cm5vdGljZXMsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zLCBhbmQgdGhlIGRpc2NsYWltZXIgYmVsb3cuCgotIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0Cm5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMsIGFuZCB0aGUgZGlzY2xhaW1lciBiZWxvdyBpbiB0aGUKZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlCmRpc3RyaWJ1dGlvbi4KClRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwKRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRgpNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORApOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBDT05UUklCVVRPUlMgT1IgQ09QWVJJR0hUCkhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFMLApFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4KQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4KQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIFdJVEggVEhFClNPRlRXQVJFLgo= \ No newline at end of file
diff --git a/webrtc/third_party/pffft/meson.build b/webrtc/third_party/pffft/meson.build
new file mode 100644
index 0000000..c1eb5c6
--- /dev/null
+++ b/webrtc/third_party/pffft/meson.build
@@ -0,0 +1,21 @@
+pffft_sources = [
+ 'src/pffft.c',
+]
+
+pffft_cflags = [ '-D_GNU_SOURCE' ]
+
+if (have_arm and not have_neon) or (have_mips and host_machine.endian() == 'little') or have_mips64
+ pffft_cflags += [ '-DPFFFT_SIMD_DISABLE' ]
+endif
+
+libpffft = static_library('libpffft',
+ pffft_sources,
+ dependencies: common_deps,
+ include_directories: webrtc_inc,
+ c_args : common_cflags + pffft_cflags
+)
+
+pffft_dep = declare_dependency(
+ link_with: libpffft
+)
+
diff --git a/webrtc/third_party/pffft/src/pffft.c b/webrtc/third_party/pffft/src/pffft.c
new file mode 100644
index 0000000..bdac4d7
--- /dev/null
+++ b/webrtc/third_party/pffft/src/pffft.c
@@ -0,0 +1,1881 @@
+/* Copyright (c) 2013 Julien Pommier ( pommier@modartt.com )
+
+ Based on original fortran 77 code from FFTPACKv4 from NETLIB
+ (http://www.netlib.org/fftpack), authored by Dr Paul Swarztrauber
+ of NCAR, in 1985.
+
+ As confirmed by the NCAR fftpack software curators, the following
+ FFTPACKv5 license applies to FFTPACKv4 sources. My changes are
+ released under the same terms.
+
+ FFTPACK license:
+
+ http://www.cisl.ucar.edu/css/software/fftpack5/ftpk.html
+
+ Copyright (c) 2004 the University Corporation for Atmospheric
+ Research ("UCAR"). All rights reserved. Developed by NCAR's
+ Computational and Information Systems Laboratory, UCAR,
+ www.cisl.ucar.edu.
+
+ Redistribution and use of the Software in source and binary forms,
+ with or without modification, is permitted provided that the
+ following conditions are met:
+
+ - Neither the names of NCAR's Computational and Information Systems
+ Laboratory, the University Corporation for Atmospheric Research,
+ nor the names of its sponsors or contributors may be used to
+ endorse or promote products derived from this Software without
+ specific prior written permission.
+
+ - Redistributions of source code must retain the above copyright
+ notices, this list of conditions, and the disclaimer below.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions, and the disclaimer below in the
+ documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+ SOFTWARE.
+
+
+ PFFFT : a Pretty Fast FFT.
+
+ This file is largerly based on the original FFTPACK implementation, modified in
+ order to take advantage of SIMD instructions of modern CPUs.
+*/
+
+/*
+ ChangeLog:
+ - 2011/10/02, version 1: This is the very first release of this file.
+*/
+
+#include "pffft.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#include <assert.h>
+
+/* detect compiler flavour */
+#if defined(_MSC_VER)
+# define COMPILER_MSVC
+#elif defined(__GNUC__)
+# define COMPILER_GCC
+#endif
+
+#if defined(COMPILER_GCC)
+# define ALWAYS_INLINE(return_type) inline return_type __attribute__ ((always_inline))
+# define NEVER_INLINE(return_type) return_type __attribute__ ((noinline))
+# define RESTRICT __restrict
+# define VLA_ARRAY_ON_STACK(type__, varname__, size__) type__ varname__[size__];
+# define VLA_ARRAY_ON_STACK_FREE(varname__)
+#elif defined(COMPILER_MSVC)
+#include <malloc.h>
+# define ALWAYS_INLINE(return_type) __forceinline return_type
+# define NEVER_INLINE(return_type) __declspec(noinline) return_type
+# define RESTRICT __restrict
+# define VLA_ARRAY_ON_STACK(type__, varname__, size__) type__ *varname__ = (type__*)_malloca(size__ * sizeof(type__))
+# define VLA_ARRAY_ON_STACK_FREE(varname__) _freea(varname__)
+#endif
+
+
+/*
+ vector support macros: the rest of the code is independant of
+ SSE/Altivec/NEON -- adding support for other platforms with 4-element
+ vectors should be limited to these macros
+*/
+
+
+// define PFFFT_SIMD_DISABLE if you want to use scalar code instead of simd code
+//#define PFFFT_SIMD_DISABLE
+
+/*
+ Altivec support macros
+*/
+#if !defined(PFFFT_SIMD_DISABLE) && (defined(__ppc__) || defined(__ppc64__))
+typedef vector float v4sf;
+# define SIMD_SZ 4
+# define VZERO() ((vector float) vec_splat_u8(0))
+# define VMUL(a,b) vec_madd(a,b, VZERO())
+# define VADD(a,b) vec_add(a,b)
+# define VMADD(a,b,c) vec_madd(a,b,c)
+# define VSUB(a,b) vec_sub(a,b)
+inline v4sf ld_ps1(const float *p) { v4sf v=vec_lde(0,p); return vec_splat(vec_perm(v, v, vec_lvsl(0, p)), 0); }
+# define LD_PS1(p) ld_ps1(&p)
+# define INTERLEAVE2(in1, in2, out1, out2) { v4sf tmp__ = vec_mergeh(in1, in2); out2 = vec_mergel(in1, in2); out1 = tmp__; }
+# define UNINTERLEAVE2(in1, in2, out1, out2) { \
+ vector unsigned char vperm1 = (vector unsigned char)(0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27); \
+ vector unsigned char vperm2 = (vector unsigned char)(4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31); \
+ v4sf tmp__ = vec_perm(in1, in2, vperm1); out2 = vec_perm(in1, in2, vperm2); out1 = tmp__; \
+ }
+# define VTRANSPOSE4(x0,x1,x2,x3) { \
+ v4sf y0 = vec_mergeh(x0, x2); \
+ v4sf y1 = vec_mergel(x0, x2); \
+ v4sf y2 = vec_mergeh(x1, x3); \
+ v4sf y3 = vec_mergel(x1, x3); \
+ x0 = vec_mergeh(y0, y2); \
+ x1 = vec_mergel(y0, y2); \
+ x2 = vec_mergeh(y1, y3); \
+ x3 = vec_mergel(y1, y3); \
+ }
+# define VSWAPHL(a,b) vec_perm(a,b, (vector unsigned char)(16,17,18,19,20,21,22,23,8,9,10,11,12,13,14,15))
+# define VALIGNED(ptr) ((((uintptr_t)(ptr)) & 0xF) == 0)
+
+/*
+ SSE1 support macros
+*/
+#elif !defined(PFFFT_SIMD_DISABLE) && (defined(__x86_64__) || defined(_M_X64) || defined(i386) || defined(__i386__) || defined(_M_IX86))
+
+#include <xmmintrin.h>
+typedef __m128 v4sf;
+# define SIMD_SZ 4 // 4 floats by simd vector -- this is pretty much hardcoded in the preprocess/finalize functions anyway so you will have to work if you want to enable AVX with its 256-bit vectors.
+# define VZERO() _mm_setzero_ps()
+# define VMUL(a,b) _mm_mul_ps(a,b)
+# define VADD(a,b) _mm_add_ps(a,b)
+# define VMADD(a,b,c) _mm_add_ps(_mm_mul_ps(a,b), c)
+# define VSUB(a,b) _mm_sub_ps(a,b)
+# define LD_PS1(p) _mm_set1_ps(p)
+# define INTERLEAVE2(in1, in2, out1, out2) { v4sf tmp__ = _mm_unpacklo_ps(in1, in2); out2 = _mm_unpackhi_ps(in1, in2); out1 = tmp__; }
+# define UNINTERLEAVE2(in1, in2, out1, out2) { v4sf tmp__ = _mm_shuffle_ps(in1, in2, _MM_SHUFFLE(2,0,2,0)); out2 = _mm_shuffle_ps(in1, in2, _MM_SHUFFLE(3,1,3,1)); out1 = tmp__; }
+# define VTRANSPOSE4(x0,x1,x2,x3) _MM_TRANSPOSE4_PS(x0,x1,x2,x3)
+# define VSWAPHL(a,b) _mm_shuffle_ps(b, a, _MM_SHUFFLE(3,2,1,0))
+# define VALIGNED(ptr) ((((uintptr_t)(ptr)) & 0xF) == 0)
+
+/*
+ ARM NEON support macros
+*/
+#elif !defined(PFFFT_SIMD_DISABLE) && (defined(__arm__) || defined(__ARMEL__) || defined(__aarch64__) || defined(_M_ARM64))
+# include <arm_neon.h>
+typedef float32x4_t v4sf;
+# define SIMD_SZ 4
+# define VZERO() vdupq_n_f32(0)
+# define VMUL(a,b) vmulq_f32(a,b)
+# define VADD(a,b) vaddq_f32(a,b)
+# define VMADD(a,b,c) vmlaq_f32(c,a,b)
+# define VSUB(a,b) vsubq_f32(a,b)
+# define LD_PS1(p) vld1q_dup_f32(&(p))
+# define INTERLEAVE2(in1, in2, out1, out2) { float32x4x2_t tmp__ = vzipq_f32(in1,in2); out1=tmp__.val[0]; out2=tmp__.val[1]; }
+# define UNINTERLEAVE2(in1, in2, out1, out2) { float32x4x2_t tmp__ = vuzpq_f32(in1,in2); out1=tmp__.val[0]; out2=tmp__.val[1]; }
+# define VTRANSPOSE4(x0,x1,x2,x3) { \
+ float32x4x2_t t0_ = vzipq_f32(x0, x2); \
+ float32x4x2_t t1_ = vzipq_f32(x1, x3); \
+ float32x4x2_t u0_ = vzipq_f32(t0_.val[0], t1_.val[0]); \
+ float32x4x2_t u1_ = vzipq_f32(t0_.val[1], t1_.val[1]); \
+ x0 = u0_.val[0]; x1 = u0_.val[1]; x2 = u1_.val[0]; x3 = u1_.val[1]; \
+ }
+// marginally faster version
+//# define VTRANSPOSE4(x0,x1,x2,x3) { asm("vtrn.32 %q0, %q1;\n vtrn.32 %q2,%q3\n vswp %f0,%e2\n vswp %f1,%e3" : "+w"(x0), "+w"(x1), "+w"(x2), "+w"(x3)::); }
+# define VSWAPHL(a,b) vcombine_f32(vget_low_f32(b), vget_high_f32(a))
+# define VALIGNED(ptr) ((((uintptr_t)(ptr)) & 0x3) == 0)
+#else
+# if !defined(PFFFT_SIMD_DISABLE)
+# warning "building with simd disabled !\n";
+# define PFFFT_SIMD_DISABLE // fallback to scalar code
+# endif
+#endif
+
+// fallback mode for situations where SSE/Altivec are not available, use scalar mode instead
+#ifdef PFFFT_SIMD_DISABLE
+typedef float v4sf;
+# define SIMD_SZ 1
+# define VZERO() 0.f
+# define VMUL(a,b) ((a)*(b))
+# define VADD(a,b) ((a)+(b))
+# define VMADD(a,b,c) ((a)*(b)+(c))
+# define VSUB(a,b) ((a)-(b))
+# define LD_PS1(p) (p)
+# define VALIGNED(ptr) ((((uintptr_t)(ptr)) & 0x3) == 0)
+#endif
+
+// shortcuts for complex multiplcations
+#define VCPLXMUL(ar,ai,br,bi) { v4sf tmp; tmp=VMUL(ar,bi); ar=VMUL(ar,br); ar=VSUB(ar,VMUL(ai,bi)); ai=VMUL(ai,br); ai=VADD(ai,tmp); }
+#define VCPLXMULCONJ(ar,ai,br,bi) { v4sf tmp; tmp=VMUL(ar,bi); ar=VMUL(ar,br); ar=VADD(ar,VMUL(ai,bi)); ai=VMUL(ai,br); ai=VSUB(ai,tmp); }
+#ifndef SVMUL
+// multiply a scalar with a vector
+#define SVMUL(f,v) VMUL(LD_PS1(f),v)
+#endif
+
+#if !defined(PFFFT_SIMD_DISABLE)
+typedef union v4sf_union {
+ v4sf v;
+ float f[4];
+} v4sf_union;
+
+#include <string.h>
+
+#define assertv4(v,f0,f1,f2,f3) assert(v.f[0] == (f0) && v.f[1] == (f1) && v.f[2] == (f2) && v.f[3] == (f3))
+
+/* detect bugs with the vector support macros */
+void validate_pffft_simd() {
+ float f[16] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
+ v4sf_union a0, a1, a2, a3, t, u;
+ memcpy(a0.f, f, 4*sizeof(float));
+ memcpy(a1.f, f+4, 4*sizeof(float));
+ memcpy(a2.f, f+8, 4*sizeof(float));
+ memcpy(a3.f, f+12, 4*sizeof(float));
+
+ t = a0; u = a1; t.v = VZERO();
+ assertv4(t, 0, 0, 0, 0);
+ t.v = VADD(a1.v, a2.v);
+ assertv4(t, 12, 14, 16, 18);
+ t.v = VMUL(a1.v, a2.v);
+ assertv4(t, 32, 45, 60, 77);
+ t.v = VMADD(a1.v, a2.v,a0.v);
+ assertv4(t, 32, 46, 62, 80);
+
+ INTERLEAVE2(a1.v,a2.v,t.v,u.v);
+ assertv4(t, 4, 8, 5, 9); assertv4(u, 6, 10, 7, 11);
+ UNINTERLEAVE2(a1.v,a2.v,t.v,u.v);
+ assertv4(t, 4, 6, 8, 10); assertv4(u, 5, 7, 9, 11);
+
+ t.v=LD_PS1(f[15]);
+ assertv4(t, 15, 15, 15, 15);
+ t.v = VSWAPHL(a1.v, a2.v);
+ assertv4(t, 8, 9, 6, 7);
+ VTRANSPOSE4(a0.v, a1.v, a2.v, a3.v);
+ assertv4(a0, 0, 4, 8, 12); assertv4(a1, 1, 5, 9, 13); assertv4(a2, 2, 6, 10, 14); assertv4(a3, 3, 7, 11, 15);
+}
+#endif //!PFFFT_SIMD_DISABLE
+
+/* SSE and co like 16-bytes aligned pointers */
+#define MALLOC_V4SF_ALIGNMENT 64 // with a 64-byte alignment, we are even aligned on L2 cache lines...
+void *pffft_aligned_malloc(size_t nb_bytes) {
+ void *p, *p0 = malloc(nb_bytes + MALLOC_V4SF_ALIGNMENT);
+ if (!p0) return (void *) 0;
+ p = (void *) (((size_t) p0 + MALLOC_V4SF_ALIGNMENT) & (~((size_t) (MALLOC_V4SF_ALIGNMENT-1))));
+ *((void **) p - 1) = p0;
+ return p;
+}
+
+void pffft_aligned_free(void *p) {
+ if (p) free(*((void **) p - 1));
+}
+
+int pffft_simd_size() { return SIMD_SZ; }
+
+/*
+ passf2 and passb2 has been merged here, fsign = -1 for passf2, +1 for passb2
+*/
+static NEVER_INLINE(void) passf2_ps(int ido, int l1, const v4sf *cc, v4sf *ch, const float *wa1, float fsign) {
+ int k, i;
+ int l1ido = l1*ido;
+ if (ido <= 2) {
+ for (k=0; k < l1ido; k += ido, ch += ido, cc+= 2*ido) {
+ ch[0] = VADD(cc[0], cc[ido+0]);
+ ch[l1ido] = VSUB(cc[0], cc[ido+0]);
+ ch[1] = VADD(cc[1], cc[ido+1]);
+ ch[l1ido + 1] = VSUB(cc[1], cc[ido+1]);
+ }
+ } else {
+ for (k=0; k < l1ido; k += ido, ch += ido, cc += 2*ido) {
+ for (i=0; i<ido-1; i+=2) {
+ v4sf tr2 = VSUB(cc[i+0], cc[i+ido+0]);
+ v4sf ti2 = VSUB(cc[i+1], cc[i+ido+1]);
+ v4sf wr = LD_PS1(wa1[i]), wi = VMUL(LD_PS1(fsign), LD_PS1(wa1[i+1]));
+ ch[i] = VADD(cc[i+0], cc[i+ido+0]);
+ ch[i+1] = VADD(cc[i+1], cc[i+ido+1]);
+ VCPLXMUL(tr2, ti2, wr, wi);
+ ch[i+l1ido] = tr2;
+ ch[i+l1ido+1] = ti2;
+ }
+ }
+ }
+}
+
+/*
+ passf3 and passb3 has been merged here, fsign = -1 for passf3, +1 for passb3
+*/
+static NEVER_INLINE(void) passf3_ps(int ido, int l1, const v4sf *cc, v4sf *ch,
+ const float *wa1, const float *wa2, float fsign) {
+ static const float taur = -0.5f;
+ float taui = 0.866025403784439f*fsign;
+ int i, k;
+ v4sf tr2, ti2, cr2, ci2, cr3, ci3, dr2, di2, dr3, di3;
+ int l1ido = l1*ido;
+ float wr1, wi1, wr2, wi2;
+ assert(ido > 2);
+ for (k=0; k< l1ido; k += ido, cc+= 3*ido, ch +=ido) {
+ for (i=0; i<ido-1; i+=2) {
+ tr2 = VADD(cc[i+ido], cc[i+2*ido]);
+ cr2 = VADD(cc[i], SVMUL(taur,tr2));
+ ch[i] = VADD(cc[i], tr2);
+ ti2 = VADD(cc[i+ido+1], cc[i+2*ido+1]);
+ ci2 = VADD(cc[i +1], SVMUL(taur,ti2));
+ ch[i+1] = VADD(cc[i+1], ti2);
+ cr3 = SVMUL(taui, VSUB(cc[i+ido], cc[i+2*ido]));
+ ci3 = SVMUL(taui, VSUB(cc[i+ido+1], cc[i+2*ido+1]));
+ dr2 = VSUB(cr2, ci3);
+ dr3 = VADD(cr2, ci3);
+ di2 = VADD(ci2, cr3);
+ di3 = VSUB(ci2, cr3);
+ wr1=wa1[i], wi1=fsign*wa1[i+1], wr2=wa2[i], wi2=fsign*wa2[i+1];
+ VCPLXMUL(dr2, di2, LD_PS1(wr1), LD_PS1(wi1));
+ ch[i+l1ido] = dr2;
+ ch[i+l1ido + 1] = di2;
+ VCPLXMUL(dr3, di3, LD_PS1(wr2), LD_PS1(wi2));
+ ch[i+2*l1ido] = dr3;
+ ch[i+2*l1ido+1] = di3;
+ }
+ }
+} /* passf3 */
+
+static NEVER_INLINE(void) passf4_ps(int ido, int l1, const v4sf *cc, v4sf *ch,
+ const float *wa1, const float *wa2, const float *wa3, float fsign) {
+ /* isign == -1 for forward transform and +1 for backward transform */
+
+ int i, k;
+ v4sf ci2, ci3, ci4, cr2, cr3, cr4, ti1, ti2, ti3, ti4, tr1, tr2, tr3, tr4;
+ int l1ido = l1*ido;
+ if (ido == 2) {
+ for (k=0; k < l1ido; k += ido, ch += ido, cc += 4*ido) {
+ tr1 = VSUB(cc[0], cc[2*ido + 0]);
+ tr2 = VADD(cc[0], cc[2*ido + 0]);
+ ti1 = VSUB(cc[1], cc[2*ido + 1]);
+ ti2 = VADD(cc[1], cc[2*ido + 1]);
+ ti4 = VMUL(VSUB(cc[1*ido + 0], cc[3*ido + 0]), LD_PS1(fsign));
+ tr4 = VMUL(VSUB(cc[3*ido + 1], cc[1*ido + 1]), LD_PS1(fsign));
+ tr3 = VADD(cc[ido + 0], cc[3*ido + 0]);
+ ti3 = VADD(cc[ido + 1], cc[3*ido + 1]);
+
+ ch[0*l1ido + 0] = VADD(tr2, tr3);
+ ch[0*l1ido + 1] = VADD(ti2, ti3);
+ ch[1*l1ido + 0] = VADD(tr1, tr4);
+ ch[1*l1ido + 1] = VADD(ti1, ti4);
+ ch[2*l1ido + 0] = VSUB(tr2, tr3);
+ ch[2*l1ido + 1] = VSUB(ti2, ti3);
+ ch[3*l1ido + 0] = VSUB(tr1, tr4);
+ ch[3*l1ido + 1] = VSUB(ti1, ti4);
+ }
+ } else {
+ for (k=0; k < l1ido; k += ido, ch+=ido, cc += 4*ido) {
+ for (i=0; i<ido-1; i+=2) {
+ float wr1, wi1, wr2, wi2, wr3, wi3;
+ tr1 = VSUB(cc[i + 0], cc[i + 2*ido + 0]);
+ tr2 = VADD(cc[i + 0], cc[i + 2*ido + 0]);
+ ti1 = VSUB(cc[i + 1], cc[i + 2*ido + 1]);
+ ti2 = VADD(cc[i + 1], cc[i + 2*ido + 1]);
+ tr4 = VMUL(VSUB(cc[i + 3*ido + 1], cc[i + 1*ido + 1]), LD_PS1(fsign));
+ ti4 = VMUL(VSUB(cc[i + 1*ido + 0], cc[i + 3*ido + 0]), LD_PS1(fsign));
+ tr3 = VADD(cc[i + ido + 0], cc[i + 3*ido + 0]);
+ ti3 = VADD(cc[i + ido + 1], cc[i + 3*ido + 1]);
+
+ ch[i] = VADD(tr2, tr3);
+ cr3 = VSUB(tr2, tr3);
+ ch[i + 1] = VADD(ti2, ti3);
+ ci3 = VSUB(ti2, ti3);
+
+ cr2 = VADD(tr1, tr4);
+ cr4 = VSUB(tr1, tr4);
+ ci2 = VADD(ti1, ti4);
+ ci4 = VSUB(ti1, ti4);
+ wr1=wa1[i], wi1=fsign*wa1[i+1];
+ VCPLXMUL(cr2, ci2, LD_PS1(wr1), LD_PS1(wi1));
+ wr2=wa2[i], wi2=fsign*wa2[i+1];
+ ch[i + l1ido] = cr2;
+ ch[i + l1ido + 1] = ci2;
+
+ VCPLXMUL(cr3, ci3, LD_PS1(wr2), LD_PS1(wi2));
+ wr3=wa3[i], wi3=fsign*wa3[i+1];
+ ch[i + 2*l1ido] = cr3;
+ ch[i + 2*l1ido + 1] = ci3;
+
+ VCPLXMUL(cr4, ci4, LD_PS1(wr3), LD_PS1(wi3));
+ ch[i + 3*l1ido] = cr4;
+ ch[i + 3*l1ido + 1] = ci4;
+ }
+ }
+ }
+} /* passf4 */
+
+/*
+ passf5 and passb5 has been merged here, fsign = -1 for passf5, +1 for passb5
+*/
+static NEVER_INLINE(void) passf5_ps(int ido, int l1, const v4sf *cc, v4sf *ch,
+ const float *wa1, const float *wa2,
+ const float *wa3, const float *wa4, float fsign) {
+ static const float tr11 = .309016994374947f;
+ const float ti11 = .951056516295154f*fsign;
+ static const float tr12 = -.809016994374947f;
+ const float ti12 = .587785252292473f*fsign;
+
+ /* Local variables */
+ int i, k;
+ v4sf ci2, ci3, ci4, ci5, di3, di4, di5, di2, cr2, cr3, cr5, cr4, ti2, ti3,
+ ti4, ti5, dr3, dr4, dr5, dr2, tr2, tr3, tr4, tr5;
+
+ float wr1, wi1, wr2, wi2, wr3, wi3, wr4, wi4;
+
+#define cc_ref(a_1,a_2) cc[(a_2-1)*ido + a_1 + 1]
+#define ch_ref(a_1,a_3) ch[(a_3-1)*l1*ido + a_1 + 1]
+
+ assert(ido > 2);
+ for (k = 0; k < l1; ++k, cc += 5*ido, ch += ido) {
+ for (i = 0; i < ido-1; i += 2) {
+ ti5 = VSUB(cc_ref(i , 2), cc_ref(i , 5));
+ ti2 = VADD(cc_ref(i , 2), cc_ref(i , 5));
+ ti4 = VSUB(cc_ref(i , 3), cc_ref(i , 4));
+ ti3 = VADD(cc_ref(i , 3), cc_ref(i , 4));
+ tr5 = VSUB(cc_ref(i-1, 2), cc_ref(i-1, 5));
+ tr2 = VADD(cc_ref(i-1, 2), cc_ref(i-1, 5));
+ tr4 = VSUB(cc_ref(i-1, 3), cc_ref(i-1, 4));
+ tr3 = VADD(cc_ref(i-1, 3), cc_ref(i-1, 4));
+ ch_ref(i-1, 1) = VADD(cc_ref(i-1, 1), VADD(tr2, tr3));
+ ch_ref(i , 1) = VADD(cc_ref(i , 1), VADD(ti2, ti3));
+ cr2 = VADD(cc_ref(i-1, 1), VADD(SVMUL(tr11, tr2),SVMUL(tr12, tr3)));
+ ci2 = VADD(cc_ref(i , 1), VADD(SVMUL(tr11, ti2),SVMUL(tr12, ti3)));
+ cr3 = VADD(cc_ref(i-1, 1), VADD(SVMUL(tr12, tr2),SVMUL(tr11, tr3)));
+ ci3 = VADD(cc_ref(i , 1), VADD(SVMUL(tr12, ti2),SVMUL(tr11, ti3)));
+ cr5 = VADD(SVMUL(ti11, tr5), SVMUL(ti12, tr4));
+ ci5 = VADD(SVMUL(ti11, ti5), SVMUL(ti12, ti4));
+ cr4 = VSUB(SVMUL(ti12, tr5), SVMUL(ti11, tr4));
+ ci4 = VSUB(SVMUL(ti12, ti5), SVMUL(ti11, ti4));
+ dr3 = VSUB(cr3, ci4);
+ dr4 = VADD(cr3, ci4);
+ di3 = VADD(ci3, cr4);
+ di4 = VSUB(ci3, cr4);
+ dr5 = VADD(cr2, ci5);
+ dr2 = VSUB(cr2, ci5);
+ di5 = VSUB(ci2, cr5);
+ di2 = VADD(ci2, cr5);
+ wr1=wa1[i], wi1=fsign*wa1[i+1], wr2=wa2[i], wi2=fsign*wa2[i+1];
+ wr3=wa3[i], wi3=fsign*wa3[i+1], wr4=wa4[i], wi4=fsign*wa4[i+1];
+ VCPLXMUL(dr2, di2, LD_PS1(wr1), LD_PS1(wi1));
+ ch_ref(i - 1, 2) = dr2;
+ ch_ref(i, 2) = di2;
+ VCPLXMUL(dr3, di3, LD_PS1(wr2), LD_PS1(wi2));
+ ch_ref(i - 1, 3) = dr3;
+ ch_ref(i, 3) = di3;
+ VCPLXMUL(dr4, di4, LD_PS1(wr3), LD_PS1(wi3));
+ ch_ref(i - 1, 4) = dr4;
+ ch_ref(i, 4) = di4;
+ VCPLXMUL(dr5, di5, LD_PS1(wr4), LD_PS1(wi4));
+ ch_ref(i - 1, 5) = dr5;
+ ch_ref(i, 5) = di5;
+ }
+ }
+#undef ch_ref
+#undef cc_ref
+}
+
+static NEVER_INLINE(void) radf2_ps(int ido, int l1, const v4sf * RESTRICT cc, v4sf * RESTRICT ch, const float *wa1) {
+ static const float minus_one = -1.f;
+ int i, k, l1ido = l1*ido;
+ for (k=0; k < l1ido; k += ido) {
+ v4sf a = cc[k], b = cc[k + l1ido];
+ ch[2*k] = VADD(a, b);
+ ch[2*(k+ido)-1] = VSUB(a, b);
+ }
+ if (ido < 2) return;
+ if (ido != 2) {
+ for (k=0; k < l1ido; k += ido) {
+ for (i=2; i<ido; i+=2) {
+ v4sf tr2 = cc[i - 1 + k + l1ido], ti2 = cc[i + k + l1ido];
+ v4sf br = cc[i - 1 + k], bi = cc[i + k];
+ VCPLXMULCONJ(tr2, ti2, LD_PS1(wa1[i - 2]), LD_PS1(wa1[i - 1]));
+ ch[i + 2*k] = VADD(bi, ti2);
+ ch[2*(k+ido) - i] = VSUB(ti2, bi);
+ ch[i - 1 + 2*k] = VADD(br, tr2);
+ ch[2*(k+ido) - i -1] = VSUB(br, tr2);
+ }
+ }
+ if (ido % 2 == 1) return;
+ }
+ for (k=0; k < l1ido; k += ido) {
+ ch[2*k + ido] = SVMUL(minus_one, cc[ido-1 + k + l1ido]);
+ ch[2*k + ido-1] = cc[k + ido-1];
+ }
+} /* radf2 */
+
+
+static NEVER_INLINE(void) radb2_ps(int ido, int l1, const v4sf *cc, v4sf *ch, const float *wa1) {
+ static const float minus_two=-2;
+ int i, k, l1ido = l1*ido;
+ v4sf a,b,c,d, tr2, ti2;
+ for (k=0; k < l1ido; k += ido) {
+ a = cc[2*k]; b = cc[2*(k+ido) - 1];
+ ch[k] = VADD(a, b);
+ ch[k + l1ido] =VSUB(a, b);
+ }
+ if (ido < 2) return;
+ if (ido != 2) {
+ for (k = 0; k < l1ido; k += ido) {
+ for (i = 2; i < ido; i += 2) {
+ a = cc[i-1 + 2*k]; b = cc[2*(k + ido) - i - 1];
+ c = cc[i+0 + 2*k]; d = cc[2*(k + ido) - i + 0];
+ ch[i-1 + k] = VADD(a, b);
+ tr2 = VSUB(a, b);
+ ch[i+0 + k] = VSUB(c, d);
+ ti2 = VADD(c, d);
+ VCPLXMUL(tr2, ti2, LD_PS1(wa1[i - 2]), LD_PS1(wa1[i - 1]));
+ ch[i-1 + k + l1ido] = tr2;
+ ch[i+0 + k + l1ido] = ti2;
+ }
+ }
+ if (ido % 2 == 1) return;
+ }
+ for (k = 0; k < l1ido; k += ido) {
+ a = cc[2*k + ido-1]; b = cc[2*k + ido];
+ ch[k + ido-1] = VADD(a,a);
+ ch[k + ido-1 + l1ido] = SVMUL(minus_two, b);
+ }
+} /* radb2 */
+
+static void radf3_ps(int ido, int l1, const v4sf * RESTRICT cc, v4sf * RESTRICT ch,
+ const float *wa1, const float *wa2) {
+ static const float taur = -0.5f;
+ static const float taui = 0.866025403784439f;
+ int i, k, ic;
+ v4sf ci2, di2, di3, cr2, dr2, dr3, ti2, ti3, tr2, tr3, wr1, wi1, wr2, wi2;
+ for (k=0; k<l1; k++) {
+ cr2 = VADD(cc[(k + l1)*ido], cc[(k + 2*l1)*ido]);
+ ch[3*k*ido] = VADD(cc[k*ido], cr2);
+ ch[(3*k+2)*ido] = SVMUL(taui, VSUB(cc[(k + l1*2)*ido], cc[(k + l1)*ido]));
+ ch[ido-1 + (3*k + 1)*ido] = VADD(cc[k*ido], SVMUL(taur, cr2));
+ }
+ if (ido == 1) return;
+ for (k=0; k<l1; k++) {
+ for (i=2; i<ido; i+=2) {
+ ic = ido - i;
+ wr1 = LD_PS1(wa1[i - 2]); wi1 = LD_PS1(wa1[i - 1]);
+ dr2 = cc[i - 1 + (k + l1)*ido]; di2 = cc[i + (k + l1)*ido];
+ VCPLXMULCONJ(dr2, di2, wr1, wi1);
+
+ wr2 = LD_PS1(wa2[i - 2]); wi2 = LD_PS1(wa2[i - 1]);
+ dr3 = cc[i - 1 + (k + l1*2)*ido]; di3 = cc[i + (k + l1*2)*ido];
+ VCPLXMULCONJ(dr3, di3, wr2, wi2);
+
+ cr2 = VADD(dr2, dr3);
+ ci2 = VADD(di2, di3);
+ ch[i - 1 + 3*k*ido] = VADD(cc[i - 1 + k*ido], cr2);
+ ch[i + 3*k*ido] = VADD(cc[i + k*ido], ci2);
+ tr2 = VADD(cc[i - 1 + k*ido], SVMUL(taur, cr2));
+ ti2 = VADD(cc[i + k*ido], SVMUL(taur, ci2));
+ tr3 = SVMUL(taui, VSUB(di2, di3));
+ ti3 = SVMUL(taui, VSUB(dr3, dr2));
+ ch[i - 1 + (3*k + 2)*ido] = VADD(tr2, tr3);
+ ch[ic - 1 + (3*k + 1)*ido] = VSUB(tr2, tr3);
+ ch[i + (3*k + 2)*ido] = VADD(ti2, ti3);
+ ch[ic + (3*k + 1)*ido] = VSUB(ti3, ti2);
+ }
+ }
+} /* radf3 */
+
+
+static void radb3_ps(int ido, int l1, const v4sf *RESTRICT cc, v4sf *RESTRICT ch,
+ const float *wa1, const float *wa2)
+{
+ static const float taur = -0.5f;
+ static const float taui = 0.866025403784439f;
+ static const float taui_2 = 0.866025403784439f*2;
+ int i, k, ic;
+ v4sf ci2, ci3, di2, di3, cr2, cr3, dr2, dr3, ti2, tr2;
+ for (k=0; k<l1; k++) {
+ tr2 = cc[ido-1 + (3*k + 1)*ido]; tr2 = VADD(tr2,tr2);
+ cr2 = VMADD(LD_PS1(taur), tr2, cc[3*k*ido]);
+ ch[k*ido] = VADD(cc[3*k*ido], tr2);
+ ci3 = SVMUL(taui_2, cc[(3*k + 2)*ido]);
+ ch[(k + l1)*ido] = VSUB(cr2, ci3);
+ ch[(k + 2*l1)*ido] = VADD(cr2, ci3);
+ }
+ if (ido == 1) return;
+ for (k=0; k<l1; k++) {
+ for (i=2; i<ido; i+=2) {
+ ic = ido - i;
+ tr2 = VADD(cc[i - 1 + (3*k + 2)*ido], cc[ic - 1 + (3*k + 1)*ido]);
+ cr2 = VMADD(LD_PS1(taur), tr2, cc[i - 1 + 3*k*ido]);
+ ch[i - 1 + k*ido] = VADD(cc[i - 1 + 3*k*ido], tr2);
+ ti2 = VSUB(cc[i + (3*k + 2)*ido], cc[ic + (3*k + 1)*ido]);
+ ci2 = VMADD(LD_PS1(taur), ti2, cc[i + 3*k*ido]);
+ ch[i + k*ido] = VADD(cc[i + 3*k*ido], ti2);
+ cr3 = SVMUL(taui, VSUB(cc[i - 1 + (3*k + 2)*ido], cc[ic - 1 + (3*k + 1)*ido]));
+ ci3 = SVMUL(taui, VADD(cc[i + (3*k + 2)*ido], cc[ic + (3*k + 1)*ido]));
+ dr2 = VSUB(cr2, ci3);
+ dr3 = VADD(cr2, ci3);
+ di2 = VADD(ci2, cr3);
+ di3 = VSUB(ci2, cr3);
+ VCPLXMUL(dr2, di2, LD_PS1(wa1[i-2]), LD_PS1(wa1[i-1]));
+ ch[i - 1 + (k + l1)*ido] = dr2;
+ ch[i + (k + l1)*ido] = di2;
+ VCPLXMUL(dr3, di3, LD_PS1(wa2[i-2]), LD_PS1(wa2[i-1]));
+ ch[i - 1 + (k + 2*l1)*ido] = dr3;
+ ch[i + (k + 2*l1)*ido] = di3;
+ }
+ }
+} /* radb3 */
+
+static NEVER_INLINE(void) radf4_ps(int ido, int l1, const v4sf *RESTRICT cc, v4sf * RESTRICT ch,
+ const float * RESTRICT wa1, const float * RESTRICT wa2, const float * RESTRICT wa3)
+{
+ static const float minus_hsqt2 = (float)-0.7071067811865475;
+ int i, k, l1ido = l1*ido;
+ {
+ const v4sf *RESTRICT cc_ = cc, * RESTRICT cc_end = cc + l1ido;
+ v4sf * RESTRICT ch_ = ch;
+ while (cc < cc_end) {
+ // this loop represents between 25% and 40% of total radf4_ps cost !
+ v4sf a0 = cc[0], a1 = cc[l1ido];
+ v4sf a2 = cc[2*l1ido], a3 = cc[3*l1ido];
+ v4sf tr1 = VADD(a1, a3);
+ v4sf tr2 = VADD(a0, a2);
+ ch[2*ido-1] = VSUB(a0, a2);
+ ch[2*ido ] = VSUB(a3, a1);
+ ch[0 ] = VADD(tr1, tr2);
+ ch[4*ido-1] = VSUB(tr2, tr1);
+ cc += ido; ch += 4*ido;
+ }
+ cc = cc_; ch = ch_;
+ }
+ if (ido < 2) return;
+ if (ido != 2) {
+ for (k = 0; k < l1ido; k += ido) {
+ const v4sf * RESTRICT pc = (v4sf*)(cc + 1 + k);
+ for (i=2; i<ido; i += 2, pc += 2) {
+ int ic = ido - i;
+ v4sf wr, wi, cr2, ci2, cr3, ci3, cr4, ci4;
+ v4sf tr1, ti1, tr2, ti2, tr3, ti3, tr4, ti4;
+
+ cr2 = pc[1*l1ido+0];
+ ci2 = pc[1*l1ido+1];
+ wr=LD_PS1(wa1[i - 2]);
+ wi=LD_PS1(wa1[i - 1]);
+ VCPLXMULCONJ(cr2,ci2,wr,wi);
+
+ cr3 = pc[2*l1ido+0];
+ ci3 = pc[2*l1ido+1];
+ wr = LD_PS1(wa2[i-2]);
+ wi = LD_PS1(wa2[i-1]);
+ VCPLXMULCONJ(cr3, ci3, wr, wi);
+
+ cr4 = pc[3*l1ido];
+ ci4 = pc[3*l1ido+1];
+ wr = LD_PS1(wa3[i-2]);
+ wi = LD_PS1(wa3[i-1]);
+ VCPLXMULCONJ(cr4, ci4, wr, wi);
+
+ /* at this point, on SSE, five of "cr2 cr3 cr4 ci2 ci3 ci4" should be loaded in registers */
+
+ tr1 = VADD(cr2,cr4);
+ tr4 = VSUB(cr4,cr2);
+ tr2 = VADD(pc[0],cr3);
+ tr3 = VSUB(pc[0],cr3);
+ ch[i - 1 + 4*k] = VADD(tr1,tr2);
+ ch[ic - 1 + 4*k + 3*ido] = VSUB(tr2,tr1); // at this point tr1 and tr2 can be disposed
+ ti1 = VADD(ci2,ci4);
+ ti4 = VSUB(ci2,ci4);
+ ch[i - 1 + 4*k + 2*ido] = VADD(ti4,tr3);
+ ch[ic - 1 + 4*k + 1*ido] = VSUB(tr3,ti4); // dispose tr3, ti4
+ ti2 = VADD(pc[1],ci3);
+ ti3 = VSUB(pc[1],ci3);
+ ch[i + 4*k] = VADD(ti1, ti2);
+ ch[ic + 4*k + 3*ido] = VSUB(ti1, ti2);
+ ch[i + 4*k + 2*ido] = VADD(tr4, ti3);
+ ch[ic + 4*k + 1*ido] = VSUB(tr4, ti3);
+ }
+ }
+ if (ido % 2 == 1) return;
+ }
+ for (k=0; k<l1ido; k += ido) {
+ v4sf a = cc[ido-1 + k + l1ido], b = cc[ido-1 + k + 3*l1ido];
+ v4sf c = cc[ido-1 + k], d = cc[ido-1 + k + 2*l1ido];
+ v4sf ti1 = SVMUL(minus_hsqt2, VADD(a, b));
+ v4sf tr1 = SVMUL(minus_hsqt2, VSUB(b, a));
+ ch[ido-1 + 4*k] = VADD(tr1, c);
+ ch[ido-1 + 4*k + 2*ido] = VSUB(c, tr1);
+ ch[4*k + 1*ido] = VSUB(ti1, d);
+ ch[4*k + 3*ido] = VADD(ti1, d);
+ }
+} /* radf4 */
+
+
+static NEVER_INLINE(void) radb4_ps(int ido, int l1, const v4sf * RESTRICT cc, v4sf * RESTRICT ch,
+ const float * RESTRICT wa1, const float * RESTRICT wa2, const float *RESTRICT wa3)
+{
+ static const float minus_sqrt2 = (float)-1.414213562373095;
+ static const float two = 2.f;
+ int i, k, l1ido = l1*ido;
+ v4sf ci2, ci3, ci4, cr2, cr3, cr4, ti1, ti2, ti3, ti4, tr1, tr2, tr3, tr4;
+ {
+ const v4sf *RESTRICT cc_ = cc, * RESTRICT ch_end = ch + l1ido;
+ v4sf *ch_ = ch;
+ while (ch < ch_end) {
+ v4sf a = cc[0], b = cc[4*ido-1];
+ v4sf c = cc[2*ido], d = cc[2*ido-1];
+ tr3 = SVMUL(two,d);
+ tr2 = VADD(a,b);
+ tr1 = VSUB(a,b);
+ tr4 = SVMUL(two,c);
+ ch[0*l1ido] = VADD(tr2, tr3);
+ ch[2*l1ido] = VSUB(tr2, tr3);
+ ch[1*l1ido] = VSUB(tr1, tr4);
+ ch[3*l1ido] = VADD(tr1, tr4);
+
+ cc += 4*ido; ch += ido;
+ }
+ cc = cc_; ch = ch_;
+ }
+ if (ido < 2) return;
+ if (ido != 2) {
+ for (k = 0; k < l1ido; k += ido) {
+ const v4sf * RESTRICT pc = (v4sf*)(cc - 1 + 4*k);
+ v4sf * RESTRICT ph = (v4sf*)(ch + k + 1);
+ for (i = 2; i < ido; i += 2) {
+
+ tr1 = VSUB(pc[i], pc[4*ido - i]);
+ tr2 = VADD(pc[i], pc[4*ido - i]);
+ ti4 = VSUB(pc[2*ido + i], pc[2*ido - i]);
+ tr3 = VADD(pc[2*ido + i], pc[2*ido - i]);
+ ph[0] = VADD(tr2, tr3);
+ cr3 = VSUB(tr2, tr3);
+
+ ti3 = VSUB(pc[2*ido + i + 1], pc[2*ido - i + 1]);
+ tr4 = VADD(pc[2*ido + i + 1], pc[2*ido - i + 1]);
+ cr2 = VSUB(tr1, tr4);
+ cr4 = VADD(tr1, tr4);
+
+ ti1 = VADD(pc[i + 1], pc[4*ido - i + 1]);
+ ti2 = VSUB(pc[i + 1], pc[4*ido - i + 1]);
+
+ ph[1] = VADD(ti2, ti3); ph += l1ido;
+ ci3 = VSUB(ti2, ti3);
+ ci2 = VADD(ti1, ti4);
+ ci4 = VSUB(ti1, ti4);
+ VCPLXMUL(cr2, ci2, LD_PS1(wa1[i-2]), LD_PS1(wa1[i-1]));
+ ph[0] = cr2;
+ ph[1] = ci2; ph += l1ido;
+ VCPLXMUL(cr3, ci3, LD_PS1(wa2[i-2]), LD_PS1(wa2[i-1]));
+ ph[0] = cr3;
+ ph[1] = ci3; ph += l1ido;
+ VCPLXMUL(cr4, ci4, LD_PS1(wa3[i-2]), LD_PS1(wa3[i-1]));
+ ph[0] = cr4;
+ ph[1] = ci4; ph = ph - 3*l1ido + 2;
+ }
+ }
+ if (ido % 2 == 1) return;
+ }
+ for (k=0; k < l1ido; k+=ido) {
+ int i0 = 4*k + ido;
+ v4sf c = cc[i0-1], d = cc[i0 + 2*ido-1];
+ v4sf a = cc[i0+0], b = cc[i0 + 2*ido+0];
+ tr1 = VSUB(c,d);
+ tr2 = VADD(c,d);
+ ti1 = VADD(b,a);
+ ti2 = VSUB(b,a);
+ ch[ido-1 + k + 0*l1ido] = VADD(tr2,tr2);
+ ch[ido-1 + k + 1*l1ido] = SVMUL(minus_sqrt2, VSUB(ti1, tr1));
+ ch[ido-1 + k + 2*l1ido] = VADD(ti2, ti2);
+ ch[ido-1 + k + 3*l1ido] = SVMUL(minus_sqrt2, VADD(ti1, tr1));
+ }
+} /* radb4 */
+
+static void radf5_ps(int ido, int l1, const v4sf * RESTRICT cc, v4sf * RESTRICT ch,
+ const float *wa1, const float *wa2, const float *wa3, const float *wa4)
+{
+ static const float tr11 = .309016994374947f;
+ static const float ti11 = .951056516295154f;
+ static const float tr12 = -.809016994374947f;
+ static const float ti12 = .587785252292473f;
+
+ /* System generated locals */
+ int cc_offset, ch_offset;
+
+ /* Local variables */
+ int i, k, ic;
+ v4sf ci2, di2, ci4, ci5, di3, di4, di5, ci3, cr2, cr3, dr2, dr3, dr4, dr5,
+ cr5, cr4, ti2, ti3, ti5, ti4, tr2, tr3, tr4, tr5;
+ int idp2;
+
+
+#define cc_ref(a_1,a_2,a_3) cc[((a_3)*l1 + (a_2))*ido + a_1]
+#define ch_ref(a_1,a_2,a_3) ch[((a_3)*5 + (a_2))*ido + a_1]
+
+ /* Parameter adjustments */
+ ch_offset = 1 + ido * 6;
+ ch -= ch_offset;
+ cc_offset = 1 + ido * (1 + l1);
+ cc -= cc_offset;
+
+ /* Function Body */
+ for (k = 1; k <= l1; ++k) {
+ cr2 = VADD(cc_ref(1, k, 5), cc_ref(1, k, 2));
+ ci5 = VSUB(cc_ref(1, k, 5), cc_ref(1, k, 2));
+ cr3 = VADD(cc_ref(1, k, 4), cc_ref(1, k, 3));
+ ci4 = VSUB(cc_ref(1, k, 4), cc_ref(1, k, 3));
+ ch_ref(1, 1, k) = VADD(cc_ref(1, k, 1), VADD(cr2, cr3));
+ ch_ref(ido, 2, k) = VADD(cc_ref(1, k, 1), VADD(SVMUL(tr11, cr2), SVMUL(tr12, cr3)));
+ ch_ref(1, 3, k) = VADD(SVMUL(ti11, ci5), SVMUL(ti12, ci4));
+ ch_ref(ido, 4, k) = VADD(cc_ref(1, k, 1), VADD(SVMUL(tr12, cr2), SVMUL(tr11, cr3)));
+ ch_ref(1, 5, k) = VSUB(SVMUL(ti12, ci5), SVMUL(ti11, ci4));
+ //printf("pffft: radf5, k=%d ch_ref=%f, ci4=%f\n", k, ch_ref(1, 5, k), ci4);
+ }
+ if (ido == 1) {
+ return;
+ }
+ idp2 = ido + 2;
+ for (k = 1; k <= l1; ++k) {
+ for (i = 3; i <= ido; i += 2) {
+ ic = idp2 - i;
+ dr2 = LD_PS1(wa1[i-3]); di2 = LD_PS1(wa1[i-2]);
+ dr3 = LD_PS1(wa2[i-3]); di3 = LD_PS1(wa2[i-2]);
+ dr4 = LD_PS1(wa3[i-3]); di4 = LD_PS1(wa3[i-2]);
+ dr5 = LD_PS1(wa4[i-3]); di5 = LD_PS1(wa4[i-2]);
+ VCPLXMULCONJ(dr2, di2, cc_ref(i-1, k, 2), cc_ref(i, k, 2));
+ VCPLXMULCONJ(dr3, di3, cc_ref(i-1, k, 3), cc_ref(i, k, 3));
+ VCPLXMULCONJ(dr4, di4, cc_ref(i-1, k, 4), cc_ref(i, k, 4));
+ VCPLXMULCONJ(dr5, di5, cc_ref(i-1, k, 5), cc_ref(i, k, 5));
+ cr2 = VADD(dr2, dr5);
+ ci5 = VSUB(dr5, dr2);
+ cr5 = VSUB(di2, di5);
+ ci2 = VADD(di2, di5);
+ cr3 = VADD(dr3, dr4);
+ ci4 = VSUB(dr4, dr3);
+ cr4 = VSUB(di3, di4);
+ ci3 = VADD(di3, di4);
+ ch_ref(i - 1, 1, k) = VADD(cc_ref(i - 1, k, 1), VADD(cr2, cr3));
+ ch_ref(i, 1, k) = VSUB(cc_ref(i, k, 1), VADD(ci2, ci3));//
+ tr2 = VADD(cc_ref(i - 1, k, 1), VADD(SVMUL(tr11, cr2), SVMUL(tr12, cr3)));
+ ti2 = VSUB(cc_ref(i, k, 1), VADD(SVMUL(tr11, ci2), SVMUL(tr12, ci3)));//
+ tr3 = VADD(cc_ref(i - 1, k, 1), VADD(SVMUL(tr12, cr2), SVMUL(tr11, cr3)));
+ ti3 = VSUB(cc_ref(i, k, 1), VADD(SVMUL(tr12, ci2), SVMUL(tr11, ci3)));//
+ tr5 = VADD(SVMUL(ti11, cr5), SVMUL(ti12, cr4));
+ ti5 = VADD(SVMUL(ti11, ci5), SVMUL(ti12, ci4));
+ tr4 = VSUB(SVMUL(ti12, cr5), SVMUL(ti11, cr4));
+ ti4 = VSUB(SVMUL(ti12, ci5), SVMUL(ti11, ci4));
+ ch_ref(i - 1, 3, k) = VSUB(tr2, tr5);
+ ch_ref(ic - 1, 2, k) = VADD(tr2, tr5);
+ ch_ref(i, 3, k) = VADD(ti2, ti5);
+ ch_ref(ic, 2, k) = VSUB(ti5, ti2);
+ ch_ref(i - 1, 5, k) = VSUB(tr3, tr4);
+ ch_ref(ic - 1, 4, k) = VADD(tr3, tr4);
+ ch_ref(i, 5, k) = VADD(ti3, ti4);
+ ch_ref(ic, 4, k) = VSUB(ti4, ti3);
+ }
+ }
+#undef cc_ref
+#undef ch_ref
+} /* radf5 */
+
+static void radb5_ps(int ido, int l1, const v4sf *RESTRICT cc, v4sf *RESTRICT ch,
+ const float *wa1, const float *wa2, const float *wa3, const float *wa4)
+{
+ static const float tr11 = .309016994374947f;
+ static const float ti11 = .951056516295154f;
+ static const float tr12 = -.809016994374947f;
+ static const float ti12 = .587785252292473f;
+
+ int cc_offset, ch_offset;
+
+ /* Local variables */
+ int i, k, ic;
+ v4sf ci2, ci3, ci4, ci5, di3, di4, di5, di2, cr2, cr3, cr5, cr4, ti2, ti3,
+ ti4, ti5, dr3, dr4, dr5, dr2, tr2, tr3, tr4, tr5;
+ int idp2;
+
+#define cc_ref(a_1,a_2,a_3) cc[((a_3)*5 + (a_2))*ido + a_1]
+#define ch_ref(a_1,a_2,a_3) ch[((a_3)*l1 + (a_2))*ido + a_1]
+
+ /* Parameter adjustments */
+ ch_offset = 1 + ido * (1 + l1);
+ ch -= ch_offset;
+ cc_offset = 1 + ido * 6;
+ cc -= cc_offset;
+
+ /* Function Body */
+ for (k = 1; k <= l1; ++k) {
+ ti5 = VADD(cc_ref(1, 3, k), cc_ref(1, 3, k));
+ ti4 = VADD(cc_ref(1, 5, k), cc_ref(1, 5, k));
+ tr2 = VADD(cc_ref(ido, 2, k), cc_ref(ido, 2, k));
+ tr3 = VADD(cc_ref(ido, 4, k), cc_ref(ido, 4, k));
+ ch_ref(1, k, 1) = VADD(cc_ref(1, 1, k), VADD(tr2, tr3));
+ cr2 = VADD(cc_ref(1, 1, k), VADD(SVMUL(tr11, tr2), SVMUL(tr12, tr3)));
+ cr3 = VADD(cc_ref(1, 1, k), VADD(SVMUL(tr12, tr2), SVMUL(tr11, tr3)));
+ ci5 = VADD(SVMUL(ti11, ti5), SVMUL(ti12, ti4));
+ ci4 = VSUB(SVMUL(ti12, ti5), SVMUL(ti11, ti4));
+ ch_ref(1, k, 2) = VSUB(cr2, ci5);
+ ch_ref(1, k, 3) = VSUB(cr3, ci4);
+ ch_ref(1, k, 4) = VADD(cr3, ci4);
+ ch_ref(1, k, 5) = VADD(cr2, ci5);
+ }
+ if (ido == 1) {
+ return;
+ }
+ idp2 = ido + 2;
+ for (k = 1; k <= l1; ++k) {
+ for (i = 3; i <= ido; i += 2) {
+ ic = idp2 - i;
+ ti5 = VADD(cc_ref(i , 3, k), cc_ref(ic , 2, k));
+ ti2 = VSUB(cc_ref(i , 3, k), cc_ref(ic , 2, k));
+ ti4 = VADD(cc_ref(i , 5, k), cc_ref(ic , 4, k));
+ ti3 = VSUB(cc_ref(i , 5, k), cc_ref(ic , 4, k));
+ tr5 = VSUB(cc_ref(i-1, 3, k), cc_ref(ic-1, 2, k));
+ tr2 = VADD(cc_ref(i-1, 3, k), cc_ref(ic-1, 2, k));
+ tr4 = VSUB(cc_ref(i-1, 5, k), cc_ref(ic-1, 4, k));
+ tr3 = VADD(cc_ref(i-1, 5, k), cc_ref(ic-1, 4, k));
+ ch_ref(i - 1, k, 1) = VADD(cc_ref(i-1, 1, k), VADD(tr2, tr3));
+ ch_ref(i, k, 1) = VADD(cc_ref(i, 1, k), VADD(ti2, ti3));
+ cr2 = VADD(cc_ref(i-1, 1, k), VADD(SVMUL(tr11, tr2), SVMUL(tr12, tr3)));
+ ci2 = VADD(cc_ref(i , 1, k), VADD(SVMUL(tr11, ti2), SVMUL(tr12, ti3)));
+ cr3 = VADD(cc_ref(i-1, 1, k), VADD(SVMUL(tr12, tr2), SVMUL(tr11, tr3)));
+ ci3 = VADD(cc_ref(i , 1, k), VADD(SVMUL(tr12, ti2), SVMUL(tr11, ti3)));
+ cr5 = VADD(SVMUL(ti11, tr5), SVMUL(ti12, tr4));
+ ci5 = VADD(SVMUL(ti11, ti5), SVMUL(ti12, ti4));
+ cr4 = VSUB(SVMUL(ti12, tr5), SVMUL(ti11, tr4));
+ ci4 = VSUB(SVMUL(ti12, ti5), SVMUL(ti11, ti4));
+ dr3 = VSUB(cr3, ci4);
+ dr4 = VADD(cr3, ci4);
+ di3 = VADD(ci3, cr4);
+ di4 = VSUB(ci3, cr4);
+ dr5 = VADD(cr2, ci5);
+ dr2 = VSUB(cr2, ci5);
+ di5 = VSUB(ci2, cr5);
+ di2 = VADD(ci2, cr5);
+ VCPLXMUL(dr2, di2, LD_PS1(wa1[i-3]), LD_PS1(wa1[i-2]));
+ VCPLXMUL(dr3, di3, LD_PS1(wa2[i-3]), LD_PS1(wa2[i-2]));
+ VCPLXMUL(dr4, di4, LD_PS1(wa3[i-3]), LD_PS1(wa3[i-2]));
+ VCPLXMUL(dr5, di5, LD_PS1(wa4[i-3]), LD_PS1(wa4[i-2]));
+
+ ch_ref(i-1, k, 2) = dr2; ch_ref(i, k, 2) = di2;
+ ch_ref(i-1, k, 3) = dr3; ch_ref(i, k, 3) = di3;
+ ch_ref(i-1, k, 4) = dr4; ch_ref(i, k, 4) = di4;
+ ch_ref(i-1, k, 5) = dr5; ch_ref(i, k, 5) = di5;
+ }
+ }
+#undef cc_ref
+#undef ch_ref
+} /* radb5 */
+
+static NEVER_INLINE(v4sf *) rfftf1_ps(int n, const v4sf *input_readonly, v4sf *work1, v4sf *work2,
+ const float *wa, const int *ifac) {
+ v4sf *in = (v4sf*)input_readonly;
+ v4sf *out = (in == work2 ? work1 : work2);
+ int nf = ifac[1], k1;
+ int l2 = n;
+ int iw = n-1;
+ assert(in != out && work1 != work2);
+ for (k1 = 1; k1 <= nf; ++k1) {
+ int kh = nf - k1;
+ int ip = ifac[kh + 2];
+ int l1 = l2 / ip;
+ int ido = n / l2;
+ iw -= (ip - 1)*ido;
+ switch (ip) {
+ case 5: {
+ int ix2 = iw + ido;
+ int ix3 = ix2 + ido;
+ int ix4 = ix3 + ido;
+ radf5_ps(ido, l1, in, out, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4]);
+ } break;
+ case 4: {
+ int ix2 = iw + ido;
+ int ix3 = ix2 + ido;
+ radf4_ps(ido, l1, in, out, &wa[iw], &wa[ix2], &wa[ix3]);
+ } break;
+ case 3: {
+ int ix2 = iw + ido;
+ radf3_ps(ido, l1, in, out, &wa[iw], &wa[ix2]);
+ } break;
+ case 2:
+ radf2_ps(ido, l1, in, out, &wa[iw]);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ l2 = l1;
+ if (out == work2) {
+ out = work1; in = work2;
+ } else {
+ out = work2; in = work1;
+ }
+ }
+ return in; /* this is in fact the output .. */
+} /* rfftf1 */
+
+static NEVER_INLINE(v4sf *) rfftb1_ps(int n, const v4sf *input_readonly, v4sf *work1, v4sf *work2,
+ const float *wa, const int *ifac) {
+ v4sf *in = (v4sf*)input_readonly;
+ v4sf *out = (in == work2 ? work1 : work2);
+ int nf = ifac[1], k1;
+ int l1 = 1;
+ int iw = 0;
+ assert(in != out);
+ for (k1=1; k1<=nf; k1++) {
+ int ip = ifac[k1 + 1];
+ int l2 = ip*l1;
+ int ido = n / l2;
+ switch (ip) {
+ case 5: {
+ int ix2 = iw + ido;
+ int ix3 = ix2 + ido;
+ int ix4 = ix3 + ido;
+ radb5_ps(ido, l1, in, out, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4]);
+ } break;
+ case 4: {
+ int ix2 = iw + ido;
+ int ix3 = ix2 + ido;
+ radb4_ps(ido, l1, in, out, &wa[iw], &wa[ix2], &wa[ix3]);
+ } break;
+ case 3: {
+ int ix2 = iw + ido;
+ radb3_ps(ido, l1, in, out, &wa[iw], &wa[ix2]);
+ } break;
+ case 2:
+ radb2_ps(ido, l1, in, out, &wa[iw]);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ l1 = l2;
+ iw += (ip - 1)*ido;
+
+ if (out == work2) {
+ out = work1; in = work2;
+ } else {
+ out = work2; in = work1;
+ }
+ }
+ return in; /* this is in fact the output .. */
+}
+
+static int decompose(int n, int *ifac, const int *ntryh) {
+ int nl = n, nf = 0, i, j = 0;
+ for (j=0; ntryh[j]; ++j) {
+ int ntry = ntryh[j];
+ while (nl != 1) {
+ int nq = nl / ntry;
+ int nr = nl - ntry * nq;
+ if (nr == 0) {
+ ifac[2+nf++] = ntry;
+ nl = nq;
+ if (ntry == 2 && nf != 1) {
+ for (i = 2; i <= nf; ++i) {
+ int ib = nf - i + 2;
+ ifac[ib + 1] = ifac[ib];
+ }
+ ifac[2] = 2;
+ }
+ } else break;
+ }
+ }
+ ifac[0] = n;
+ ifac[1] = nf;
+ return nf;
+}
+
+
+
+static void rffti1_ps(int n, float *wa, int *ifac)
+{
+ static const int ntryh[] = { 4,2,3,5,0 };
+ int k1, j, ii;
+
+ int nf = decompose(n,ifac,ntryh);
+ float argh = (2*M_PI) / n;
+ int is = 0;
+ int nfm1 = nf - 1;
+ int l1 = 1;
+ for (k1 = 1; k1 <= nfm1; k1++) {
+ int ip = ifac[k1 + 1];
+ int ld = 0;
+ int l2 = l1*ip;
+ int ido = n / l2;
+ int ipm = ip - 1;
+ for (j = 1; j <= ipm; ++j) {
+ float argld;
+ int i = is, fi=0;
+ ld += l1;
+ argld = ld*argh;
+ for (ii = 3; ii <= ido; ii += 2) {
+ i += 2;
+ fi += 1;
+ wa[i - 2] = cos(fi*argld);
+ wa[i - 1] = sin(fi*argld);
+ }
+ is += ido;
+ }
+ l1 = l2;
+ }
+} /* rffti1 */
+
+void cffti1_ps(int n, float *wa, int *ifac)
+{
+ static const int ntryh[] = { 5,3,4,2,0 };
+ int k1, j, ii;
+
+ int nf = decompose(n,ifac,ntryh);
+ float argh = (2*M_PI)/(float)n;
+ int i = 1;
+ int l1 = 1;
+ for (k1=1; k1<=nf; k1++) {
+ int ip = ifac[k1+1];
+ int ld = 0;
+ int l2 = l1*ip;
+ int ido = n / l2;
+ int idot = ido + ido + 2;
+ int ipm = ip - 1;
+ for (j=1; j<=ipm; j++) {
+ float argld;
+ int i1 = i, fi = 0;
+ wa[i-1] = 1;
+ wa[i] = 0;
+ ld += l1;
+ argld = ld*argh;
+ for (ii = 4; ii <= idot; ii += 2) {
+ i += 2;
+ fi += 1;
+ wa[i-1] = cos(fi*argld);
+ wa[i] = sin(fi*argld);
+ }
+ if (ip > 5) {
+ wa[i1-1] = wa[i-1];
+ wa[i1] = wa[i];
+ }
+ }
+ l1 = l2;
+ }
+} /* cffti1 */
+
+
+v4sf *cfftf1_ps(int n, const v4sf *input_readonly, v4sf *work1, v4sf *work2, const float *wa, const int *ifac, int isign) {
+ v4sf *in = (v4sf*)input_readonly;
+ v4sf *out = (in == work2 ? work1 : work2);
+ int nf = ifac[1], k1;
+ int l1 = 1;
+ int iw = 0;
+ assert(in != out && work1 != work2);
+ for (k1=2; k1<=nf+1; k1++) {
+ int ip = ifac[k1];
+ int l2 = ip*l1;
+ int ido = n / l2;
+ int idot = ido + ido;
+ switch (ip) {
+ case 5: {
+ int ix2 = iw + idot;
+ int ix3 = ix2 + idot;
+ int ix4 = ix3 + idot;
+ passf5_ps(idot, l1, in, out, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4], isign);
+ } break;
+ case 4: {
+ int ix2 = iw + idot;
+ int ix3 = ix2 + idot;
+ passf4_ps(idot, l1, in, out, &wa[iw], &wa[ix2], &wa[ix3], isign);
+ } break;
+ case 2: {
+ passf2_ps(idot, l1, in, out, &wa[iw], isign);
+ } break;
+ case 3: {
+ int ix2 = iw + idot;
+ passf3_ps(idot, l1, in, out, &wa[iw], &wa[ix2], isign);
+ } break;
+ default:
+ assert(0);
+ }
+ l1 = l2;
+ iw += (ip - 1)*idot;
+ if (out == work2) {
+ out = work1; in = work2;
+ } else {
+ out = work2; in = work1;
+ }
+ }
+
+ return in; /* this is in fact the output .. */
+}
+
+
+struct PFFFT_Setup {
+ int N;
+ int Ncvec; // nb of complex simd vectors (N/4 if PFFFT_COMPLEX, N/8 if PFFFT_REAL)
+ int ifac[15];
+ pffft_transform_t transform;
+ v4sf *data; // allocated room for twiddle coefs
+ float *e; // points into 'data' , N/4*3 elements
+ float *twiddle; // points into 'data', N/4 elements
+};
+
+PFFFT_Setup *pffft_new_setup(int N, pffft_transform_t transform) {
+ PFFFT_Setup *s = (PFFFT_Setup*)malloc(sizeof(PFFFT_Setup));
+ int k, m;
+ /* unfortunately, the fft size must be a multiple of 16 for complex FFTs
+ and 32 for real FFTs -- a lot of stuff would need to be rewritten to
+ handle other cases (or maybe just switch to a scalar fft, I don't know..) */
+ if (transform == PFFFT_REAL) { assert((N%(2*SIMD_SZ*SIMD_SZ))==0 && N>0); }
+ if (transform == PFFFT_COMPLEX) { assert((N%(SIMD_SZ*SIMD_SZ))==0 && N>0); }
+ //assert((N % 32) == 0);
+ s->N = N;
+ s->transform = transform;
+ /* nb of complex simd vectors */
+ s->Ncvec = (transform == PFFFT_REAL ? N/2 : N)/SIMD_SZ;
+ s->data = (v4sf*)pffft_aligned_malloc(2*s->Ncvec * sizeof(v4sf));
+ s->e = (float*)s->data;
+ s->twiddle = (float*)(s->data + (2*s->Ncvec*(SIMD_SZ-1))/SIMD_SZ);
+
+ if (transform == PFFFT_REAL) {
+ for (k=0; k < s->Ncvec; ++k) {
+ int i = k/SIMD_SZ;
+ int j = k%SIMD_SZ;
+ for (m=0; m < SIMD_SZ-1; ++m) {
+ float A = -2*M_PI*(m+1)*k / N;
+ s->e[(2*(i*3 + m) + 0) * SIMD_SZ + j] = cos(A);
+ s->e[(2*(i*3 + m) + 1) * SIMD_SZ + j] = sin(A);
+ }
+ }
+ rffti1_ps(N/SIMD_SZ, s->twiddle, s->ifac);
+ } else {
+ for (k=0; k < s->Ncvec; ++k) {
+ int i = k/SIMD_SZ;
+ int j = k%SIMD_SZ;
+ for (m=0; m < SIMD_SZ-1; ++m) {
+ float A = -2*M_PI*(m+1)*k / N;
+ s->e[(2*(i*3 + m) + 0)*SIMD_SZ + j] = cos(A);
+ s->e[(2*(i*3 + m) + 1)*SIMD_SZ + j] = sin(A);
+ }
+ }
+ cffti1_ps(N/SIMD_SZ, s->twiddle, s->ifac);
+ }
+
+ /* check that N is decomposable with allowed prime factors */
+ for (k=0, m=1; k < s->ifac[1]; ++k) { m *= s->ifac[2+k]; }
+ if (m != N/SIMD_SZ) {
+ pffft_destroy_setup(s); s = 0;
+ }
+
+ return s;
+}
+
+
+void pffft_destroy_setup(PFFFT_Setup *s) {
+ pffft_aligned_free(s->data);
+ free(s);
+}
+
+#if !defined(PFFFT_SIMD_DISABLE)
+
+/* [0 0 1 2 3 4 5 6 7 8] -> [0 8 7 6 5 4 3 2 1] */
+static void reversed_copy(int N, const v4sf *in, int in_stride, v4sf *out) {
+ v4sf g0, g1;
+ int k;
+ INTERLEAVE2(in[0], in[1], g0, g1); in += in_stride;
+
+ *--out = VSWAPHL(g0, g1); // [g0l, g0h], [g1l g1h] -> [g1l, g0h]
+ for (k=1; k < N; ++k) {
+ v4sf h0, h1;
+ INTERLEAVE2(in[0], in[1], h0, h1); in += in_stride;
+ *--out = VSWAPHL(g1, h0);
+ *--out = VSWAPHL(h0, h1);
+ g1 = h1;
+ }
+ *--out = VSWAPHL(g1, g0);
+}
+
+static void unreversed_copy(int N, const v4sf *in, v4sf *out, int out_stride) {
+ v4sf g0, g1, h0, h1;
+ int k;
+ g0 = g1 = in[0]; ++in;
+ for (k=1; k < N; ++k) {
+ h0 = *in++; h1 = *in++;
+ g1 = VSWAPHL(g1, h0);
+ h0 = VSWAPHL(h0, h1);
+ UNINTERLEAVE2(h0, g1, out[0], out[1]); out += out_stride;
+ g1 = h1;
+ }
+ h0 = *in++; h1 = g0;
+ g1 = VSWAPHL(g1, h0);
+ h0 = VSWAPHL(h0, h1);
+ UNINTERLEAVE2(h0, g1, out[0], out[1]);
+}
+
+void pffft_zreorder(PFFFT_Setup *setup, const float *in, float *out, pffft_direction_t direction) {
+ int k, N = setup->N, Ncvec = setup->Ncvec;
+ const v4sf *vin = (const v4sf*)in;
+ v4sf *vout = (v4sf*)out;
+ assert(in != out);
+ if (setup->transform == PFFFT_REAL) {
+ int k, dk = N/32;
+ if (direction == PFFFT_FORWARD) {
+ for (k=0; k < dk; ++k) {
+ INTERLEAVE2(vin[k*8 + 0], vin[k*8 + 1], vout[2*(0*dk + k) + 0], vout[2*(0*dk + k) + 1]);
+ INTERLEAVE2(vin[k*8 + 4], vin[k*8 + 5], vout[2*(2*dk + k) + 0], vout[2*(2*dk + k) + 1]);
+ }
+ reversed_copy(dk, vin+2, 8, (v4sf*)(out + N/2));
+ reversed_copy(dk, vin+6, 8, (v4sf*)(out + N));
+ } else {
+ for (k=0; k < dk; ++k) {
+ UNINTERLEAVE2(vin[2*(0*dk + k) + 0], vin[2*(0*dk + k) + 1], vout[k*8 + 0], vout[k*8 + 1]);
+ UNINTERLEAVE2(vin[2*(2*dk + k) + 0], vin[2*(2*dk + k) + 1], vout[k*8 + 4], vout[k*8 + 5]);
+ }
+ unreversed_copy(dk, (v4sf*)(in + N/4), (v4sf*)(out + N - 6*SIMD_SZ), -8);
+ unreversed_copy(dk, (v4sf*)(in + 3*N/4), (v4sf*)(out + N - 2*SIMD_SZ), -8);
+ }
+ } else {
+ if (direction == PFFFT_FORWARD) {
+ for (k=0; k < Ncvec; ++k) {
+ int kk = (k/4) + (k%4)*(Ncvec/4);
+ INTERLEAVE2(vin[k*2], vin[k*2+1], vout[kk*2], vout[kk*2+1]);
+ }
+ } else {
+ for (k=0; k < Ncvec; ++k) {
+ int kk = (k/4) + (k%4)*(Ncvec/4);
+ UNINTERLEAVE2(vin[kk*2], vin[kk*2+1], vout[k*2], vout[k*2+1]);
+ }
+ }
+ }
+}
+
+void pffft_cplx_finalize(int Ncvec, const v4sf *in, v4sf *out, const v4sf *e) {
+ int k, dk = Ncvec/SIMD_SZ; // number of 4x4 matrix blocks
+ v4sf r0, i0, r1, i1, r2, i2, r3, i3;
+ v4sf sr0, dr0, sr1, dr1, si0, di0, si1, di1;
+ assert(in != out);
+ for (k=0; k < dk; ++k) {
+ r0 = in[8*k+0]; i0 = in[8*k+1];
+ r1 = in[8*k+2]; i1 = in[8*k+3];
+ r2 = in[8*k+4]; i2 = in[8*k+5];
+ r3 = in[8*k+6]; i3 = in[8*k+7];
+ VTRANSPOSE4(r0,r1,r2,r3);
+ VTRANSPOSE4(i0,i1,i2,i3);
+ VCPLXMUL(r1,i1,e[k*6+0],e[k*6+1]);
+ VCPLXMUL(r2,i2,e[k*6+2],e[k*6+3]);
+ VCPLXMUL(r3,i3,e[k*6+4],e[k*6+5]);
+
+ sr0 = VADD(r0,r2); dr0 = VSUB(r0, r2);
+ sr1 = VADD(r1,r3); dr1 = VSUB(r1, r3);
+ si0 = VADD(i0,i2); di0 = VSUB(i0, i2);
+ si1 = VADD(i1,i3); di1 = VSUB(i1, i3);
+
+ /*
+ transformation for each column is:
+
+ [1 1 1 1 0 0 0 0] [r0]
+ [1 0 -1 0 0 -1 0 1] [r1]
+ [1 -1 1 -1 0 0 0 0] [r2]
+ [1 0 -1 0 0 1 0 -1] [r3]
+ [0 0 0 0 1 1 1 1] * [i0]
+ [0 1 0 -1 1 0 -1 0] [i1]
+ [0 0 0 0 1 -1 1 -1] [i2]
+ [0 -1 0 1 1 0 -1 0] [i3]
+ */
+
+ r0 = VADD(sr0, sr1); i0 = VADD(si0, si1);
+ r1 = VADD(dr0, di1); i1 = VSUB(di0, dr1);
+ r2 = VSUB(sr0, sr1); i2 = VSUB(si0, si1);
+ r3 = VSUB(dr0, di1); i3 = VADD(di0, dr1);
+
+ *out++ = r0; *out++ = i0; *out++ = r1; *out++ = i1;
+ *out++ = r2; *out++ = i2; *out++ = r3; *out++ = i3;
+ }
+}
+
+void pffft_cplx_preprocess(int Ncvec, const v4sf *in, v4sf *out, const v4sf *e) {
+ int k, dk = Ncvec/SIMD_SZ; // number of 4x4 matrix blocks
+ v4sf r0, i0, r1, i1, r2, i2, r3, i3;
+ v4sf sr0, dr0, sr1, dr1, si0, di0, si1, di1;
+ assert(in != out);
+ for (k=0; k < dk; ++k) {
+ r0 = in[8*k+0]; i0 = in[8*k+1];
+ r1 = in[8*k+2]; i1 = in[8*k+3];
+ r2 = in[8*k+4]; i2 = in[8*k+5];
+ r3 = in[8*k+6]; i3 = in[8*k+7];
+
+ sr0 = VADD(r0,r2); dr0 = VSUB(r0, r2);
+ sr1 = VADD(r1,r3); dr1 = VSUB(r1, r3);
+ si0 = VADD(i0,i2); di0 = VSUB(i0, i2);
+ si1 = VADD(i1,i3); di1 = VSUB(i1, i3);
+
+ r0 = VADD(sr0, sr1); i0 = VADD(si0, si1);
+ r1 = VSUB(dr0, di1); i1 = VADD(di0, dr1);
+ r2 = VSUB(sr0, sr1); i2 = VSUB(si0, si1);
+ r3 = VADD(dr0, di1); i3 = VSUB(di0, dr1);
+
+ VCPLXMULCONJ(r1,i1,e[k*6+0],e[k*6+1]);
+ VCPLXMULCONJ(r2,i2,e[k*6+2],e[k*6+3]);
+ VCPLXMULCONJ(r3,i3,e[k*6+4],e[k*6+5]);
+
+ VTRANSPOSE4(r0,r1,r2,r3);
+ VTRANSPOSE4(i0,i1,i2,i3);
+
+ *out++ = r0; *out++ = i0; *out++ = r1; *out++ = i1;
+ *out++ = r2; *out++ = i2; *out++ = r3; *out++ = i3;
+ }
+}
+
+
+static ALWAYS_INLINE(void) pffft_real_finalize_4x4(const v4sf *in0, const v4sf *in1, const v4sf *in,
+ const v4sf *e, v4sf *out) {
+ v4sf r0, i0, r1, i1, r2, i2, r3, i3;
+ v4sf sr0, dr0, sr1, dr1, si0, di0, si1, di1;
+ r0 = *in0; i0 = *in1;
+ r1 = *in++; i1 = *in++; r2 = *in++; i2 = *in++; r3 = *in++; i3 = *in++;
+ VTRANSPOSE4(r0,r1,r2,r3);
+ VTRANSPOSE4(i0,i1,i2,i3);
+
+ /*
+ transformation for each column is:
+
+ [1 1 1 1 0 0 0 0] [r0]
+ [1 0 -1 0 0 -1 0 1] [r1]
+ [1 0 -1 0 0 1 0 -1] [r2]
+ [1 -1 1 -1 0 0 0 0] [r3]
+ [0 0 0 0 1 1 1 1] * [i0]
+ [0 -1 0 1 -1 0 1 0] [i1]
+ [0 -1 0 1 1 0 -1 0] [i2]
+ [0 0 0 0 -1 1 -1 1] [i3]
+ */
+
+ //cerr << "matrix initial, before e , REAL:\n 1: " << r0 << "\n 1: " << r1 << "\n 1: " << r2 << "\n 1: " << r3 << "\n";
+ //cerr << "matrix initial, before e, IMAG :\n 1: " << i0 << "\n 1: " << i1 << "\n 1: " << i2 << "\n 1: " << i3 << "\n";
+
+ VCPLXMUL(r1,i1,e[0],e[1]);
+ VCPLXMUL(r2,i2,e[2],e[3]);
+ VCPLXMUL(r3,i3,e[4],e[5]);
+
+ //cerr << "matrix initial, real part:\n 1: " << r0 << "\n 1: " << r1 << "\n 1: " << r2 << "\n 1: " << r3 << "\n";
+ //cerr << "matrix initial, imag part:\n 1: " << i0 << "\n 1: " << i1 << "\n 1: " << i2 << "\n 1: " << i3 << "\n";
+
+ sr0 = VADD(r0,r2); dr0 = VSUB(r0,r2);
+ sr1 = VADD(r1,r3); dr1 = VSUB(r3,r1);
+ si0 = VADD(i0,i2); di0 = VSUB(i0,i2);
+ si1 = VADD(i1,i3); di1 = VSUB(i3,i1);
+
+ r0 = VADD(sr0, sr1);
+ r3 = VSUB(sr0, sr1);
+ i0 = VADD(si0, si1);
+ i3 = VSUB(si1, si0);
+ r1 = VADD(dr0, di1);
+ r2 = VSUB(dr0, di1);
+ i1 = VSUB(dr1, di0);
+ i2 = VADD(dr1, di0);
+
+ *out++ = r0;
+ *out++ = i0;
+ *out++ = r1;
+ *out++ = i1;
+ *out++ = r2;
+ *out++ = i2;
+ *out++ = r3;
+ *out++ = i3;
+
+}
+
+static NEVER_INLINE(void) pffft_real_finalize(int Ncvec, const v4sf *in, v4sf *out, const v4sf *e) {
+ int k, dk = Ncvec/SIMD_SZ; // number of 4x4 matrix blocks
+ /* fftpack order is f0r f1r f1i f2r f2i ... f(n-1)r f(n-1)i f(n)r */
+
+ v4sf_union cr, ci, *uout = (v4sf_union*)out;
+ v4sf save = in[7], zero=VZERO();
+ float xr0, xi0, xr1, xi1, xr2, xi2, xr3, xi3;
+ static const float s = M_SQRT2/2;
+
+ cr.v = in[0]; ci.v = in[Ncvec*2-1];
+ assert(in != out);
+ pffft_real_finalize_4x4(&zero, &zero, in+1, e, out);
+
+ /*
+ [cr0 cr1 cr2 cr3 ci0 ci1 ci2 ci3]
+
+ [Xr(1)] ] [1 1 1 1 0 0 0 0]
+ [Xr(N/4) ] [0 0 0 0 1 s 0 -s]
+ [Xr(N/2) ] [1 0 -1 0 0 0 0 0]
+ [Xr(3N/4)] [0 0 0 0 1 -s 0 s]
+ [Xi(1) ] [1 -1 1 -1 0 0 0 0]
+ [Xi(N/4) ] [0 0 0 0 0 -s -1 -s]
+ [Xi(N/2) ] [0 -1 0 1 0 0 0 0]
+ [Xi(3N/4)] [0 0 0 0 0 -s 1 -s]
+ */
+
+ xr0=(cr.f[0]+cr.f[2]) + (cr.f[1]+cr.f[3]); uout[0].f[0] = xr0;
+ xi0=(cr.f[0]+cr.f[2]) - (cr.f[1]+cr.f[3]); uout[1].f[0] = xi0;
+ xr2=(cr.f[0]-cr.f[2]); uout[4].f[0] = xr2;
+ xi2=(cr.f[3]-cr.f[1]); uout[5].f[0] = xi2;
+ xr1= ci.f[0] + s*(ci.f[1]-ci.f[3]); uout[2].f[0] = xr1;
+ xi1=-ci.f[2] - s*(ci.f[1]+ci.f[3]); uout[3].f[0] = xi1;
+ xr3= ci.f[0] - s*(ci.f[1]-ci.f[3]); uout[6].f[0] = xr3;
+ xi3= ci.f[2] - s*(ci.f[1]+ci.f[3]); uout[7].f[0] = xi3;
+
+ for (k=1; k < dk; ++k) {
+ v4sf save_next = in[8*k+7];
+ pffft_real_finalize_4x4(&save, &in[8*k+0], in + 8*k+1,
+ e + k*6, out + k*8);
+ save = save_next;
+ }
+
+}
+
+static ALWAYS_INLINE(void) pffft_real_preprocess_4x4(const v4sf *in,
+ const v4sf *e, v4sf *out, int first) {
+ v4sf r0=in[0], i0=in[1], r1=in[2], i1=in[3], r2=in[4], i2=in[5], r3=in[6], i3=in[7];
+ /*
+ transformation for each column is:
+
+ [1 1 1 1 0 0 0 0] [r0]
+ [1 0 0 -1 0 -1 -1 0] [r1]
+ [1 -1 -1 1 0 0 0 0] [r2]
+ [1 0 0 -1 0 1 1 0] [r3]
+ [0 0 0 0 1 -1 1 -1] * [i0]
+ [0 -1 1 0 1 0 0 1] [i1]
+ [0 0 0 0 1 1 -1 -1] [i2]
+ [0 1 -1 0 1 0 0 1] [i3]
+ */
+
+ v4sf sr0 = VADD(r0,r3), dr0 = VSUB(r0,r3);
+ v4sf sr1 = VADD(r1,r2), dr1 = VSUB(r1,r2);
+ v4sf si0 = VADD(i0,i3), di0 = VSUB(i0,i3);
+ v4sf si1 = VADD(i1,i2), di1 = VSUB(i1,i2);
+
+ r0 = VADD(sr0, sr1);
+ r2 = VSUB(sr0, sr1);
+ r1 = VSUB(dr0, si1);
+ r3 = VADD(dr0, si1);
+ i0 = VSUB(di0, di1);
+ i2 = VADD(di0, di1);
+ i1 = VSUB(si0, dr1);
+ i3 = VADD(si0, dr1);
+
+ VCPLXMULCONJ(r1,i1,e[0],e[1]);
+ VCPLXMULCONJ(r2,i2,e[2],e[3]);
+ VCPLXMULCONJ(r3,i3,e[4],e[5]);
+
+ VTRANSPOSE4(r0,r1,r2,r3);
+ VTRANSPOSE4(i0,i1,i2,i3);
+
+ if (!first) {
+ *out++ = r0;
+ *out++ = i0;
+ }
+ *out++ = r1;
+ *out++ = i1;
+ *out++ = r2;
+ *out++ = i2;
+ *out++ = r3;
+ *out++ = i3;
+}
+
+static NEVER_INLINE(void) pffft_real_preprocess(int Ncvec, const v4sf *in, v4sf *out, const v4sf *e) {
+ int k, dk = Ncvec/SIMD_SZ; // number of 4x4 matrix blocks
+ /* fftpack order is f0r f1r f1i f2r f2i ... f(n-1)r f(n-1)i f(n)r */
+
+ v4sf_union Xr, Xi, *uout = (v4sf_union*)out;
+ float cr0, ci0, cr1, ci1, cr2, ci2, cr3, ci3;
+ static const float s = M_SQRT2;
+ assert(in != out);
+ for (k=0; k < 4; ++k) {
+ Xr.f[k] = ((float*)in)[8*k];
+ Xi.f[k] = ((float*)in)[8*k+4];
+ }
+
+ pffft_real_preprocess_4x4(in, e, out+1, 1); // will write only 6 values
+
+ /*
+ [Xr0 Xr1 Xr2 Xr3 Xi0 Xi1 Xi2 Xi3]
+
+ [cr0] [1 0 2 0 1 0 0 0]
+ [cr1] [1 0 0 0 -1 0 -2 0]
+ [cr2] [1 0 -2 0 1 0 0 0]
+ [cr3] [1 0 0 0 -1 0 2 0]
+ [ci0] [0 2 0 2 0 0 0 0]
+ [ci1] [0 s 0 -s 0 -s 0 -s]
+ [ci2] [0 0 0 0 0 -2 0 2]
+ [ci3] [0 -s 0 s 0 -s 0 -s]
+ */
+ for (k=1; k < dk; ++k) {
+ pffft_real_preprocess_4x4(in+8*k, e + k*6, out-1+k*8, 0);
+ }
+
+ cr0=(Xr.f[0]+Xi.f[0]) + 2*Xr.f[2]; uout[0].f[0] = cr0;
+ cr1=(Xr.f[0]-Xi.f[0]) - 2*Xi.f[2]; uout[0].f[1] = cr1;
+ cr2=(Xr.f[0]+Xi.f[0]) - 2*Xr.f[2]; uout[0].f[2] = cr2;
+ cr3=(Xr.f[0]-Xi.f[0]) + 2*Xi.f[2]; uout[0].f[3] = cr3;
+ ci0= 2*(Xr.f[1]+Xr.f[3]); uout[2*Ncvec-1].f[0] = ci0;
+ ci1= s*(Xr.f[1]-Xr.f[3]) - s*(Xi.f[1]+Xi.f[3]); uout[2*Ncvec-1].f[1] = ci1;
+ ci2= 2*(Xi.f[3]-Xi.f[1]); uout[2*Ncvec-1].f[2] = ci2;
+ ci3=-s*(Xr.f[1]-Xr.f[3]) - s*(Xi.f[1]+Xi.f[3]); uout[2*Ncvec-1].f[3] = ci3;
+}
+
+
+void pffft_transform_internal(PFFFT_Setup *setup, const float *finput, float *foutput, v4sf *scratch,
+ pffft_direction_t direction, int ordered) {
+ int k, Ncvec = setup->Ncvec;
+ int nf_odd = (setup->ifac[1] & 1);
+
+ // temporary buffer is allocated on the stack if the scratch pointer is NULL
+ int stack_allocate = (scratch == 0 ? Ncvec*2 : 1);
+ VLA_ARRAY_ON_STACK(v4sf, scratch_on_stack, stack_allocate);
+
+ const v4sf *vinput = (const v4sf*)finput;
+ v4sf *voutput = (v4sf*)foutput;
+ v4sf *buff[2] = { voutput, scratch ? scratch : scratch_on_stack };
+ int ib = (nf_odd ^ ordered ? 1 : 0);
+
+ assert(VALIGNED(finput) && VALIGNED(foutput));
+
+ //assert(finput != foutput);
+ if (direction == PFFFT_FORWARD) {
+ ib = !ib;
+ if (setup->transform == PFFFT_REAL) {
+ ib = (rfftf1_ps(Ncvec*2, vinput, buff[ib], buff[!ib],
+ setup->twiddle, &setup->ifac[0]) == buff[0] ? 0 : 1);
+ pffft_real_finalize(Ncvec, buff[ib], buff[!ib], (v4sf*)setup->e);
+ } else {
+ v4sf *tmp = buff[ib];
+ for (k=0; k < Ncvec; ++k) {
+ UNINTERLEAVE2(vinput[k*2], vinput[k*2+1], tmp[k*2], tmp[k*2+1]);
+ }
+ ib = (cfftf1_ps(Ncvec, buff[ib], buff[!ib], buff[ib],
+ setup->twiddle, &setup->ifac[0], -1) == buff[0] ? 0 : 1);
+ pffft_cplx_finalize(Ncvec, buff[ib], buff[!ib], (v4sf*)setup->e);
+ }
+ if (ordered) {
+ pffft_zreorder(setup, (float*)buff[!ib], (float*)buff[ib], PFFFT_FORWARD);
+ } else ib = !ib;
+ } else {
+ if (vinput == buff[ib]) {
+ ib = !ib; // may happen when finput == foutput
+ }
+ if (ordered) {
+ pffft_zreorder(setup, (float*)vinput, (float*)buff[ib], PFFFT_BACKWARD);
+ vinput = buff[ib]; ib = !ib;
+ }
+ if (setup->transform == PFFFT_REAL) {
+ pffft_real_preprocess(Ncvec, vinput, buff[ib], (v4sf*)setup->e);
+ ib = (rfftb1_ps(Ncvec*2, buff[ib], buff[0], buff[1],
+ setup->twiddle, &setup->ifac[0]) == buff[0] ? 0 : 1);
+ } else {
+ pffft_cplx_preprocess(Ncvec, vinput, buff[ib], (v4sf*)setup->e);
+ ib = (cfftf1_ps(Ncvec, buff[ib], buff[0], buff[1],
+ setup->twiddle, &setup->ifac[0], +1) == buff[0] ? 0 : 1);
+ for (k=0; k < Ncvec; ++k) {
+ INTERLEAVE2(buff[ib][k*2], buff[ib][k*2+1], buff[ib][k*2], buff[ib][k*2+1]);
+ }
+ }
+ }
+
+ if (buff[ib] != voutput) {
+ /* extra copy required -- this situation should only happen when finput == foutput */
+ assert(finput==foutput);
+ for (k=0; k < Ncvec; ++k) {
+ v4sf a = buff[ib][2*k], b = buff[ib][2*k+1];
+ voutput[2*k] = a; voutput[2*k+1] = b;
+ }
+ ib = !ib;
+ }
+ assert(buff[ib] == voutput);
+
+ VLA_ARRAY_ON_STACK_FREE(scratch_on_stack);
+}
+
+void pffft_zconvolve_accumulate(PFFFT_Setup *s, const float *a, const float *b, float *ab, float scaling) {
+ int Ncvec = s->Ncvec;
+ const v4sf * RESTRICT va = (const v4sf*)a;
+ const v4sf * RESTRICT vb = (const v4sf*)b;
+ v4sf * RESTRICT vab = (v4sf*)ab;
+
+#ifdef __arm__
+ __builtin_prefetch(va);
+ __builtin_prefetch(vb);
+ __builtin_prefetch(vab);
+ __builtin_prefetch(va+2);
+ __builtin_prefetch(vb+2);
+ __builtin_prefetch(vab+2);
+ __builtin_prefetch(va+4);
+ __builtin_prefetch(vb+4);
+ __builtin_prefetch(vab+4);
+ __builtin_prefetch(va+6);
+ __builtin_prefetch(vb+6);
+ __builtin_prefetch(vab+6);
+# ifndef __clang__
+# define ZCONVOLVE_USING_INLINE_NEON_ASM
+# endif
+#endif
+
+ float ar, ai, br, bi, abr, abi;
+#ifndef ZCONVOLVE_USING_INLINE_ASM
+ v4sf vscal = LD_PS1(scaling);
+ int i;
+#endif
+
+ assert(VALIGNED(a) && VALIGNED(b) && VALIGNED(ab));
+ ar = ((v4sf_union*)va)[0].f[0];
+ ai = ((v4sf_union*)va)[1].f[0];
+ br = ((v4sf_union*)vb)[0].f[0];
+ bi = ((v4sf_union*)vb)[1].f[0];
+ abr = ((v4sf_union*)vab)[0].f[0];
+ abi = ((v4sf_union*)vab)[1].f[0];
+
+#ifdef ZCONVOLVE_USING_INLINE_ASM // inline asm version, unfortunately miscompiled by clang 3.2, at least on ubuntu.. so this will be restricted to gcc
+ const float *a_ = a, *b_ = b; float *ab_ = ab;
+ int N = Ncvec;
+ asm volatile("mov r8, %2 \n"
+ "vdup.f32 q15, %4 \n"
+ "1: \n"
+ "pld [%0,#64] \n"
+ "pld [%1,#64] \n"
+ "pld [%2,#64] \n"
+ "pld [%0,#96] \n"
+ "pld [%1,#96] \n"
+ "pld [%2,#96] \n"
+ "vld1.f32 {q0,q1}, [%0,:128]! \n"
+ "vld1.f32 {q4,q5}, [%1,:128]! \n"
+ "vld1.f32 {q2,q3}, [%0,:128]! \n"
+ "vld1.f32 {q6,q7}, [%1,:128]! \n"
+ "vld1.f32 {q8,q9}, [r8,:128]! \n"
+
+ "vmul.f32 q10, q0, q4 \n"
+ "vmul.f32 q11, q0, q5 \n"
+ "vmul.f32 q12, q2, q6 \n"
+ "vmul.f32 q13, q2, q7 \n"
+ "vmls.f32 q10, q1, q5 \n"
+ "vmla.f32 q11, q1, q4 \n"
+ "vld1.f32 {q0,q1}, [r8,:128]! \n"
+ "vmls.f32 q12, q3, q7 \n"
+ "vmla.f32 q13, q3, q6 \n"
+ "vmla.f32 q8, q10, q15 \n"
+ "vmla.f32 q9, q11, q15 \n"
+ "vmla.f32 q0, q12, q15 \n"
+ "vmla.f32 q1, q13, q15 \n"
+ "vst1.f32 {q8,q9},[%2,:128]! \n"
+ "vst1.f32 {q0,q1},[%2,:128]! \n"
+ "subs %3, #2 \n"
+ "bne 1b \n"
+ : "+r"(a_), "+r"(b_), "+r"(ab_), "+r"(N) : "r"(scaling) : "r8", "q0","q1","q2","q3","q4","q5","q6","q7","q8","q9", "q10","q11","q12","q13","q15","memory");
+#else // default routine, works fine for non-arm cpus with current compilers
+ for (i=0; i < Ncvec; i += 2) {
+ v4sf ar, ai, br, bi;
+ ar = va[2*i+0]; ai = va[2*i+1];
+ br = vb[2*i+0]; bi = vb[2*i+1];
+ VCPLXMUL(ar, ai, br, bi);
+ vab[2*i+0] = VMADD(ar, vscal, vab[2*i+0]);
+ vab[2*i+1] = VMADD(ai, vscal, vab[2*i+1]);
+ ar = va[2*i+2]; ai = va[2*i+3];
+ br = vb[2*i+2]; bi = vb[2*i+3];
+ VCPLXMUL(ar, ai, br, bi);
+ vab[2*i+2] = VMADD(ar, vscal, vab[2*i+2]);
+ vab[2*i+3] = VMADD(ai, vscal, vab[2*i+3]);
+ }
+#endif
+ if (s->transform == PFFFT_REAL) {
+ ((v4sf_union*)vab)[0].f[0] = abr + ar*br*scaling;
+ ((v4sf_union*)vab)[1].f[0] = abi + ai*bi*scaling;
+ }
+}
+
+
+#else // defined(PFFFT_SIMD_DISABLE)
+
+// standard routine using scalar floats, without SIMD stuff.
+
+#define pffft_zreorder_nosimd pffft_zreorder
+void pffft_zreorder_nosimd(PFFFT_Setup *setup, const float *in, float *out, pffft_direction_t direction) {
+ int k, N = setup->N;
+ if (setup->transform == PFFFT_COMPLEX) {
+ for (k=0; k < 2*N; ++k) out[k] = in[k];
+ return;
+ }
+ else if (direction == PFFFT_FORWARD) {
+ float x_N = in[N-1];
+ for (k=N-1; k > 1; --k) out[k] = in[k-1];
+ out[0] = in[0];
+ out[1] = x_N;
+ } else {
+ float x_N = in[1];
+ for (k=1; k < N-1; ++k) out[k] = in[k+1];
+ out[0] = in[0];
+ out[N-1] = x_N;
+ }
+}
+
+#define pffft_transform_internal_nosimd pffft_transform_internal
+void pffft_transform_internal_nosimd(PFFFT_Setup *setup, const float *input, float *output, float *scratch,
+ pffft_direction_t direction, int ordered) {
+ int Ncvec = setup->Ncvec;
+ int nf_odd = (setup->ifac[1] & 1);
+
+ // temporary buffer is allocated on the stack if the scratch pointer is NULL
+ int stack_allocate = (scratch == 0 ? Ncvec*2 : 1);
+ VLA_ARRAY_ON_STACK(v4sf, scratch_on_stack, stack_allocate);
+ float *buff[2];
+ int ib;
+ if (scratch == 0) scratch = scratch_on_stack;
+ buff[0] = output; buff[1] = scratch;
+
+ if (setup->transform == PFFFT_COMPLEX) ordered = 0; // it is always ordered.
+ ib = (nf_odd ^ ordered ? 1 : 0);
+
+ if (direction == PFFFT_FORWARD) {
+ if (setup->transform == PFFFT_REAL) {
+ ib = (rfftf1_ps(Ncvec*2, input, buff[ib], buff[!ib],
+ setup->twiddle, &setup->ifac[0]) == buff[0] ? 0 : 1);
+ } else {
+ ib = (cfftf1_ps(Ncvec, input, buff[ib], buff[!ib],
+ setup->twiddle, &setup->ifac[0], -1) == buff[0] ? 0 : 1);
+ }
+ if (ordered) {
+ pffft_zreorder(setup, buff[ib], buff[!ib], PFFFT_FORWARD); ib = !ib;
+ }
+ } else {
+ if (input == buff[ib]) {
+ ib = !ib; // may happen when finput == foutput
+ }
+ if (ordered) {
+ pffft_zreorder(setup, input, buff[!ib], PFFFT_BACKWARD);
+ input = buff[!ib];
+ }
+ if (setup->transform == PFFFT_REAL) {
+ ib = (rfftb1_ps(Ncvec*2, input, buff[ib], buff[!ib],
+ setup->twiddle, &setup->ifac[0]) == buff[0] ? 0 : 1);
+ } else {
+ ib = (cfftf1_ps(Ncvec, input, buff[ib], buff[!ib],
+ setup->twiddle, &setup->ifac[0], +1) == buff[0] ? 0 : 1);
+ }
+ }
+ if (buff[ib] != output) {
+ int k;
+ // extra copy required -- this situation should happens only when finput == foutput
+ assert(input==output);
+ for (k=0; k < Ncvec; ++k) {
+ float a = buff[ib][2*k], b = buff[ib][2*k+1];
+ output[2*k] = a; output[2*k+1] = b;
+ }
+ ib = !ib;
+ }
+ assert(buff[ib] == output);
+
+ VLA_ARRAY_ON_STACK_FREE(scratch_on_stack);
+}
+
+#define pffft_zconvolve_accumulate_nosimd pffft_zconvolve_accumulate
+void pffft_zconvolve_accumulate_nosimd(PFFFT_Setup *s, const float *a, const float *b,
+ float *ab, float scaling) {
+ int i, Ncvec = s->Ncvec;
+
+ if (s->transform == PFFFT_REAL) {
+ // take care of the fftpack ordering
+ ab[0] += a[0]*b[0]*scaling;
+ ab[2*Ncvec-1] += a[2*Ncvec-1]*b[2*Ncvec-1]*scaling;
+ ++ab; ++a; ++b; --Ncvec;
+ }
+ for (i=0; i < Ncvec; ++i) {
+ float ar, ai, br, bi;
+ ar = a[2*i+0]; ai = a[2*i+1];
+ br = b[2*i+0]; bi = b[2*i+1];
+ VCPLXMUL(ar, ai, br, bi);
+ ab[2*i+0] += ar*scaling;
+ ab[2*i+1] += ai*scaling;
+ }
+}
+
+#endif // defined(PFFFT_SIMD_DISABLE)
+
+void pffft_transform(PFFFT_Setup *setup, const float *input, float *output, float *work, pffft_direction_t direction) {
+ pffft_transform_internal(setup, input, output, (v4sf*)work, direction, 0);
+}
+
+void pffft_transform_ordered(PFFFT_Setup *setup, const float *input, float *output, float *work, pffft_direction_t direction) {
+ pffft_transform_internal(setup, input, output, (v4sf*)work, direction, 1);
+}
diff --git a/webrtc/third_party/pffft/src/pffft.h b/webrtc/third_party/pffft/src/pffft.h
new file mode 100644
index 0000000..e235f12
--- /dev/null
+++ b/webrtc/third_party/pffft/src/pffft.h
@@ -0,0 +1,198 @@
+/* Copyright (c) 2013 Julien Pommier ( pommier@modartt.com )
+
+ Based on original fortran 77 code from FFTPACKv4 from NETLIB,
+ authored by Dr Paul Swarztrauber of NCAR, in 1985.
+
+ As confirmed by the NCAR fftpack software curators, the following
+ FFTPACKv5 license applies to FFTPACKv4 sources. My changes are
+ released under the same terms.
+
+ FFTPACK license:
+
+ http://www.cisl.ucar.edu/css/software/fftpack5/ftpk.html
+
+ Copyright (c) 2004 the University Corporation for Atmospheric
+ Research ("UCAR"). All rights reserved. Developed by NCAR's
+ Computational and Information Systems Laboratory, UCAR,
+ www.cisl.ucar.edu.
+
+ Redistribution and use of the Software in source and binary forms,
+ with or without modification, is permitted provided that the
+ following conditions are met:
+
+ - Neither the names of NCAR's Computational and Information Systems
+ Laboratory, the University Corporation for Atmospheric Research,
+ nor the names of its sponsors or contributors may be used to
+ endorse or promote products derived from this Software without
+ specific prior written permission.
+
+ - Redistributions of source code must retain the above copyright
+ notices, this list of conditions, and the disclaimer below.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions, and the disclaimer below in the
+ documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+ SOFTWARE.
+*/
+
+/*
+ PFFFT : a Pretty Fast FFT.
+
+ This is basically an adaptation of the single precision fftpack
+ (v4) as found on netlib taking advantage of SIMD instruction found
+ on cpus such as intel x86 (SSE1), powerpc (Altivec), and arm (NEON).
+
+ For architectures where no SIMD instruction is available, the code
+ falls back to a scalar version.
+
+ Restrictions:
+
+ - 1D transforms only, with 32-bit single precision.
+
+ - supports only transforms for inputs of length N of the form
+ N=(2^a)*(3^b)*(5^c), a >= 5, b >=0, c >= 0 (32, 48, 64, 96, 128,
+ 144, 160, etc are all acceptable lengths). Performance is best for
+ 128<=N<=8192.
+
+ - all (float*) pointers in the functions below are expected to
+ have an "simd-compatible" alignment, that is 16 bytes on x86 and
+ powerpc CPUs.
+
+ You can allocate such buffers with the functions
+ pffft_aligned_malloc / pffft_aligned_free (or with stuff like
+ posix_memalign..)
+
+*/
+
+#ifndef PFFFT_H
+#define PFFFT_H
+
+#include <stddef.h> // for size_t
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef PFFFT_SIMD_DISABLE
+// Detects compiler bugs with respect to simd instruction.
+void validate_pffft_simd();
+#endif
+
+/* opaque struct holding internal stuff (precomputed twiddle factors)
+ this struct can be shared by many threads as it contains only
+ read-only data.
+*/
+typedef struct PFFFT_Setup PFFFT_Setup;
+
+/* direction of the transform */
+typedef enum { PFFFT_FORWARD, PFFFT_BACKWARD } pffft_direction_t;
+
+/* type of transform */
+typedef enum { PFFFT_REAL, PFFFT_COMPLEX } pffft_transform_t;
+
+/*
+ prepare for performing transforms of size N -- the returned
+ PFFFT_Setup structure is read-only so it can safely be shared by
+ multiple concurrent threads.
+*/
+PFFFT_Setup* pffft_new_setup(int N, pffft_transform_t transform);
+void pffft_destroy_setup(PFFFT_Setup*);
+/*
+ Perform a Fourier transform , The z-domain data is stored in the
+ most efficient order for transforming it back, or using it for
+ convolution. If you need to have its content sorted in the
+ "usual" way, that is as an array of interleaved complex numbers,
+ either use pffft_transform_ordered , or call pffft_zreorder after
+ the forward fft, and before the backward fft.
+
+ Transforms are not scaled: PFFFT_BACKWARD(PFFFT_FORWARD(x)) = N*x.
+ Typically you will want to scale the backward transform by 1/N.
+
+ The 'work' pointer should point to an area of N (2*N for complex
+ fft) floats, properly aligned. If 'work' is NULL, then stack will
+ be used instead (this is probably the best strategy for small
+ FFTs, say for N < 16384).
+
+ input and output may alias.
+*/
+void pffft_transform(PFFFT_Setup* setup,
+ const float* input,
+ float* output,
+ float* work,
+ pffft_direction_t direction);
+
+/*
+ Similar to pffft_transform, but makes sure that the output is
+ ordered as expected (interleaved complex numbers). This is
+ similar to calling pffft_transform and then pffft_zreorder.
+
+ input and output may alias.
+*/
+void pffft_transform_ordered(PFFFT_Setup* setup,
+ const float* input,
+ float* output,
+ float* work,
+ pffft_direction_t direction);
+
+/*
+ call pffft_zreorder(.., PFFFT_FORWARD) after pffft_transform(...,
+ PFFFT_FORWARD) if you want to have the frequency components in
+ the correct "canonical" order, as interleaved complex numbers.
+
+ (for real transforms, both 0-frequency and half frequency
+ components, which are real, are assembled in the first entry as
+ F(0)+i*F(n/2+1). Note that the original fftpack did place
+ F(n/2+1) at the end of the arrays).
+
+ input and output should not alias.
+*/
+void pffft_zreorder(PFFFT_Setup* setup,
+ const float* input,
+ float* output,
+ pffft_direction_t direction);
+
+/*
+ Perform a multiplication of the frequency components of dft_a and
+ dft_b and accumulate them into dft_ab. The arrays should have
+ been obtained with pffft_transform(.., PFFFT_FORWARD) and should
+ *not* have been reordered with pffft_zreorder (otherwise just
+ perform the operation yourself as the dft coefs are stored as
+ interleaved complex numbers).
+
+ the operation performed is: dft_ab += (dft_a * fdt_b)*scaling
+
+ The dft_a, dft_b and dft_ab pointers may alias.
+*/
+void pffft_zconvolve_accumulate(PFFFT_Setup* setup,
+ const float* dft_a,
+ const float* dft_b,
+ float* dft_ab,
+ float scaling);
+
+/*
+ the float buffers must have the correct alignment (16-byte boundary
+ on intel and powerpc). This function may be used to obtain such
+ correctly aligned buffers.
+*/
+void* pffft_aligned_malloc(size_t nb_bytes);
+void pffft_aligned_free(void*);
+
+/* return 4 or 1 wether support SSE/Altivec instructions was enable when
+ * building pffft.c */
+int pffft_simd_size();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PFFFT_H
diff --git a/webrtc/third_party/rnnoise/BUILD.gn b/webrtc/third_party/rnnoise/BUILD.gn
new file mode 100644
index 0000000..7bfa784
--- /dev/null
+++ b/webrtc/third_party/rnnoise/BUILD.gn
@@ -0,0 +1 @@
+IyBDb3B5cmlnaHQgMjAxOCBUaGUgQ2hyb21pdW0gQXV0aG9ycy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KIyBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlCiMgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZS4KCmltcG9ydCgiLy90ZXN0aW5nL3Rlc3QuZ25pIikKCmdyb3VwKCJybm5vaXNlIikgewogIGRlcHMgPSBbICI6cm5uX3ZhZCIgXQp9Cgpzb3VyY2Vfc2V0KCJybm5fdmFkIikgewogIHNvdXJjZXMgPSBbCiAgICAic3JjL3Jubl9hY3RpdmF0aW9ucy5oIiwKICAgICJzcmMvcm5uX3ZhZF93ZWlnaHRzLmNjIiwKICAgICJzcmMvcm5uX3ZhZF93ZWlnaHRzLmgiLAogIF0KfQo= \ No newline at end of file
diff --git a/webrtc/third_party/rnnoise/COPYING b/webrtc/third_party/rnnoise/COPYING
new file mode 100644
index 0000000..6e286fd
--- /dev/null
+++ b/webrtc/third_party/rnnoise/COPYING
@@ -0,0 +1 @@
+Q29weXJpZ2h0IChjKSAyMDE3LCBNb3ppbGxhCkNvcHlyaWdodCAoYykgMjAwNy0yMDE3LCBKZWFuLU1hcmMgVmFsaW4KQ29weXJpZ2h0IChjKSAyMDA1LTIwMTcsIFhpcGguT3JnIEZvdW5kYXRpb24KQ29weXJpZ2h0IChjKSAyMDAzLTIwMDQsIE1hcmsgQm9yZ2VyZGluZwoKUmVkaXN0cmlidXRpb24gYW5kIHVzZSBpbiBzb3VyY2UgYW5kIGJpbmFyeSBmb3Jtcywgd2l0aCBvciB3aXRob3V0Cm1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucwphcmUgbWV0OgoKLSBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodApub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgotIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0Cm5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lciBpbiB0aGUKZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4KCi0gTmVpdGhlciB0aGUgbmFtZSBvZiB0aGUgWGlwaC5PcmcgRm91bmRhdGlvbiBub3IgdGhlIG5hbWVzIG9mIGl0cwpjb250cmlidXRvcnMgbWF5IGJlIHVzZWQgdG8gZW5kb3JzZSBvciBwcm9tb3RlIHByb2R1Y3RzIGRlcml2ZWQgZnJvbQp0aGlzIHNvZnR3YXJlIHdpdGhvdXQgc3BlY2lmaWMgcHJpb3Igd3JpdHRlbiBwZXJtaXNzaW9uLgoKVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRSSUJVVE9SUwpgYEFTIElTJycgQU5EIEFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UCkxJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUgpBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUgRElTQ0xBSU1FRC4gIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBGT1VOREFUSU9OCk9SIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLApTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyAoSU5DTFVESU5HLCBCVVQgTk9UCkxJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVM7IExPU1MgT0YgVVNFLApEQVRBLCBPUiBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkKVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUIExJQUJJTElUWSwgT1IgVE9SVAooSU5DTFVESU5HIE5FR0xJR0VOQ0UgT1IgT1RIRVJXSVNFKSBBUklTSU5HIElOIEFOWSBXQVkgT1VUIE9GIFRIRSBVU0UKT0YgVEhJUyBTT0ZUV0FSRSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS4K \ No newline at end of file
diff --git a/webrtc/third_party/rnnoise/meson.build b/webrtc/third_party/rnnoise/meson.build
new file mode 100644
index 0000000..158353f
--- /dev/null
+++ b/webrtc/third_party/rnnoise/meson.build
@@ -0,0 +1,15 @@
+rnnoise_sources = [
+ 'src/rnn_vad_weights.cc',
+]
+
+librnnoise = static_library('librnnoise',
+ rnnoise_sources,
+ dependencies: common_deps,
+ include_directories: webrtc_inc,
+ cpp_args : common_cxxflags
+)
+
+rnnoise_dep = declare_dependency(
+ link_with: librnnoise
+)
+
diff --git a/webrtc/third_party/rnnoise/src/rnn_activations.h b/webrtc/third_party/rnnoise/src/rnn_activations.h
new file mode 100644
index 0000000..af81031
--- /dev/null
+++ b/webrtc/third_party/rnnoise/src/rnn_activations.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+ 2012-2017 Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_
+#define THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_
+
+#include <cmath>
+
+namespace rnnoise {
+
+inline float TansigApproximated(float x) {
+ static constexpr float kTansigTable[201] = {
+ 0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, 0.197375f,
+ 0.235496f, 0.272905f, 0.309507f, 0.345214f, 0.379949f, 0.413644f,
+ 0.446244f, 0.477700f, 0.507977f, 0.537050f, 0.564900f, 0.591519f,
+ 0.616909f, 0.641077f, 0.664037f, 0.685809f, 0.706419f, 0.725897f,
+ 0.744277f, 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
+ 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f,
+ 0.893698f, 0.901468f, 0.908698f, 0.915420f, 0.921669f, 0.927473f,
+ 0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f,
+ 0.957917f, 0.961090f, 0.964028f, 0.966747f, 0.969265f, 0.971594f,
+ 0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
+ 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, 0.989027f,
+ 0.989867f, 0.990642f, 0.991359f, 0.992020f, 0.992631f, 0.993196f,
+ 0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f,
+ 0.996108f, 0.996407f, 0.996682f, 0.996937f, 0.997172f, 0.997389f,
+ 0.997590f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
+ 0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999000f,
+ 0.999076f, 0.999147f, 0.999213f, 0.999273f, 0.999329f, 0.999381f,
+ 0.999428f, 0.999472f, 0.999513f, 0.999550f, 0.999585f, 0.999617f,
+ 0.999646f, 0.999673f, 0.999699f, 0.999722f, 0.999743f, 0.999763f,
+ 0.999781f, 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
+ 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f,
+ 0.999916f, 0.999923f, 0.999929f, 0.999934f, 0.999939f, 0.999944f,
+ 0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f,
+ 0.999968f, 0.999970f, 0.999973f, 0.999975f, 0.999977f, 0.999978f,
+ 0.999980f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
+ 0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f, 0.999992f,
+ 0.999992f, 0.999993f, 0.999994f, 0.999994f, 0.999994f, 0.999995f,
+ 0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f,
+ 0.999997f, 0.999997f, 0.999997f, 0.999998f, 0.999998f, 0.999998f,
+ 0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
+ 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+ 0.999999f, 0.999999f, 0.999999f, 0.999999f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+ 1.000000f, 1.000000f, 1.000000f,
+ };
+
+ // Tests are reversed to catch NaNs.
+ if (!(x < 8.f))
+ return 1.f;
+ if (!(x > -8.f))
+ return -1.f;
+ float sign = 1.f;
+ if (x < 0.f) {
+ x = -x;
+ sign = -1.f;
+ }
+ // Look-up.
+ int i = static_cast<int>(std::floor(0.5f + 25 * x));
+ float y = kTansigTable[i];
+ // Map i back to x's scale (undo 25 factor).
+ x -= 0.04f * i;
+ y = y + x * (1.f - y * y) * (1.f - y * x);
+ return sign * y;
+}
+
+inline float SigmoidApproximated(const float x) {
+ return 0.5f + 0.5f * TansigApproximated(0.5f * x);
+}
+
+inline float RectifiedLinearUnit(const float x) {
+ return x < 0.f ? 0.f : x;
+}
+
+} // namespace rnnoise
+
+#endif // THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_
diff --git a/webrtc/third_party/rnnoise/src/rnn_vad_weights.cc b/webrtc/third_party/rnnoise/src/rnn_vad_weights.cc
new file mode 100644
index 0000000..40c184b
--- /dev/null
+++ b/webrtc/third_party/rnnoise/src/rnn_vad_weights.cc
@@ -0,0 +1,401 @@
+#include "third_party/rnnoise/src/rnn_vad_weights.h"
+
+namespace rnnoise {
+
+const int8_t kInputDenseWeights[kInputLayerWeights] = {
+ -10, 0, -3, 1, -8, -6, 3, -13, 1, 0, -3, -7,
+ -5, -3, 6, -1, -6, 0, -6, -4, -1, -2, 1, 1,
+ -7, 2, 21, 10, -5, -20, 24, 23, 37, 8, -2, 33,
+ -6, 22, 13, -2, 50, 8, 13, 1, -15, 30, -10, 30,
+ 0, 3, 5, 27, 1, 4, -3, 41, 56, 35, -2, 49,
+ -13, 11, 13, -2, -47, 5, -16, -60, -15, 77, -17, 26,
+ -3, 14, -21, 19, -5, -19, -13, 0, 10, 14, 9, 31,
+ -13, -41, -10, 4, 22, 18, -48, -6, -10, 62, -3, -18,
+ -14, 12, 26, -28, 3, 14, 25, -13, -19, 6, 5, 36,
+ -3, -65, -12, 0, 31, -7, -9, 101, -4, 26, 16, 17,
+ -12, -12, 14, -36, -3, 5, -15, 21, 2, 30, -3, 38,
+ -4, 1, -6, 7, -7, 14, 38, -22, -30, -3, -7, 3,
+ -39, -70, -126, 25, 34, 94, -67, -22, -33, 83, -47, -118,
+ 4, 70, 33, 25, 62, -128, -76, -118, -113, 49, -12, -100,
+ -18, -114, -33, 43, 32, 61, 40, -9, -106, 2, 36, -100,
+ -40, -5, 20, -75, 61, -51, -9, 126, -27, -52, 5, -24,
+ -21, -126, -114, -12, 15, 106, -2, 73, -125, 50, 13, -120,
+ 35, 35, 4, -61, 29, -124, 6, -53, -69, -125, 64, -89,
+ 36, -107, -103, -7, 27, 121, 69, 77, -35, 35, 95, -125,
+ -49, 97, -45, -43, -23, 23, -28, -65, -118, 2, 8, -126,
+ 27, -97, 92, 5, 55, 82, 17, -57, -115, 37, 8, -106,
+ -46, 41, -2, 21, -44, 8, -73, -58, -39, 34, 89, -95,
+ 95, -117, 120, -58, 31, 123, 1, -32, -109, -110, 60, -120,
+ -43, -74, 5, 91, 26, 21, 114, 82, -83, -126, 123, 22,
+ -16, -67, 25, -83, 46, 48, -34, -121, -124, -63, -35, -9,
+ 31, 82, 123, 6, -3, 117, 93, -2, -13, -36, 124, -112,
+ -6, -102, -5, -33, -15, 44, -69, -127, -23, -40, -34, -85,
+ 68, 83, -1, 40, 8, 84, 118, -58, -55, -102, 123, -55,
+ -14, -123, 44, -63, -14, 21, 35, 16, 24, -126, -13, -114,
+ 35, 20, -36, 61, -9, 97, 34, 19, -32, -109, 76, -104,
+ 99, -119, 45, -125, -51, -28, -8, -69, -8, 125, -45, -93,
+ 113, 103, -41, -82, 52, 7, 126, 0, -40, 104, 55, -58,
+ 17, -124, -93, -58, 8, -45, 1, 56, -123, 108, -47, -23,
+ 115, 127, 17, -68, -13, 116, -82, -44, 45, 67, -120, -101,
+ -15, -125, 120, -113, 17, -48, -73, 126, -64, -86, -118, -19,
+ 112, -1, -66, -27, -62, 121, -86, -58, 50, 89, -38, -75,
+ 95, -111, 12, -113, 2, -68, 2, -94, -121, 91, -5, 0,
+ 79, 43, -7, -18, 79, 35, -38, 47, 1, -45, 83, -50,
+ 102, 32, 55, -96, 15, -122, -69, 45, -27, 91, -62, -30,
+ 46, -95, 22, -72, -97, -1, 14, -122, 28, 127, 61, -126,
+ 121, 9, 68, -120, 49, -60, 90, 3, 43, 68, 54, 34,
+ -10, 28, 21, -24, -54, 22, -113, -12, 82, -2, -17, -9,
+ 127, 8, 116, -92, 0, -70, -33, 123, 66, 116, -74, -4,
+ 74, -72, -22, -47, 1, -83, -60, -124, 1, 122, -57, -43,
+ 49, 40, -126, -128, -8, -29, 28, -24, -123, -121, -70, -93,
+ -37, -126, 11, -125, -37, 11, -31, -51, -124, 116, -128, 8,
+ -25, 109, 75, -12, 7, 8, 10, 117, 124, -128, -128, 29,
+ -26, 101, 21, -128, 87, 8, -39, 23, -128, 127, -127, 74,
+ -55, 74, 112, 127, 4, 55, 44, -92, 123, 34, -93, 47,
+ -21, -92, 17, 49, -121, 92, 7, -126, -125, 124, -74, 3,
+ -59, 18, -91, 3, -9, 9, 56, 116, 7, -29, 33, 87,
+ -21, -128, -13, 57, 74, 9, -29, -61, -97, -21, -95, -12,
+ -114, 16, 82, 125, -7, 10, -24, 9, 77, -128, -102, -25,
+ 3, -126, 10, 13, -18, 51, 26, 127, -79, 35, 51, 12,
+ -50, -24, 1, -7, 22, 81, 65, 120, -30, -38, 85, 122,
+ -4, -106, -11, 27, 53, 41, 8, -104, -66, -38, -124, 10,
+ 12, 76, 117, -109, 9, 11, 2, -18, 3, 113, -16, -79,
+ -39, -123, -20, -128, 2, 13, -33, -58, 10, 84, -104, 13,
+ 64, 109, 1, 54, -12, 28, 24, 63, -126, 118, -82, 46,
+ -12, -15, 14, -43, 60, 22, -32, -19, -46, 91, -107, 24,
+ -94, 26, -47, 125, 6, 58, -15, -75, -26, -38, -35, 103,
+ -16, -17, -13, 63, -2, 45, -45, -73, -23, 70, -87, 51,
+ -17, 53, 76, 14, -18, -31, -14, 103, 8, 21, -28, -33,
+ -20, -47, 6, 39, 40, -30, 7, -76, 55, 31, -20, -21,
+ -59, 1, 25, -11, 17, 5, -13, -39, 0, -76, 50, -33,
+ -29, -50, -16, -11, -12, -1, -46, 40, -10, 65, -19, 21,
+ -41, -32, -83, -19, -4, 49, -60, 118, -24, -46, 9, 102,
+ -20, 8, -19, 25, 31, -3, -37, 0, 25, 7, 29, 2,
+ -39, 127, -64, -20, 64, 115, -30, 36, 100, 35, 122, 127,
+ 127, -127, 127, -127, 19, 127, -89, -79, -32, 39, -127, 125,
+ -80, 126, -127, 26, 8, 98, -8, -57, -90, -50, 126, 61,
+ 127, -126, 40, -106, -68, 104, -125, -119, 11, 10, -127, 66,
+ -56, -12, -126, -104, 27, 75, 38, -124, -126, -125, 84, -123,
+ -45, -114, -128, 127, 103, -101, -124, 127, -11, -23, -123, 92,
+ -123, 24, 126, 41, -2, -39, -27, -94, 40, -112, -48, 127,
+ 58, 14, 38, -75, -64, 73, 117, 100, -119, -11, 6, 32,
+ -126, -14, 35, 121, -10, 54, -60, 89, -3, 69, -25, -20,
+ 43, -86, -34, 24, 27, 7, -81, -99, -23, -16, -26, 13,
+ 35, -97, 80, -29, -13, -121, -12, -65, -94, 70, -89, -126,
+ -95, 88, 33, 96, 29, -90, 69, 114, -78, 65, 90, -47,
+ -47, 89, 1, -12, 3, 8, 30, 5, 2, -30, -1, 6,
+ -7, 10, -4, 46, -27, -40, 22, -6, -17, 45, 24, -9,
+ 23, -14, -63, -26, -12, -57, 27, 25, 55, -76, -47, 21,
+ 34, 33, 26, 17, 14, 6, 9, 26, 25, -25, -25, -18};
+
+const int8_t kInputDenseBias[kInputLayerOutputSize] = {
+ 38, -6, 127, 127, 127, -43, -127, 78, 127, 5, 127, 123,
+ 127, 127, -128, -76, -126, 28, 127, 125, -30, 127, -89, -20};
+
+const int8_t kHiddenGruWeights[kHiddenLayerWeights] = {
+ -124, 23, -123, -33, -95, -4, 8, -84, 4, 101, -119, 116,
+ -4, 123, 103, -51, 29, -124, -114, -49, 31, 9, 75, -128,
+ 0, -49, 37, -50, 46, -21, -63, -104, 54, 82, 33, 21,
+ 70, 127, -9, -79, -39, -23, -127, 107, 122, -96, -46, -18,
+ -39, 13, -28, -48, 14, 56, -52, 49, -1, -121, 25, -18,
+ -36, -52, -57, -30, 54, -124, -26, -47, 10, 39, 12, 2,
+ 9, -127, -128, 102, 21, 11, -64, -71, 89, -113, -111, 54,
+ 31, 94, 121, -40, 30, 40, -109, 73, -9, 108, -92, 2,
+ -127, 116, 127, 127, -122, 95, 127, -37, -127, 28, 89, 10,
+ 24, -104, -62, -67, -14, 38, 14, -71, 22, -41, 20, -50,
+ 39, 63, 86, 127, -18, 79, 4, -51, 2, 33, 117, -113,
+ -78, 56, -91, 37, 34, -45, -44, -22, 21, -16, 56, 30,
+ -84, -79, 38, -74, 127, 9, -25, 2, 82, 61, 25, -26,
+ 26, 11, 117, -65, 12, -58, 42, -62, -93, 11, 11, 124,
+ -123, 80, -125, 11, -90, 42, 94, 4, -109, -1, 85, -52,
+ 45, -26, -27, 77, -5, 30, 90, 0, 95, -7, 53, 29,
+ -82, 22, -9, 74, 2, -12, -73, 114, 97, -64, 122, -77,
+ 43, 91, 86, 126, 106, 72, 90, -43, 46, 96, -51, 21,
+ 22, 68, 22, 41, 79, 75, -46, -105, 23, -116, 127, -123,
+ 102, 57, 85, 10, -29, 34, 125, 126, 124, 81, -15, 54,
+ 96, -128, 39, -124, 103, 74, 126, 127, -50, -71, -122, -64,
+ 93, -75, 71, 105, 122, 123, 126, 122, -127, 33, -63, -74,
+ 124, -71, 33, 41, -56, 19, 6, 65, 41, 90, -116, -3,
+ -46, 75, -13, 98, -74, -42, 74, -95, -96, 81, 24, 32,
+ -19, -123, 74, 55, 109, 115, 0, 32, 33, 12, -20, 9,
+ 127, 127, -61, 79, -48, -54, -49, 101, -9, 27, -106, 74,
+ 119, 77, 87, -126, -24, 127, 124, 31, 34, 127, 40, 3,
+ -90, 127, 23, 57, -53, 127, -69, -88, -33, 127, 19, -46,
+ -9, -125, 13, -126, -113, 127, -41, 46, 106, -62, 3, -10,
+ 111, 49, -34, -24, -20, -112, 11, 101, -50, -34, 50, 65,
+ -64, -106, 70, -48, 60, 9, -122, -45, 15, -112, -26, -4,
+ 1, 39, 23, 58, -45, -80, 127, 82, 58, 30, -94, -119,
+ 51, -89, 95, -107, 30, 127, 125, 58, -52, -42, -38, -20,
+ -122, 115, 39, -26, 5, 73, 13, -39, 43, -23, -20, -125,
+ 23, 35, 53, -61, -66, 72, -20, 33, 8, 35, 4, 7,
+ 18, 19, 16, -45, -50, -71, 31, -29, -41, -27, 10, 14,
+ 27, 9, -23, 98, 6, -94, 92, 127, -114, 59, -26, -100,
+ -62, -127, -17, -85, -60, 126, -42, -6, 33, -120, -26, -126,
+ -127, -35, -114, -31, 25, -126, -100, -126, -64, -46, -31, 30,
+ 25, -74, -111, -97, -81, -104, -114, -19, -9, -116, -69, 22,
+ 30, 59, 8, -51, 16, -97, 18, -4, -89, 80, -50, 3,
+ 36, -67, 56, 69, -26, 107, -10, 58, -28, -4, -57, -72,
+ -111, 0, -75, -119, 14, -75, -49, -66, -49, 8, -121, 22,
+ -54, 121, 30, 54, -26, -126, -123, 56, 5, 48, 21, -127,
+ -11, 23, 25, -82, 6, -25, 119, 78, 4, -104, 27, 61,
+ -48, 37, -13, -52, 50, -50, 44, -1, -22, -43, -59, -78,
+ -67, -32, -26, 9, -3, 40, 16, 19, 3, -9, 20, -6,
+ -37, 28, 39, 17, -19, -10, 1, 6, -59, 74, 47, 3,
+ -119, 0, -128, -107, -25, -22, -69, -23, -111, -42, -93, -120,
+ 90, -85, -54, -118, 76, -79, 124, 101, -77, -75, -17, -71,
+ -114, 68, 55, 79, -1, -123, -20, 127, -65, -123, -128, -87,
+ 123, 9, -115, -14, 7, -4, 127, -79, -115, 125, -28, 89,
+ -83, 49, 89, 119, -69, -5, 12, -49, 60, 57, -24, -99,
+ -110, 76, -83, 125, 73, 81, 11, 8, -45, 1, 83, 13,
+ -70, -2, 97, 112, -97, 53, -9, -94, 124, 44, -49, -24,
+ 52, 76, -110, -70, -114, -12, 72, -4, -114, 43, -43, 81,
+ 102, -84, -27, 62, -40, 52, 58, 124, -35, -51, -123, -43,
+ 56, -75, -34, -35, -106, 93, -43, 14, -16, 46, 62, -97,
+ 21, 30, -53, 21, -11, -33, -20, -95, 4, -126, 12, 45,
+ 20, 108, 85, 11, 20, -40, 99, 4, -25, -18, -23, -12,
+ -126, -55, -20, -44, -51, 91, -127, 127, -44, 7, 127, 78,
+ 38, 125, -6, -94, -103, 73, 126, -126, 18, 59, -46, 106,
+ 76, 116, -31, 75, -4, 92, 102, 32, -31, 73, 42, -21,
+ -28, 57, 127, -8, -107, 115, 124, -94, -4, -128, 29, -57,
+ 70, -82, 50, -13, -44, 38, 67, -93, 6, -39, -46, 56,
+ 68, 27, 61, 26, 18, -72, 127, 22, 18, -31, 127, 61,
+ -65, -38, 1, -67, -1, 8, -73, 46, -116, -94, 58, -49,
+ 71, -40, -63, -82, -20, -60, 93, 76, 69, -106, 34, -31,
+ 4, -25, 107, -18, 45, 4, -61, 126, 54, -126, -125, 41,
+ 19, 44, 32, -98, 125, -24, 125, -96, -125, 15, 87, -4,
+ -90, 18, -40, 28, -69, 67, 22, 41, 39, 7, -48, -44,
+ 12, 69, -13, 2, 44, -38, 111, -7, -126, -22, -9, 74,
+ -128, -36, -7, -123, -15, -79, -91, -37, -127, -122, 104, 30,
+ 7, 98, -37, 111, -116, -47, 127, -45, 118, -111, -123, -120,
+ -77, -64, -125, 124, 77, 111, 77, 18, -113, 117, -9, 67,
+ -77, 126, 49, -20, -124, 39, 41, -124, -34, 114, -87, -126,
+ 98, -20, 59, -17, -24, 125, 107, 54, 35, 33, -44, 12,
+ -29, 125, -71, -28, -63, -114, 28, -17, 121, -36, 127, 89,
+ -122, -49, -18, -48, 17, 24, 19, -64, -128, 13, 86, 45,
+ 13, -49, 55, 84, 48, 80, -39, 99, -127, 70, -33, 30,
+ 50, 126, -65, -117, -13, -20, -24, 127, 115, -72, -104, 63,
+ 126, -42, 57, 17, 46, 21, 119, 110, -100, -60, -112, 62,
+ -33, 28, 26, -22, -60, -33, -54, 78, 25, 32, -114, 86,
+ 44, 26, 43, 76, 121, 19, 97, -2, -3, -73, -68, 6,
+ -116, 6, -43, -97, 46, -128, -120, -31, -119, -29, 16, 16,
+ -126, -128, -126, -46, -9, -3, 92, -31, -76, -126, -3, -107,
+ -12, -23, -69, 5, 51, 27, -42, 23, -70, -128, -29, 22,
+ 29, -126, -55, 50, -71, -3, 127, 44, -27, -70, -63, -66,
+ -70, 104, 86, 115, 29, -92, 41, -90, 44, -11, -28, 20,
+ -11, -63, -16, 43, 31, 17, -73, -31, -1, -17, -11, -39,
+ 56, 18, 124, 72, -14, 28, 69, -121, -125, 34, 127, 63,
+ 86, -80, -126, -125, -124, -47, 124, 77, 124, -19, 23, -7,
+ -50, 96, -128, -93, 102, -53, -36, -87, 119, -125, 92, -126,
+ 118, 102, 72, -2, 125, 10, 97, 124, -125, 125, 71, -20,
+ -47, -116, -121, -4, -9, -32, 79, -124, -36, 33, -128, -74,
+ 125, 23, 127, -29, -115, -32, 124, -89, 32, -107, 43, -17,
+ 24, 24, 18, 29, -13, -15, -36, 62, -91, 4, -41, 95,
+ 28, -23, 6, 46, 84, 66, 77, 68, -70, -1, -23, -6,
+ 65, 70, -21, 9, 77, -12, 2, -118, 4, 9, -108, 84,
+ 52, 2, 52, 13, -10, 58, -110, 18, 66, -95, -23, 70,
+ 31, -3, 56, 56, -3, -7, 1, -27, -48, -61, 41, -4,
+ 10, -62, 32, -7, -24, 9, -48, -60, -4, 79, -20, -38,
+ -76, 68, -49, -97, 0, -15, 5, -100, -49, -95, -99, -115,
+ -9, -40, 10, 104, 13, 56, 127, -27, -109, -94, -118, -102,
+ -44, -85, 52, 127, -4, 14, 62, 121, -122, -26, -79, -42,
+ -34, 1, 25, -38, -79, -58, -31, -31, -90, -30, -123, 32,
+ -56, 125, 66, 124, -1, 3, 91, -103, -7, 23, 78, -18,
+ 9, 69, -69, 76, -38, -33, -2, -98, 18, 106, 84, 55,
+ 87, -47, 35, -124, 64, 41, -14, 46, 25, -2, 120, -21,
+ 82, 19, -79, -37, -3, -8, -16, 21, 19, -5, -28, -112,
+ 39, -6, -30, 53, -69, 53, 46, 127, 123, 78, 20, 28,
+ -7, 73, 72, 17, -40, 41, 111, 57, 32, -95, 29, 28,
+ -39, -65, 54, -20, -63, 29, -67, 3, 44, -57, -47, 11,
+ 61, -22, -44, 61, 48, -100, 20, 125, 96, -24, -16, 3,
+ -69, -126, 74, -125, 9, 45, -67, -123, -59, -72, 118, 69,
+ 45, 50, -57, 67, 13, -66, -106, 47, 62, 22, -1, -22,
+ -25, -40, -125, 3, 125, 32, 102, -56, -25, -75, -30, 122,
+ 60, -13, 36, -73, 7, -84, 124, 40, -118, 17, -87, -118,
+ -8, 3, -27, 111, -40, 40, -51, 127, 125, -45, -30, -54,
+ 46, 80, -1, -30, 101, -17, 18, 26, 54, 7, -12, 1,
+ -127, 123, -122, -27, -75, 64, 10, 25, -15, -44, 127, -127,
+ 5, -84, -81, -7, 19, -26, 126, 15, 116, -126, 14, -76,
+ 44, 62, -110, -124, 125, -29, -87, -3, -69, 82, 90, 57,
+ -123, 123, 100, -19, -51, -32, 69, 37, -57, -128, -124, -72,
+ -13, 51, -7, -45, -73, 5, 99, -26, -117, -96, -109, 4,
+ -31, -12, 0, 31, -42, -27, 12, -81, 118, 39, 83, 14,
+ 41, -126, 107, -82, 94, -116, -122, -47, -109, -84, -128, -35,
+ -56, 66, 8, -65, 19, 42, -46, -72, -109, 41, 43, -127,
+ -113, 58, 127, 42, -75, -1, 65, 117, -55, -113, -123, 124,
+ 43, -96, -115, -19, 68, 15, 94, 3, 75, 0, 34, 9,
+ 42, 110, -48, 92, -76, 99, -17, 27, 32, 13, 125, 50,
+ -17, 56, 4, 53, 34, -8, 99, 80, -126, -21, -65, -11,
+ -46, 44, -81, -3, -121, 123, 66, -81, -84, 119, 127, 84,
+ 105, 45, -66, -42, -23, 32, -25, 12, 111, 127, 88, 125,
+ 30, 24, -127, -9, -54, 127, -116, -119, 88, 70, 94, -120,
+ 35, -93, 15, 22, -21, 25, -110, -123, -45, 8, -109, 125,
+ -122, -86, -126, 8, -14, -120, -45, -45, 69, -125, -122, 6,
+ 81, 86, 125, 95, 54, 77, 54, -123, 126, -85, -117, 56,
+ 11, 0, -61, -91, -12, -2, -113, -3, -15, -122, -63, -91,
+ 10, 84, -111, 125, 93, 21, 62, -78, -116, 13, -57, 28,
+ -124, 126, 110, 12, 15, 95, 15, -19, -125, -97, 52, -7,
+ 101, 9, 20, -125, -26, -56, 72, 77, 12, -126, 22, -29,
+ 47, 62, 95, 112, 69, 32, 97, -83, -8, -5, 67, -63,
+ -123, 79, 59, 0, -6, -17, 4, -111, -52, 27, 65, 0};
+
+const int8_t kHiddenGruRecurrentWeights[kHiddenLayerWeights] = {
+ 65, 83, 35, 56, 24, -34, -28, -2, 125, 19, 42, -9,
+ 124, -53, 24, -87, 11, 35, -81, -35, -125, -31, 123, -21,
+ 33, -91, 113, -93, 45, -6, 53, 38, -92, 8, -27, 87,
+ 4, 43, 43, 10, -128, -128, -46, 127, -38, -45, 25, -87,
+ 19, 5, 52, -96, -23, -29, 121, -126, -24, -20, -2, 69,
+ -50, 6, 71, -81, -125, 90, -94, 1, -38, 36, 89, 17,
+ -60, 71, -48, 18, -15, 44, -18, 59, 11, 114, -51, 32,
+ 110, 1, 4, 109, -24, 127, 27, 60, 88, 24, 45, -59,
+ 75, -36, 8, 57, -32, -25, 13, 126, -89, -61, -76, 127,
+ 18, -62, -68, 23, -113, 5, 126, 43, -88, 26, -78, 18,
+ 75, 21, 9, -74, 20, 41, 126, -118, -15, 9, 116, 126,
+ -127, 34, -6, 126, -128, -53, -54, -55, -121, 70, 127, -12,
+ -68, 82, -25, 104, -126, 126, -21, -26, 124, -75, -127, -120,
+ 13, 61, -64, -108, -63, -65, -44, -35, -61, -39, 109, -74,
+ 113, -3, 108, -30, 125, 120, 39, 125, -128, -95, -99, 111,
+ 9, 25, 114, -75, -92, -54, -12, -32, -38, 10, 31, 10,
+ 63, 51, 40, -99, 74, 4, 50, -128, -36, -35, -11, -28,
+ -126, -7, 66, -58, -126, -22, -83, -61, -127, 49, 126, -8,
+ 7, 62, 36, -11, -32, -44, 63, 116, 41, 65, -127, 126,
+ 63, -30, -96, 74, -92, 127, 38, -18, -128, 68, -5, 101,
+ -4, 85, 58, 79, 0, -58, 8, 119, -70, -1, -79, -68,
+ 114, -28, -90, -6, -112, 2, 127, -8, 10, 55, -59, -126,
+ 127, 125, 80, 72, 35, -54, 95, -124, -124, 79, 23, -46,
+ -61, -127, -100, 99, -77, 8, -87, 5, -2, 49, 85, 7,
+ -71, 82, 53, -41, 22, -22, -93, -103, 6, 52, -56, 14,
+ -8, -111, 85, 16, 54, 32, -118, -24, 61, -53, 96, -70,
+ -5, -17, -67, -84, -7, -82, -107, -96, 21, -83, -58, 50,
+ 12, -126, -1, -28, 34, -126, 115, 17, 91, 1, -127, 72,
+ 11, 126, -81, 6, 96, -8, 77, 15, -6, 63, -27, 20,
+ -123, -109, 85, -79, -17, 126, -92, 2, -61, 20, 14, 17,
+ 121, 123, 30, 57, 120, 127, 57, 42, 117, 98, 67, 39,
+ -20, -70, 100, 7, 125, 122, 40, 16, -79, 125, 83, 41,
+ -106, -57, 24, 55, 27, -66, -111, -44, -7, -43, -66, 121,
+ 42, -128, -45, 35, 15, -127, 34, -35, -34, -40, -18, -6,
+ 63, 111, 31, 116, 127, 19, 24, -71, -39, 34, 11, 19,
+ -40, 27, 12, 106, -10, 56, -82, -106, -2, -50, -52, 114,
+ -126, -34, -43, -68, 10, 76, 57, -118, -128, 37, -104, 76,
+ 125, 3, -76, 127, -29, 84, -94, -15, 55, 125, 79, 127,
+ -57, -125, 104, -68, 126, 126, -77, 51, 45, 33, -109, 115,
+ -11, 1, 95, -121, -5, -9, -126, -114, 39, 68, -126, -107,
+ -51, -42, 24, -8, 51, -27, -43, 66, -45, 62, -98, -109,
+ 69, 67, 0, -125, -128, 49, 31, 126, -122, 2, -55, -67,
+ -126, -70, -128, -125, -77, 25, 16, -8, -102, 11, -75, 82,
+ 38, -5, 5, 19, 34, 47, -127, -93, 21, 24, -97, -18,
+ 31, 39, 34, -20, 22, 123, 7, -77, -81, -46, -9, 1,
+ 23, 39, -127, -43, -8, -50, 10, -21, 59, -9, -4, -13,
+ -27, 44, 127, 52, -47, 70, -43, 52, 101, -49, 27, 45,
+ 49, 33, -125, 55, 114, 20, -1, 76, -24, -96, 105, 24,
+ 126, 75, -21, -105, 13, -42, 40, 126, -30, -39, -95, 125,
+ -63, 11, 6, 125, 125, -14, 5, 42, -61, -4, 49, 88,
+ 6, -107, -28, 19, -29, 47, 126, 6, -46, -89, -18, 91,
+ -20, -6, 118, -21, -22, 39, 115, 11, -42, 54, 73, -55,
+ -77, 62, -27, -59, -99, -12, -127, -40, 56, -3, -124, -91,
+ 71, -111, 6, -19, 82, -24, -35, 102, -42, 7, -126, -126,
+ -125, 18, 98, -52, 127, 105, -52, 40, -83, 126, -122, 109,
+ 5, 127, 48, 6, 5, -125, 100, -16, 29, 85, -89, 8,
+ 4, 41, 62, -127, 62, 122, 85, 122, -107, 8, -125, 93,
+ -127, 127, 102, 19, 19, -66, 41, -42, 114, 127, -48, -117,
+ -29, -6, -73, -102, -3, -19, 0, 88, 42, 87, -117, -20,
+ 2, 122, 28, 63, 71, 66, 120, 93, 124, -43, 49, 103,
+ 31, 90, -91, -22, -126, 26, -24, -21, 51, -126, 87, -103,
+ -69, -10, -66, -23, 20, 97, 36, 25, -127, 30, -20, -63,
+ 30, 51, -116, 23, 40, -39, 36, -83, -77, -25, -50, 110,
+ 14, 13, -109, 125, -65, -55, -87, 124, -126, -32, -72, -108,
+ 127, 127, -125, -124, 61, 121, 102, -128, -127, 16, 100, 127,
+ -124, -68, 72, -93, -128, 43, -93, -19, -125, -97, -113, -33,
+ 83, 127, -44, 127, -75, 127, 16, 44, 50, -122, 23, 118,
+ 46, 19, 26, -128, 10, 4, 99, -14, -82, -13, 30, 125,
+ 57, 65, 60, -71, 35, 98, 28, 7, 1, 43, 89, 70,
+ 75, 121, -59, 82, -126, -53, -16, -116, -65, 52, -52, 0,
+ 80, 35, 45, -61, 46, 8, 107, 27, -26, -118, 90, 57,
+ -10, 7, -15, 0, -39, -4, 12, 29, -1, 116, 84, 79,
+ 119, 125, -59, 28, -6, -25, -43, 2, 90, 79, 67, 103,
+ -82, 2, -6, 125, 19, 73, 0, -105, 112, -17, 104, 107,
+ 124, 106, 19, 56, -44, 55, -112, 6, -39, -83, 126, -93,
+ -98, 57, -120, -23, -38, 2, -31, -48, 106, 127, 127, 69,
+ 16, 110, 71, 104, 62, -12, -22, 42, -37, -94, 34, -1,
+ -32, -12, -124, -47, -13, 60, -75, -66, 58, -127, -2, 64,
+ 76, -106, 73, -49, -31, 127, 126, 31, 16, 127, -110, 107,
+ -16, -53, 20, 69, -14, -125, 59, -44, 15, 120, 125, 125,
+ 43, 6, 19, -58, 127, 127, 43, 16, 82, 97, -127, 127,
+ -93, -41, 88, 0, 77, -15, 116, 16, -124, -31, -3, 95,
+ -40, -126, -54, -126, -83, -8, -59, 6, 67, -29, 4, 124,
+ -10, 112, -28, -8, 85, -21, 45, 84, 6, -8, 11, 72,
+ 32, 84, -62, 77, 2, -36, 75, 31, -50, 116, 126, 119,
+ -88, -55, -14, -37, 126, 40, -108, -6, -6, 57, 64, -28,
+ -76, 30, -117, -93, 31, -92, -44, -64, 94, 58, 65, 114,
+ 41, 47, 71, 42, -26, 99, -126, 57, -5, 74, -19, -113,
+ -1, 67, -21, 126, 1, -3, 33, 60, -82, 37, -48, 89,
+ 114, -38, 127, -114, 35, 58, -5, 21, -46, 121, -123, -43,
+ 127, 115, 123, 122, -101, 126, 127, 81, 52, 89, -127, 102,
+ 42, 117, -9, -2, 125, 127, 110, 96, 120, 66, 70, 124,
+ 55, 84, -38, -58, 119, -127, -16, -79, 123, 18, -127, -50,
+ -38, 120, -85, 1, 7, -56, 108, -77, -2, 21, 37, 1,
+ 13, -105, -69, 28, -87, 33, -104, -51, 126, 41, 3, -121,
+ 28, 71, 58, 86, -8, 127, 94, -55, 125, 40, -19, 127,
+ -33, -87, -23, 7, -111, -68, 9, 84, -119, 55, -82, 78,
+ -37, -20, -9, -23, 53, -13, 15, -46, 116, 126, -127, 56,
+ -126, 125, -7, -1, 45, 26, 125, 121, 29, 47, -86, 30,
+ 10, 76, -125, -7, 23, 92, -12, -39, -18, 92, -97, -8,
+ -85, -41, 49, -50, 123, -37, -126, -30, 14, 79, -49, -65,
+ 9, -36, -38, -96, 85, -24, -13, 37, -25, -5, -64, -127,
+ 55, -60, -18, -61, -63, 127, 56, 67, 15, 124, 72, 120,
+ 127, 40, -10, 114, 24, -23, 46, 78, -53, 125, 86, 124,
+ 86, 0, 38, 93, 21, 127, 123, 75, -72, 13, 48, 33,
+ 83, -51, 15, -32, -49, -33, 120, 64, 7, 9, 65, 60,
+ 21, -21, -61, -53, -113, 84, -97, 101, 37, -114, -27, 41,
+ 73, 126, -10, 59, 61, -15, 70, -13, 82, -4, 69, 56,
+ 94, -91, -50, 92, -74, -48, 53, -7, -107, 127, 28, 30,
+ -26, -21, -61, 77, 82, 64, -91, -125, 122, -104, 127, 123,
+ 122, 123, 76, -126, 127, -6, -80, 7, 40, -66, -65, 54,
+ -2, 23, 96, -64, 74, 2, -53, -12, -123, 39, 60, -20,
+ 16, -17, -97, 23, -4, -53, -122, 32, -16, -54, -95, 43,
+ 71, -1, -67, -33, 41, 18, 72, 28, -83, 31, -100, -91,
+ -27, 10, -128, -106, 2, 76, -13, 42, 34, 112, -19, 44,
+ 40, -9, -11, 65, 92, -43, -125, 2, 47, -32, 25, 122,
+ -29, 12, 101, -8, -126, -23, 43, 7, 125, -20, -124, 82,
+ -2, 13, -73, -106, 115, 31, 116, -23, -44, -71, 84, 3,
+ 47, 91, 127, 127, -15, 95, 7, 93, 5, 113, -50, 54,
+ 11, 13, -127, 17, 72, 43, -23, 5, -70, 20, 15, -27,
+ 99, 69, -109, -122, -94, 16, 127, 0, 116, 104, 45, 108,
+ -34, 87, 72, -14, 118, 46, 42, 109, -26, 95, 93, 127,
+ 60, 127, -93, -54, -122, 34, -105, 56, 55, 103, 125, -71,
+ -50, 95, -72, 127, 107, 21, 73, 126, 61, 127, 127, 24,
+ -62, 90, 73, 90, -46, -78, -124, 72, 123, -42, 50, -107,
+ 17, -32, -62, -89, 124, 1, 80, -2, 117, 119, -65, -127,
+ -95, -121, -52, 103, 66, 75, -3, -62, -127, 127, -74, 124,
+ 79, 49, 40, 105, -67, -71, -70, 43, 127, 119, -4, 66,
+ 43, 23, 91, -126, 15, 63, -119, 112, 103, 15, -99, 31,
+ -127, 69, 116, -46, -67, 2, -126, -29, 30, 30, -69, -98,
+ -47, -87, -70, -127, 23, -73, 30, -7, 94, -52, -65, 98,
+ -45, 97, 53, 23, -9, -22, -52, -47, 6, -1, -85, -15,
+ -61, -14, 68, 110, -10, -121, -25, -35, -15, -94, -123, 27,
+ 75, 48, -66, -56, -44, 93, 109, 67, -36, 24, 70, -126,
+ 8, -127, 126, 52, 11, -32, 120, -13, -26, -28, -125, 127,
+ 106, -50, 124, 36, -126, -12, 0, -23, 76, -71, -126, -12,
+ -17, -82, 12, 124, 57, 33, 4, 77, -46, 71, -34, 72,
+ 125, -128, 124, -24, -128, 75, -120, 69, -45, 55, 33, 127,
+ -33, 4, -105, -41, -59, -91, 123, 44, -127, 127, -67, 52,
+ 25, -125, -65, 100, -25, 123, 6, 11, -123, -92, -33, 126,
+ -17, -4, 29, 33, 127, 96, 3, 87, -48, -18, -70, 123,
+ 58, -127, -3, -52, -1, -36, -41, 127, 51, -52, -27, 46,
+ -83, 57, 9, 126, 127, 94, 79, -37, -127, -40, 67, 52,
+ 82, -66, 122, -13, -73, 127, -8, -80, 46, -48, 4, -54};
+
+const int8_t kHiddenGruBias[kHiddenLayerBiases] = {
+ 124, 125, -57, -126, 53, 123, 127, -75, 68, 102, -2, 116,
+ 124, 127, 124, 125, 126, 123, -16, 48, 125, 126, 78, 85,
+ 11, 126, -30, -30, -64, -3, -105, -29, -17, 69, 63, 2,
+ -32, -10, -62, 113, -52, 112, -109, 112, 7, -40, 73, 53,
+ 62, 6, -2, 0, 0, 100, -16, 26, -24, 56, 26, -10,
+ -33, 41, 70, 109, -29, 127, 34, -66, 49, 53, 27, 62};
+
+const int8_t kOutputDenseWeights[kOutputLayerWeights] = {
+ 127, 127, 127, 127, 127, 20, 127, -126, -126, -54, 14, 125,
+ -126, -126, 127, -125, -126, 127, -127, -127, -57, -30, 127, 80};
+
+const int8_t kOutputDenseBias[kOutputLayerOutputSize] = {-50};
+
+} // namespace rnnoise
diff --git a/webrtc/third_party/rnnoise/src/rnn_vad_weights.h b/webrtc/third_party/rnnoise/src/rnn_vad_weights.h
new file mode 100644
index 0000000..d55e33d
--- /dev/null
+++ b/webrtc/third_party/rnnoise/src/rnn_vad_weights.h
@@ -0,0 +1,37 @@
+#ifndef THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_
+#define THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_
+
+#include <cstdint>
+#include <cstring>
+
+namespace rnnoise {
+
+// Weights scaling factor.
+const float kWeightsScale = 1.f / 256.f;
+
+// Input layer (dense).
+const size_t kInputLayerInputSize = 42;
+const size_t kInputLayerOutputSize = 24;
+const size_t kInputLayerWeights = kInputLayerInputSize * kInputLayerOutputSize;
+extern const int8_t kInputDenseWeights[kInputLayerWeights];
+extern const int8_t kInputDenseBias[kInputLayerOutputSize];
+
+// Hidden layer (GRU).
+const size_t kHiddenLayerOutputSize = 24;
+const size_t kHiddenLayerWeights =
+ 3 * kInputLayerOutputSize * kHiddenLayerOutputSize;
+const size_t kHiddenLayerBiases = 3 * kHiddenLayerOutputSize;
+extern const int8_t kHiddenGruWeights[kHiddenLayerWeights];
+extern const int8_t kHiddenGruRecurrentWeights[kHiddenLayerWeights];
+extern const int8_t kHiddenGruBias[kHiddenLayerBiases];
+
+// Output layer (dense).
+const size_t kOutputLayerOutputSize = 1;
+const size_t kOutputLayerWeights =
+ kHiddenLayerOutputSize * kOutputLayerOutputSize;
+extern const int8_t kOutputDenseWeights[kOutputLayerWeights];
+extern const int8_t kOutputDenseBias[kOutputLayerOutputSize];
+
+} // namespace rnnoise
+
+#endif // THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_
diff --git a/webrtc/typedefs.h b/webrtc/typedefs.h
deleted file mode 100644
index d875490..0000000
--- a/webrtc/typedefs.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// This file contains platform-specific typedefs and defines.
-// Much of it is derived from Chromium's build/build_config.h.
-
-#ifndef WEBRTC_TYPEDEFS_H_
-#define WEBRTC_TYPEDEFS_H_
-
-// Processor architecture detection. For more info on what's defined, see:
-// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
-// http://www.agner.org/optimize/calling_conventions.pdf
-// or with gcc, run: "echo | gcc -E -dM -"
-#if defined(_M_X64) || defined(__x86_64__)
-#define WEBRTC_ARCH_X86_FAMILY
-#define WEBRTC_ARCH_X86_64
-#define WEBRTC_ARCH_64_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(__aarch64__)
-#define WEBRTC_ARCH_64_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(_M_IX86) || defined(__i386__)
-#define WEBRTC_ARCH_X86_FAMILY
-#define WEBRTC_ARCH_X86
-#define WEBRTC_ARCH_32_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(__ARMEL__)
-// TODO(ajm): We'd prefer to control platform defines here, but this is
-// currently provided by the Android makefiles. Commented to avoid duplicate
-// definition warnings.
-//#define WEBRTC_ARCH_ARM
-// TODO(ajm): Chromium uses the following two defines. Should we switch?
-//#define WEBRTC_ARCH_ARM_FAMILY
-//#define WEBRTC_ARCH_ARMEL
-#define WEBRTC_ARCH_32_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(__MIPSEL__)
-#define WEBRTC_ARCH_32_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#elif defined(__pnacl__)
-#define WEBRTC_ARCH_32_BITS
-#define WEBRTC_ARCH_LITTLE_ENDIAN
-#else
-#error Please add support for your architecture in typedefs.h
-#endif
-
-#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
-#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
-#endif
-
-// TODO(zhongwei.yao): WEBRTC_CPU_DETECTION is only used in one place; we should
-// probably just remove it.
-#if (defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__)) || \
- defined(WEBRTC_DETECT_NEON)
-#define WEBRTC_CPU_DETECTION
-#endif
-
-// TODO(pbos): Use webrtc/base/basictypes.h instead to include fixed-size ints.
-#include <stdint.h>
-
-// Annotate a function indicating the caller must examine the return value.
-// Use like:
-// int foo() WARN_UNUSED_RESULT;
-// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
-// libjingle are merged.
-#if !defined(WARN_UNUSED_RESULT)
-#if defined(__GNUC__)
-#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
-#else
-#define WARN_UNUSED_RESULT
-#endif
-#endif // WARN_UNUSED_RESULT
-
-// Put after a variable that might not be used, to prevent compiler warnings:
-// int result ATTRIBUTE_UNUSED = DoSomething();
-// assert(result == 17);
-#ifndef ATTRIBUTE_UNUSED
-#if defined(__GNUC__) || defined(__clang__)
-#define ATTRIBUTE_UNUSED __attribute__((unused))
-#else
-#define ATTRIBUTE_UNUSED
-#endif
-#endif
-
-// Macro to be used for switch-case fallthrough (required for enabling
-// -Wimplicit-fallthrough warning on Clang).
-#ifndef FALLTHROUGH
-#if defined(__clang__)
-#define FALLTHROUGH() [[clang::fallthrough]]
-#else
-#define FALLTHROUGH() do { } while (0)
-#endif
-#endif
-
-// Annotate a function that will not return control flow to the caller.
-#if defined(_MSC_VER)
-#define NO_RETURN __declspec(noreturn)
-#elif defined(__GNUC__)
-#define NO_RETURN __attribute__((noreturn))
-#else
-#define NO_RETURN
-#endif
-
-#endif // WEBRTC_TYPEDEFS_H_