diff --git a/modules/audio_processing/audio_buffer.cc b/modules/audio_processing/audio_buffer.cc index 5ac4f94d30..4b0ca20d82 100644 --- a/modules/audio_processing/audio_buffer.cc +++ b/modules/audio_processing/audio_buffer.cc @@ -25,8 +25,7 @@ namespace { constexpr size_t kSamplesPer32kHzChannel = 320; constexpr size_t kSamplesPer48kHzChannel = 480; -constexpr size_t kSamplesPer192kHzChannel = 1920; -constexpr size_t kMaxSamplesPerChannel = kSamplesPer192kHzChannel; +constexpr size_t kMaxSamplesPerChannel = AudioBuffer::kMaxSampleRate / 100; size_t NumBandsFromFramesPerChannel(size_t num_frames) { if (num_frames == kSamplesPer32kHzChannel) { @@ -123,7 +122,7 @@ void AudioBuffer::CopyFrom(const float* const* data, const bool resampling_needed = input_num_frames_ != buffer_num_frames_; if (downmix_needed) { - RTC_DCHECK_GT(kMaxSamplesPerChannel, input_num_frames_); + RTC_DCHECK_GE(kMaxSamplesPerChannel, input_num_frames_); std::array downmix; if (downmix_by_averaging_) { diff --git a/modules/audio_processing/audio_buffer.h b/modules/audio_processing/audio_buffer.h index 2d136d8aa6..7bab26d4c9 100644 --- a/modules/audio_processing/audio_buffer.h +++ b/modules/audio_processing/audio_buffer.h @@ -33,6 +33,7 @@ enum Band { kBand0To8kHz = 0, kBand8To16kHz = 1, kBand16To24kHz = 2 }; class AudioBuffer { public: 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, diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc index 2556f67d4e..9c30ab088b 100644 --- a/modules/audio_processing/audio_processing_unittest.cc +++ b/modules/audio_processing/audio_processing_unittest.cc @@ -2257,6 +2257,128 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple(16000, 16000, 16000, 16000, 0, 0))); #endif +// Produces a scoped trace debug output. +std::string ProduceDebugText(int render_input_sample_rate_hz, + int render_output_sample_rate_hz, + int capture_input_sample_rate_hz, + int capture_output_sample_rate_hz, + size_t render_input_num_channels, + size_t render_output_num_channels, + size_t capture_input_num_channels, + size_t capture_output_num_channels) { + rtc::StringBuilder ss; + ss << "Sample rates:" + << "\n" + << " Render input: " << render_input_sample_rate_hz << " Hz" + << "\n" + << " Render output: " << render_output_sample_rate_hz << " Hz" + << "\n" + << " Capture input: " << capture_input_sample_rate_hz << " Hz" + << "\n" + << " Capture output: " << capture_output_sample_rate_hz << " Hz" + << "\n" + << "Number of channels:" + << "\n" + << " Render input: " << render_input_num_channels << "\n" + << " Render output: " << render_output_num_channels << "\n" + << " Capture input: " << capture_input_num_channels << "\n" + << " Capture output: " << capture_output_num_channels; + return ss.Release(); +} + +// Validates that running the audio processing module using various combinations +// of sample rates and number of channels works as intended. +void RunApmRateAndChannelTest( + rtc::ArrayView sample_rates_hz, + rtc::ArrayView render_channel_counts, + rtc::ArrayView capture_channel_counts) { + std::unique_ptr apm(AudioProcessingBuilder().Create()); + webrtc::AudioProcessing::Config apm_config; + apm_config.echo_canceller.enabled = true; + apm->ApplyConfig(apm_config); + + StreamConfig render_input_stream_config; + StreamConfig render_output_stream_config; + StreamConfig capture_input_stream_config; + StreamConfig capture_output_stream_config; + + std::vector render_input_frame_channels; + std::vector render_input_frame; + std::vector render_output_frame_channels; + std::vector render_output_frame; + std::vector capture_input_frame_channels; + std::vector capture_input_frame; + std::vector capture_output_frame_channels; + std::vector capture_output_frame; + + for (auto render_input_sample_rate_hz : sample_rates_hz) { + for (auto render_output_sample_rate_hz : sample_rates_hz) { + for (auto capture_input_sample_rate_hz : sample_rates_hz) { + for (auto capture_output_sample_rate_hz : sample_rates_hz) { + for (size_t render_input_num_channels : render_channel_counts) { + for (size_t capture_input_num_channels : capture_channel_counts) { + size_t render_output_num_channels = render_input_num_channels; + size_t capture_output_num_channels = capture_input_num_channels; + auto populate_audio_frame = [](int sample_rate_hz, + size_t num_channels, + StreamConfig* cfg, + std::vector* channels_data, + std::vector* frame_data) { + cfg->set_sample_rate_hz(sample_rate_hz); + cfg->set_num_channels(num_channels); + cfg->set_has_keyboard(false); + + size_t max_frame_size = ceil(sample_rate_hz / 100.f); + channels_data->resize(num_channels * max_frame_size); + std::fill(channels_data->begin(), channels_data->end(), 0.5f); + frame_data->resize(num_channels); + for (size_t channel = 0; channel < num_channels; ++channel) { + (*frame_data)[channel] = + &(*channels_data)[channel * max_frame_size]; + } + }; + + populate_audio_frame( + render_input_sample_rate_hz, render_input_num_channels, + &render_input_stream_config, &render_input_frame_channels, + &render_input_frame); + populate_audio_frame( + render_output_sample_rate_hz, render_output_num_channels, + &render_output_stream_config, &render_output_frame_channels, + &render_output_frame); + populate_audio_frame( + capture_input_sample_rate_hz, capture_input_num_channels, + &capture_input_stream_config, &capture_input_frame_channels, + &capture_input_frame); + populate_audio_frame( + capture_output_sample_rate_hz, capture_output_num_channels, + &capture_output_stream_config, &capture_output_frame_channels, + &capture_output_frame); + + for (size_t frame = 0; frame < 2; ++frame) { + SCOPED_TRACE(ProduceDebugText( + render_input_sample_rate_hz, render_output_sample_rate_hz, + capture_input_sample_rate_hz, capture_output_sample_rate_hz, + render_input_num_channels, render_output_num_channels, + render_input_num_channels, capture_output_num_channels)); + + int result = apm->ProcessReverseStream( + &render_input_frame[0], render_input_stream_config, + render_output_stream_config, &render_output_frame[0]); + EXPECT_EQ(result, AudioProcessing::kNoError); + result = apm->ProcessStream( + &capture_input_frame[0], capture_input_stream_config, + capture_output_stream_config, &capture_output_frame[0]); + EXPECT_EQ(result, AudioProcessing::kNoError); + } + } + } + } + } + } + } +} + } // namespace TEST(RuntimeSettingTest, TestDefaultCtor) { @@ -2622,4 +2744,30 @@ TEST(ApmStatistics, ReportHasVoice) { EXPECT_EQ(apm->ProcessStream(&frame), 0); EXPECT_FALSE(apm->GetStatistics(false).voice_detected); } + +TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) { + std::array sample_rates_hz = {16000, 32000, 48000}; + std::array render_channel_counts = {1, 7}; + std::array capture_channel_counts = {1, 7}; + RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts, + capture_channel_counts); +} + +TEST(ApmConfiguration, HandlingOfChannelCombinations) { + std::array sample_rates_hz = {48000}; + std::array render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8}; + std::array capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8}; + RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts, + capture_channel_counts); +} + +TEST(ApmConfiguration, HandlingOfRateCombinations) { + std::array sample_rates_hz = {8000, 11025, 16000, 22050, 32000, + 48000, 96000, 192000, 384000}; + std::array render_channel_counts = {2}; + std::array capture_channel_counts = {2}; + RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts, + capture_channel_counts); +} + } // namespace webrtc