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