xref: /aosp_15_r20/external/webrtc/audio/audio_state_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "audio/audio_state.h"
12 
13 #include <memory>
14 #include <utility>
15 #include <vector>
16 
17 #include "api/task_queue/test/mock_task_queue_base.h"
18 #include "call/test/mock_audio_send_stream.h"
19 #include "modules/audio_device/include/mock_audio_device.h"
20 #include "modules/audio_mixer/audio_mixer_impl.h"
21 #include "modules/audio_processing/include/mock_audio_processing.h"
22 #include "test/gtest.h"
23 
24 namespace webrtc {
25 namespace test {
26 namespace {
27 
28 using ::testing::_;
29 using ::testing::Matcher;
30 using ::testing::NiceMock;
31 using ::testing::StrictMock;
32 using ::testing::Values;
33 
34 constexpr int kSampleRate = 16000;
35 constexpr int kNumberOfChannels = 1;
36 
37 struct FakeAsyncAudioProcessingHelper {
38   class FakeTaskQueue : public StrictMock<MockTaskQueueBase> {
39    public:
40     FakeTaskQueue() = default;
41 
Delete()42     void Delete() override { delete this; }
PostTask(absl::AnyInvocable<void ()&&> task)43     void PostTask(absl::AnyInvocable<void() &&> task) override {
44       std::move(task)();
45     }
46   };
47 
48   class FakeTaskQueueFactory : public TaskQueueFactory {
49    public:
50     FakeTaskQueueFactory() = default;
51     ~FakeTaskQueueFactory() override = default;
CreateTaskQueue(absl::string_view name,Priority priority) const52     std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
53         absl::string_view name,
54         Priority priority) const override {
55       return std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter>(
56           new FakeTaskQueue());
57     }
58   };
59 
60   class MockAudioFrameProcessor : public AudioFrameProcessor {
61    public:
62     ~MockAudioFrameProcessor() override = default;
63 
64     MOCK_METHOD(void, ProcessCalled, ());
65     MOCK_METHOD(void, SinkSet, ());
66     MOCK_METHOD(void, SinkCleared, ());
67 
Process(std::unique_ptr<AudioFrame> frame)68     void Process(std::unique_ptr<AudioFrame> frame) override {
69       ProcessCalled();
70       sink_callback_(std::move(frame));
71     }
72 
SetSink(OnAudioFrameCallback sink_callback)73     void SetSink(OnAudioFrameCallback sink_callback) override {
74       sink_callback_ = std::move(sink_callback);
75       if (sink_callback_ == nullptr)
76         SinkCleared();
77       else
78         SinkSet();
79     }
80 
81    private:
82     OnAudioFrameCallback sink_callback_;
83   };
84 
85   NiceMock<MockAudioFrameProcessor> audio_frame_processor_;
86   FakeTaskQueueFactory task_queue_factory_;
87 
CreateFactorywebrtc::test::__anon7c853fc30111::FakeAsyncAudioProcessingHelper88   rtc::scoped_refptr<AsyncAudioProcessing::Factory> CreateFactory() {
89     return rtc::make_ref_counted<AsyncAudioProcessing::Factory>(
90         audio_frame_processor_, task_queue_factory_);
91   }
92 };
93 
94 struct ConfigHelper {
95   struct Params {
96     bool use_null_audio_processing;
97     bool use_async_audio_processing;
98   };
99 
ConfigHelperwebrtc::test::__anon7c853fc30111::ConfigHelper100   explicit ConfigHelper(const Params& params)
101       : audio_mixer(AudioMixerImpl::Create()) {
102     audio_state_config.audio_mixer = audio_mixer;
103     audio_state_config.audio_processing =
104         params.use_null_audio_processing
105             ? nullptr
106             : rtc::make_ref_counted<testing::NiceMock<MockAudioProcessing>>();
107     audio_state_config.audio_device_module =
108         rtc::make_ref_counted<NiceMock<MockAudioDeviceModule>>();
109     if (params.use_async_audio_processing) {
110       audio_state_config.async_audio_processing_factory =
111           async_audio_processing_helper_.CreateFactory();
112     }
113   }
configwebrtc::test::__anon7c853fc30111::ConfigHelper114   AudioState::Config& config() { return audio_state_config; }
mixerwebrtc::test::__anon7c853fc30111::ConfigHelper115   rtc::scoped_refptr<AudioMixer> mixer() { return audio_mixer; }
116   NiceMock<FakeAsyncAudioProcessingHelper::MockAudioFrameProcessor>&
mock_audio_frame_processorwebrtc::test::__anon7c853fc30111::ConfigHelper117   mock_audio_frame_processor() {
118     return async_audio_processing_helper_.audio_frame_processor_;
119   }
120 
121  private:
122   AudioState::Config audio_state_config;
123   rtc::scoped_refptr<AudioMixer> audio_mixer;
124   FakeAsyncAudioProcessingHelper async_audio_processing_helper_;
125 };
126 
127 class FakeAudioSource : public AudioMixer::Source {
128  public:
129   // TODO(aleloi): Valid overrides commented out, because the gmock
130   // methods don't use any override declarations, and we want to avoid
131   // warnings from -Winconsistent-missing-override. See
132   // http://crbug.com/428099.
Ssrc() const133   int Ssrc() const /*override*/ { return 0; }
134 
PreferredSampleRate() const135   int PreferredSampleRate() const /*override*/ { return kSampleRate; }
136 
137   MOCK_METHOD(AudioFrameInfo,
138               GetAudioFrameWithInfo,
139               (int sample_rate_hz, AudioFrame*),
140               (override));
141 };
142 
Create10msTestData(int sample_rate_hz,size_t num_channels)143 std::vector<int16_t> Create10msTestData(int sample_rate_hz,
144                                         size_t num_channels) {
145   const int samples_per_channel = sample_rate_hz / 100;
146   std::vector<int16_t> audio_data(samples_per_channel * num_channels, 0);
147   // Fill the first channel with a 1kHz sine wave.
148   const float inc = (2 * 3.14159265f * 1000) / sample_rate_hz;
149   float w = 0.f;
150   for (int i = 0; i < samples_per_channel; ++i) {
151     audio_data[i * num_channels] = static_cast<int16_t>(32767.f * std::sin(w));
152     w += inc;
153   }
154   return audio_data;
155 }
156 
ComputeChannelLevels(AudioFrame * audio_frame)157 std::vector<uint32_t> ComputeChannelLevels(AudioFrame* audio_frame) {
158   const size_t num_channels = audio_frame->num_channels_;
159   const size_t samples_per_channel = audio_frame->samples_per_channel_;
160   std::vector<uint32_t> levels(num_channels, 0);
161   for (size_t i = 0; i < samples_per_channel; ++i) {
162     for (size_t j = 0; j < num_channels; ++j) {
163       levels[j] += std::abs(audio_frame->data()[i * num_channels + j]);
164     }
165   }
166   return levels;
167 }
168 }  // namespace
169 
170 class AudioStateTest : public ::testing::TestWithParam<ConfigHelper::Params> {};
171 
TEST_P(AudioStateTest,Create)172 TEST_P(AudioStateTest, Create) {
173   ConfigHelper helper(GetParam());
174   auto audio_state = AudioState::Create(helper.config());
175   EXPECT_TRUE(audio_state.get());
176 }
177 
TEST_P(AudioStateTest,ConstructDestruct)178 TEST_P(AudioStateTest, ConstructDestruct) {
179   ConfigHelper helper(GetParam());
180   rtc::scoped_refptr<internal::AudioState> audio_state(
181       rtc::make_ref_counted<internal::AudioState>(helper.config()));
182 }
183 
TEST_P(AudioStateTest,RecordedAudioArrivesAtSingleStream)184 TEST_P(AudioStateTest, RecordedAudioArrivesAtSingleStream) {
185   ConfigHelper helper(GetParam());
186 
187   if (GetParam().use_async_audio_processing) {
188     EXPECT_CALL(helper.mock_audio_frame_processor(), SinkSet);
189     EXPECT_CALL(helper.mock_audio_frame_processor(), ProcessCalled);
190     EXPECT_CALL(helper.mock_audio_frame_processor(), SinkCleared);
191   }
192 
193   rtc::scoped_refptr<internal::AudioState> audio_state(
194       rtc::make_ref_counted<internal::AudioState>(helper.config()));
195 
196   MockAudioSendStream stream;
197   audio_state->AddSendingStream(&stream, 8000, 2);
198 
199   EXPECT_CALL(
200       stream,
201       SendAudioDataForMock(::testing::AllOf(
202           ::testing::Field(&AudioFrame::sample_rate_hz_, ::testing::Eq(8000)),
203           ::testing::Field(&AudioFrame::num_channels_, ::testing::Eq(2u)))))
204       .WillOnce(
205           // Verify that channels are not swapped by default.
206           ::testing::Invoke([](AudioFrame* audio_frame) {
207             auto levels = ComputeChannelLevels(audio_frame);
208             EXPECT_LT(0u, levels[0]);
209             EXPECT_EQ(0u, levels[1]);
210           }));
211   MockAudioProcessing* ap =
212       GetParam().use_null_audio_processing
213           ? nullptr
214           : static_cast<MockAudioProcessing*>(audio_state->audio_processing());
215   if (ap) {
216     EXPECT_CALL(*ap, set_stream_delay_ms(0));
217     EXPECT_CALL(*ap, set_stream_key_pressed(false));
218     EXPECT_CALL(*ap, ProcessStream(_, _, _, Matcher<int16_t*>(_)));
219   }
220 
221   constexpr int kSampleRate = 16000;
222   constexpr size_t kNumChannels = 2;
223   auto audio_data = Create10msTestData(kSampleRate, kNumChannels);
224   uint32_t new_mic_level = 667;
225   audio_state->audio_transport()->RecordedDataIsAvailable(
226       &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels,
227       kSampleRate, 0, 0, 0, false, new_mic_level);
228   EXPECT_EQ(667u, new_mic_level);
229 
230   audio_state->RemoveSendingStream(&stream);
231 }
232 
TEST_P(AudioStateTest,RecordedAudioArrivesAtMultipleStreams)233 TEST_P(AudioStateTest, RecordedAudioArrivesAtMultipleStreams) {
234   ConfigHelper helper(GetParam());
235 
236   if (GetParam().use_async_audio_processing) {
237     EXPECT_CALL(helper.mock_audio_frame_processor(), SinkSet);
238     EXPECT_CALL(helper.mock_audio_frame_processor(), ProcessCalled);
239     EXPECT_CALL(helper.mock_audio_frame_processor(), SinkCleared);
240   }
241 
242   rtc::scoped_refptr<internal::AudioState> audio_state(
243       rtc::make_ref_counted<internal::AudioState>(helper.config()));
244 
245   MockAudioSendStream stream_1;
246   MockAudioSendStream stream_2;
247   audio_state->AddSendingStream(&stream_1, 8001, 2);
248   audio_state->AddSendingStream(&stream_2, 32000, 1);
249 
250   EXPECT_CALL(
251       stream_1,
252       SendAudioDataForMock(::testing::AllOf(
253           ::testing::Field(&AudioFrame::sample_rate_hz_, ::testing::Eq(16000)),
254           ::testing::Field(&AudioFrame::num_channels_, ::testing::Eq(1u)))))
255       .WillOnce(
256           // Verify that there is output signal.
257           ::testing::Invoke([](AudioFrame* audio_frame) {
258             auto levels = ComputeChannelLevels(audio_frame);
259             EXPECT_LT(0u, levels[0]);
260           }));
261   EXPECT_CALL(
262       stream_2,
263       SendAudioDataForMock(::testing::AllOf(
264           ::testing::Field(&AudioFrame::sample_rate_hz_, ::testing::Eq(16000)),
265           ::testing::Field(&AudioFrame::num_channels_, ::testing::Eq(1u)))))
266       .WillOnce(
267           // Verify that there is output signal.
268           ::testing::Invoke([](AudioFrame* audio_frame) {
269             auto levels = ComputeChannelLevels(audio_frame);
270             EXPECT_LT(0u, levels[0]);
271           }));
272   MockAudioProcessing* ap =
273       static_cast<MockAudioProcessing*>(audio_state->audio_processing());
274   if (ap) {
275     EXPECT_CALL(*ap, set_stream_delay_ms(5));
276     EXPECT_CALL(*ap, set_stream_key_pressed(true));
277     EXPECT_CALL(*ap, ProcessStream(_, _, _, Matcher<int16_t*>(_)));
278   }
279 
280   constexpr int kSampleRate = 16000;
281   constexpr size_t kNumChannels = 1;
282   auto audio_data = Create10msTestData(kSampleRate, kNumChannels);
283   uint32_t new_mic_level = 667;
284   audio_state->audio_transport()->RecordedDataIsAvailable(
285       &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels,
286       kSampleRate, 5, 0, 0, true, new_mic_level);
287   EXPECT_EQ(667u, new_mic_level);
288 
289   audio_state->RemoveSendingStream(&stream_1);
290   audio_state->RemoveSendingStream(&stream_2);
291 }
292 
TEST_P(AudioStateTest,EnableChannelSwap)293 TEST_P(AudioStateTest, EnableChannelSwap) {
294   constexpr int kSampleRate = 16000;
295   constexpr size_t kNumChannels = 2;
296 
297   ConfigHelper helper(GetParam());
298 
299   if (GetParam().use_async_audio_processing) {
300     EXPECT_CALL(helper.mock_audio_frame_processor(), SinkSet);
301     EXPECT_CALL(helper.mock_audio_frame_processor(), ProcessCalled);
302     EXPECT_CALL(helper.mock_audio_frame_processor(), SinkCleared);
303   }
304 
305   rtc::scoped_refptr<internal::AudioState> audio_state(
306       rtc::make_ref_counted<internal::AudioState>(helper.config()));
307 
308   audio_state->SetStereoChannelSwapping(true);
309 
310   MockAudioSendStream stream;
311   audio_state->AddSendingStream(&stream, kSampleRate, kNumChannels);
312 
313   EXPECT_CALL(stream, SendAudioDataForMock(_))
314       .WillOnce(
315           // Verify that channels are swapped.
316           ::testing::Invoke([](AudioFrame* audio_frame) {
317             auto levels = ComputeChannelLevels(audio_frame);
318             EXPECT_EQ(0u, levels[0]);
319             EXPECT_LT(0u, levels[1]);
320           }));
321 
322   auto audio_data = Create10msTestData(kSampleRate, kNumChannels);
323   uint32_t new_mic_level = 667;
324   audio_state->audio_transport()->RecordedDataIsAvailable(
325       &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels,
326       kSampleRate, 0, 0, 0, false, new_mic_level);
327   EXPECT_EQ(667u, new_mic_level);
328 
329   audio_state->RemoveSendingStream(&stream);
330 }
331 
TEST_P(AudioStateTest,QueryingTransportForAudioShouldResultInGetAudioCallOnMixerSource)332 TEST_P(AudioStateTest,
333        QueryingTransportForAudioShouldResultInGetAudioCallOnMixerSource) {
334   ConfigHelper helper(GetParam());
335   auto audio_state = AudioState::Create(helper.config());
336 
337   FakeAudioSource fake_source;
338   helper.mixer()->AddSource(&fake_source);
339 
340   EXPECT_CALL(fake_source, GetAudioFrameWithInfo(_, _))
341       .WillOnce(
342           ::testing::Invoke([](int sample_rate_hz, AudioFrame* audio_frame) {
343             audio_frame->sample_rate_hz_ = sample_rate_hz;
344             audio_frame->samples_per_channel_ = sample_rate_hz / 100;
345             audio_frame->num_channels_ = kNumberOfChannels;
346             return AudioMixer::Source::AudioFrameInfo::kNormal;
347           }));
348 
349   int16_t audio_buffer[kSampleRate / 100 * kNumberOfChannels];
350   size_t n_samples_out;
351   int64_t elapsed_time_ms;
352   int64_t ntp_time_ms;
353   audio_state->audio_transport()->NeedMorePlayData(
354       kSampleRate / 100, kNumberOfChannels * 2, kNumberOfChannels, kSampleRate,
355       audio_buffer, n_samples_out, &elapsed_time_ms, &ntp_time_ms);
356 }
357 
358 INSTANTIATE_TEST_SUITE_P(AudioStateTest,
359                          AudioStateTest,
360                          Values(ConfigHelper::Params({false, false}),
361                                 ConfigHelper::Params({true, false}),
362                                 ConfigHelper::Params({false, true}),
363                                 ConfigHelper::Params({true, true})));
364 
365 }  // namespace test
366 }  // namespace webrtc
367