OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2016 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 <string.h> | |
12 | |
13 #include <memory> | |
14 #include <utility> | |
15 | |
16 #include "webrtc/base/bind.h" | |
17 #include "webrtc/base/thread.h" | |
18 #include "webrtc/modules/audio_mixer/audio_mixer_impl.h" | |
19 #include "webrtc/modules/audio_mixer/audio_mixer.h" | |
20 #include "webrtc/test/gmock.h" | |
21 | |
22 using testing::_; | |
23 using testing::Exactly; | |
24 using testing::Invoke; | |
25 using testing::Return; | |
26 | |
27 namespace webrtc { | |
28 | |
29 namespace { | |
30 | |
31 constexpr int kDefaultSampleRateHz = 48000; | |
32 constexpr int kId = 1; | |
33 | |
34 // Utility function that resets the frame member variables with | |
35 // sensible defaults. | |
36 void ResetFrame(AudioFrame* frame) { | |
37 frame->id_ = kId; | |
38 frame->sample_rate_hz_ = kDefaultSampleRateHz; | |
39 frame->num_channels_ = 1; | |
40 | |
41 // Frame duration 10ms. | |
42 frame->samples_per_channel_ = kDefaultSampleRateHz / 100; | |
43 frame->vad_activity_ = AudioFrame::kVadActive; | |
44 frame->speech_type_ = AudioFrame::kNormalSpeech; | |
45 } | |
46 | |
47 AudioFrame frame_for_mixing; | |
48 | |
49 } // namespace | |
50 | |
51 class MockMixerAudioSource : public AudioMixer::Source { | |
52 public: | |
53 MockMixerAudioSource() | |
54 : fake_audio_frame_info_(AudioMixer::Source::AudioFrameInfo::kNormal) { | |
55 ON_CALL(*this, GetAudioFrameWithInfo(_)) | |
56 .WillByDefault( | |
57 Invoke(this, &MockMixerAudioSource::FakeAudioFrameWithInfo)); | |
58 } | |
59 | |
60 MOCK_METHOD1(GetAudioFrameWithInfo, AudioFrameWithInfo(int sample_rate_hz)); | |
61 | |
62 AudioFrame* fake_frame() { return &fake_frame_; } | |
63 AudioFrameInfo fake_info() { return fake_audio_frame_info_; } | |
64 void set_fake_info(const AudioFrameInfo audio_frame_info) { | |
65 fake_audio_frame_info_ = audio_frame_info; | |
66 } | |
67 | |
68 private: | |
69 AudioFrame fake_frame_, fake_output_frame_; | |
70 AudioFrameInfo fake_audio_frame_info_; | |
71 AudioFrameWithInfo FakeAudioFrameWithInfo(int sample_rate_hz) { | |
72 fake_output_frame_.CopyFrom(fake_frame_); | |
73 return { | |
74 &fake_output_frame_, // audio_frame_pointer | |
75 fake_info(), // audio_frame_info | |
76 }; | |
77 } | |
78 }; | |
79 | |
80 // Creates participants from |frames| and |frame_info| and adds them | |
81 // to the mixer. Compares mixed status with |expected_status| | |
82 void MixAndCompare( | |
83 const std::vector<AudioFrame>& frames, | |
84 const std::vector<AudioMixer::Source::AudioFrameInfo>& frame_info, | |
85 const std::vector<bool>& expected_status) { | |
86 int num_audio_sources = frames.size(); | |
87 RTC_DCHECK(frames.size() == frame_info.size()); | |
88 RTC_DCHECK(frame_info.size() == expected_status.size()); | |
89 | |
90 const std::unique_ptr<AudioMixerImpl> mixer(AudioMixerImpl::Create()); | |
91 std::vector<MockMixerAudioSource> participants(num_audio_sources); | |
92 | |
93 for (int i = 0; i < num_audio_sources; i++) { | |
94 participants[i].fake_frame()->CopyFrom(frames[i]); | |
95 participants[i].set_fake_info(frame_info[i]); | |
96 } | |
97 | |
98 for (int i = 0; i < num_audio_sources; i++) { | |
99 EXPECT_EQ(0, mixer->SetMixabilityStatus(&participants[i], true)); | |
100 EXPECT_CALL(participants[i], GetAudioFrameWithInfo(kDefaultSampleRateHz)) | |
101 .Times(Exactly(1)); | |
102 } | |
103 | |
104 mixer->Mix(kDefaultSampleRateHz, 1, &frame_for_mixing); | |
105 | |
106 for (int i = 0; i < num_audio_sources; i++) { | |
107 EXPECT_EQ(expected_status[i], | |
108 mixer->GetAudioSourceMixabilityStatusForTest(&participants[i])) | |
109 << "Mixed status of AudioSource #" << i << " wrong."; | |
110 } | |
111 } | |
112 | |
113 TEST(AudioMixer, LargestEnergyVadActiveMixed) { | |
114 constexpr int kAudioSources = | |
115 AudioMixer::kMaximumAmountOfMixedAudioSources + 3; | |
116 | |
117 const std::unique_ptr<AudioMixerImpl> mixer(AudioMixerImpl::Create()); | |
118 | |
119 MockMixerAudioSource participants[kAudioSources]; | |
120 | |
121 for (int i = 0; i < kAudioSources; ++i) { | |
122 ResetFrame(participants[i].fake_frame()); | |
123 | |
124 // We set the 80-th sample value since the first 80 samples may be | |
125 // modified by a ramped-in window. | |
126 participants[i].fake_frame()->data_[80] = i; | |
127 | |
128 EXPECT_EQ(0, mixer->SetMixabilityStatus(&participants[i], true)); | |
129 EXPECT_CALL(participants[i], GetAudioFrameWithInfo(_)).Times(Exactly(1)); | |
130 } | |
131 | |
132 // Last participant gives audio frame with passive VAD, although it has the | |
133 // largest energy. | |
134 participants[kAudioSources - 1].fake_frame()->vad_activity_ = | |
135 AudioFrame::kVadPassive; | |
136 | |
137 AudioFrame audio_frame; | |
138 mixer->Mix(kDefaultSampleRateHz, | |
139 1, // number of channels | |
140 &audio_frame); | |
141 | |
142 for (int i = 0; i < kAudioSources; ++i) { | |
143 bool is_mixed = | |
144 mixer->GetAudioSourceMixabilityStatusForTest(&participants[i]); | |
145 if (i == kAudioSources - 1 || | |
146 i < kAudioSources - 1 - AudioMixer::kMaximumAmountOfMixedAudioSources) { | |
147 EXPECT_FALSE(is_mixed) << "Mixing status of AudioSource #" << i | |
148 << " wrong."; | |
149 } else { | |
150 EXPECT_TRUE(is_mixed) << "Mixing status of AudioSource #" << i | |
151 << " wrong."; | |
152 } | |
153 } | |
154 } | |
155 | |
156 TEST(AudioMixer, FrameNotModifiedForSingleParticipant) { | |
157 const std::unique_ptr<AudioMixer> mixer(AudioMixer::Create()); | |
158 | |
159 MockMixerAudioSource participant; | |
160 | |
161 ResetFrame(participant.fake_frame()); | |
162 const int n_samples = participant.fake_frame()->samples_per_channel_; | |
163 | |
164 // Modify the frame so that it's not zero. | |
165 for (int j = 0; j < n_samples; j++) { | |
166 participant.fake_frame()->data_[j] = j; | |
167 } | |
168 | |
169 EXPECT_EQ(0, mixer->SetMixabilityStatus(&participant, true)); | |
170 EXPECT_CALL(participant, GetAudioFrameWithInfo(_)).Times(Exactly(2)); | |
171 | |
172 AudioFrame audio_frame; | |
173 // Two mix iteration to compare after the ramp-up step. | |
174 for (int i = 0; i < 2; i++) { | |
175 mixer->Mix(kDefaultSampleRateHz, | |
176 1, // number of channels | |
177 &audio_frame); | |
178 } | |
179 | |
180 EXPECT_EQ( | |
181 0, memcmp(participant.fake_frame()->data_, audio_frame.data_, n_samples)); | |
182 } | |
183 | |
184 TEST(AudioMixer, ParticipantSampleRate) { | |
185 const std::unique_ptr<AudioMixer> mixer(AudioMixer::Create()); | |
186 | |
187 MockMixerAudioSource participant; | |
188 ResetFrame(participant.fake_frame()); | |
189 | |
190 EXPECT_EQ(0, mixer->SetMixabilityStatus(&participant, true)); | |
191 for (auto frequency : {8000, 16000, 32000, 48000}) { | |
192 EXPECT_CALL(participant, GetAudioFrameWithInfo(frequency)) | |
193 .Times(Exactly(1)); | |
194 participant.fake_frame()->sample_rate_hz_ = frequency; | |
195 participant.fake_frame()->samples_per_channel_ = frequency / 100; | |
196 mixer->Mix(frequency, 1, &frame_for_mixing); | |
197 EXPECT_EQ(frequency, frame_for_mixing.sample_rate_hz_); | |
198 } | |
199 } | |
200 | |
201 TEST(AudioMixer, ParticipantNumberOfChannels) { | |
202 const std::unique_ptr<AudioMixer> mixer(AudioMixer::Create()); | |
203 | |
204 MockMixerAudioSource participant; | |
205 ResetFrame(participant.fake_frame()); | |
206 | |
207 EXPECT_EQ(0, mixer->SetMixabilityStatus(&participant, true)); | |
208 for (size_t number_of_channels : {1, 2}) { | |
209 EXPECT_CALL(participant, GetAudioFrameWithInfo(kDefaultSampleRateHz)) | |
210 .Times(Exactly(1)); | |
211 mixer->Mix(kDefaultSampleRateHz, number_of_channels, &frame_for_mixing); | |
212 EXPECT_EQ(number_of_channels, frame_for_mixing.num_channels_); | |
213 } | |
214 } | |
215 | |
216 // Maximal amount of participants are mixed one iteration, then | |
217 // another participant with higher energy is added. | |
218 TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) { | |
219 constexpr int kAudioSources = | |
220 AudioMixer::kMaximumAmountOfMixedAudioSources + 1; | |
221 | |
222 const std::unique_ptr<AudioMixerImpl> mixer(AudioMixerImpl::Create()); | |
223 MockMixerAudioSource participants[kAudioSources]; | |
224 | |
225 for (int i = 0; i < kAudioSources; i++) { | |
226 ResetFrame(participants[i].fake_frame()); | |
227 // Set the participant audio energy to increase with the index | |
228 // |i|. | |
229 participants[i].fake_frame()->data_[0] = 100 * i; | |
230 } | |
231 | |
232 // Add all participants but the loudest for mixing. | |
233 for (int i = 0; i < kAudioSources - 1; i++) { | |
234 EXPECT_EQ(0, mixer->SetMixabilityStatus(&participants[i], true)); | |
235 EXPECT_CALL(participants[i], GetAudioFrameWithInfo(kDefaultSampleRateHz)) | |
236 .Times(Exactly(1)); | |
237 } | |
238 | |
239 // First mixer iteration | |
240 mixer->Mix(kDefaultSampleRateHz, 1, &frame_for_mixing); | |
241 | |
242 // All participants but the loudest should have been mixed. | |
243 for (int i = 0; i < kAudioSources - 1; i++) { | |
244 EXPECT_TRUE(mixer->GetAudioSourceMixabilityStatusForTest(&participants[i])) | |
245 << "Mixed status of AudioSource #" << i << " wrong."; | |
246 } | |
247 | |
248 // Add new participant with higher energy. | |
249 EXPECT_EQ(0, | |
250 mixer->SetMixabilityStatus(&participants[kAudioSources - 1], true)); | |
251 for (int i = 0; i < kAudioSources; i++) { | |
252 EXPECT_CALL(participants[i], GetAudioFrameWithInfo(kDefaultSampleRateHz)) | |
253 .Times(Exactly(1)); | |
254 } | |
255 | |
256 mixer->Mix(kDefaultSampleRateHz, 1, &frame_for_mixing); | |
257 | |
258 // The most quiet participant should not have been mixed. | |
259 EXPECT_FALSE(mixer->GetAudioSourceMixabilityStatusForTest(&participants[0])) | |
260 << "Mixed status of AudioSource #0 wrong."; | |
261 | |
262 // The loudest participants should have been mixed. | |
263 for (int i = 1; i < kAudioSources; i++) { | |
264 EXPECT_EQ(true, | |
265 mixer->GetAudioSourceMixabilityStatusForTest(&participants[i])) | |
266 << "Mixed status of AudioSource #" << i << " wrong."; | |
267 } | |
268 } | |
269 | |
270 // This test checks that the initialization and participant addition | |
271 // can be done on a different thread. | |
272 TEST(AudioMixer, ConstructFromOtherThread) { | |
273 std::unique_ptr<rtc::Thread> init_thread = rtc::Thread::Create(); | |
274 std::unique_ptr<rtc::Thread> participant_thread = rtc::Thread::Create(); | |
275 init_thread->Start(); | |
276 std::unique_ptr<AudioMixer> mixer( | |
277 init_thread->Invoke<std::unique_ptr<AudioMixer>>( | |
278 RTC_FROM_HERE, &AudioMixer::Create)); | |
279 MockMixerAudioSource participant; | |
280 | |
281 ResetFrame(participant.fake_frame()); | |
282 | |
283 participant_thread->Start(); | |
284 EXPECT_EQ(0, participant_thread->Invoke<int>( | |
285 RTC_FROM_HERE, rtc::Bind(&AudioMixer::SetMixabilityStatus, | |
286 mixer.get(), &participant, true))); | |
287 | |
288 EXPECT_CALL(participant, GetAudioFrameWithInfo(kDefaultSampleRateHz)) | |
289 .Times(Exactly(1)); | |
290 | |
291 // Do one mixer iteration | |
292 mixer->Mix(kDefaultSampleRateHz, 1, &frame_for_mixing); | |
293 } | |
294 | |
295 TEST(AudioMixer, MutedShouldMixAfterUnmuted) { | |
296 constexpr int kAudioSources = | |
297 AudioMixer::kMaximumAmountOfMixedAudioSources + 1; | |
298 | |
299 std::vector<AudioFrame> frames(kAudioSources); | |
300 for (auto& frame : frames) { | |
301 ResetFrame(&frame); | |
302 } | |
303 | |
304 std::vector<AudioMixer::Source::AudioFrameInfo> frame_info( | |
305 kAudioSources, AudioMixer::Source::AudioFrameInfo::kNormal); | |
306 frame_info[0] = AudioMixer::Source::AudioFrameInfo::kMuted; | |
307 std::vector<bool> expected_status(kAudioSources, true); | |
308 expected_status[0] = false; | |
309 | |
310 MixAndCompare(frames, frame_info, expected_status); | |
311 } | |
312 | |
313 TEST(AudioMixer, PassiveShouldMixAfterNormal) { | |
314 constexpr int kAudioSources = | |
315 AudioMixer::kMaximumAmountOfMixedAudioSources + 1; | |
316 | |
317 std::vector<AudioFrame> frames(kAudioSources); | |
318 for (auto& frame : frames) { | |
319 ResetFrame(&frame); | |
320 } | |
321 | |
322 std::vector<AudioMixer::Source::AudioFrameInfo> frame_info( | |
323 kAudioSources, AudioMixer::Source::AudioFrameInfo::kNormal); | |
324 frames[0].vad_activity_ = AudioFrame::kVadPassive; | |
325 std::vector<bool> expected_status(kAudioSources, true); | |
326 expected_status[0] = false; | |
327 | |
328 MixAndCompare(frames, frame_info, expected_status); | |
329 } | |
330 | |
331 TEST(AudioMixer, ActiveShouldMixBeforeLoud) { | |
332 constexpr int kAudioSources = | |
333 AudioMixer::kMaximumAmountOfMixedAudioSources + 1; | |
334 | |
335 std::vector<AudioFrame> frames(kAudioSources); | |
336 for (auto& frame : frames) { | |
337 ResetFrame(&frame); | |
338 } | |
339 | |
340 std::vector<AudioMixer::Source::AudioFrameInfo> frame_info( | |
341 kAudioSources, AudioMixer::Source::AudioFrameInfo::kNormal); | |
342 frames[0].vad_activity_ = AudioFrame::kVadPassive; | |
343 std::fill(frames[0].data_, frames[0].data_ + kDefaultSampleRateHz / 100, | |
344 std::numeric_limits<int16_t>::max()); | |
345 std::vector<bool> expected_status(kAudioSources, true); | |
346 expected_status[0] = false; | |
347 | |
348 MixAndCompare(frames, frame_info, expected_status); | |
349 } | |
350 | |
351 TEST(AudioMixer, UnmutedShouldMixBeforeLoud) { | |
352 constexpr int kAudioSources = | |
353 AudioMixer::kMaximumAmountOfMixedAudioSources + 1; | |
354 | |
355 std::vector<AudioFrame> frames(kAudioSources); | |
356 for (auto& frame : frames) { | |
357 ResetFrame(&frame); | |
358 } | |
359 | |
360 std::vector<AudioMixer::Source::AudioFrameInfo> frame_info( | |
361 kAudioSources, AudioMixer::Source::AudioFrameInfo::kNormal); | |
362 frame_info[0] = AudioMixer::Source::AudioFrameInfo::kMuted; | |
363 std::fill(frames[0].data_, frames[0].data_ + kDefaultSampleRateHz / 100, | |
364 std::numeric_limits<int16_t>::max()); | |
365 std::vector<bool> expected_status(kAudioSources, true); | |
366 expected_status[0] = false; | |
367 | |
368 MixAndCompare(frames, frame_info, expected_status); | |
369 } | |
370 } // namespace webrtc | |
OLD | NEW |