Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | |
|
tommi
2016/07/06 19:42:17
update this header (it's 2016)
aleloi
2016/07/07 09:20:16
Done. I also updated the other files (they are cop
| |
| 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 <memory> | |
| 12 | |
| 13 #include "testing/gmock/include/gmock/gmock.h" | |
| 14 | |
| 15 #include "webrtc/modules/audio_conference_mixer/source/audio_frame_manipulator.h " | |
| 16 #include "webrtc/modules/audio_mixer/audio_mixer.h" | |
| 17 #include "webrtc/modules/audio_mixer/include/new_audio_conference_mixer.h" | |
| 18 #include "webrtc/modules/audio_mixer/include/audio_mixer_defines.h" | |
|
tommi
2016/07/06 19:42:17
fix include order. git cl format could help.
aleloi
2016/07/07 09:20:16
Done.
| |
| 19 #include "webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.h" | |
| 20 | |
| 21 namespace webrtc { | |
|
ivoc
2016/07/07 13:46:16
Move this below the "using" lines below.
aleloi
2016/07/07 14:29:12
Done.
| |
| 22 | |
| 23 using testing::_; | |
| 24 using testing::AtLeast; | |
| 25 using testing::Invoke; | |
| 26 using testing::Return; | |
| 27 | |
| 28 using voe::AudioMixer; | |
| 29 | |
| 30 class MockMixerAudioSource : public MixerAudioSource { | |
| 31 public: | |
| 32 MockMixerAudioSource() { | |
| 33 ON_CALL(*this, GetAudioFrame(_, _)) | |
| 34 .WillByDefault(Invoke(this, &MockMixerAudioSource::FakeAudioFrame)); | |
| 35 } | |
| 36 MOCK_METHOD2(GetAudioFrame, | |
| 37 int32_t(const int32_t id, AudioFrame* audio_frame)); | |
| 38 MOCK_CONST_METHOD1(NeededFrequency, int32_t(const int32_t id)); | |
| 39 AudioFrame* fake_frame() { return &fake_frame_; } | |
| 40 | |
| 41 private: | |
| 42 AudioFrame fake_frame_; | |
| 43 int32_t FakeAudioFrame(const int32_t id, AudioFrame* audio_frame) { | |
| 44 audio_frame->CopyFrom(fake_frame_); | |
| 45 return 0; | |
| 46 } | |
| 47 }; | |
| 48 | |
| 49 class BothMixersTest : public testing::Test { | |
| 50 protected: | |
| 51 BothMixersTest() { | |
| 52 // Create an OutputMixer. | |
| 53 AudioMixer::Create(audio_mixer_, kId); | |
| 54 | |
| 55 // Create one mixer participant and add it to the mixer. | |
| 56 EXPECT_EQ(0, audio_mixer_->SetMixabilityStatus(participant_, true)); | |
| 57 | |
| 58 // Each iteration, the participant will return a frame with this content: | |
| 59 participant_.fake_frame()->id_ = 1; | |
| 60 participant_.fake_frame()->sample_rate_hz_ = kSampleRateHz; | |
| 61 participant_.fake_frame()->speech_type_ = AudioFrame::kNormalSpeech; | |
| 62 participant_.fake_frame()->vad_activity_ = AudioFrame::kVadActive; | |
| 63 participant_.fake_frame()->num_channels_ = 1; | |
| 64 | |
| 65 // We modify one sample within the RampIn window and one sample | |
| 66 // outside of it. | |
| 67 participant_.fake_frame()->data_[10] = 100; | |
| 68 participant_.fake_frame()->data_[20] = -200; | |
| 69 participant_.fake_frame()->data_[30] = 300; | |
| 70 participant_.fake_frame()->data_[90] = -400; | |
| 71 | |
| 72 // Frame duration 10ms. | |
| 73 participant_.fake_frame()->samples_per_channel_ = kSampleRateHz / 100; | |
| 74 EXPECT_CALL(participant_, NeededFrequency(_)) | |
| 75 .WillRepeatedly(Return(kSampleRateHz)); | |
| 76 } | |
| 77 | |
| 78 ~BothMixersTest() { AudioMixer::Destroy(audio_mixer_); } | |
| 79 | |
| 80 // Mark the participant as 'unmixed' last round. | |
| 81 void ResetParticipant() { participant_._mixHistory->SetIsMixed(false); } | |
| 82 | |
| 83 AudioMixer* audio_mixer_; | |
| 84 MockMixerAudioSource participant_; | |
| 85 AudioFrame mixing_round_frame, mixed_results_frame_; | |
| 86 | |
| 87 constexpr static int kSampleRateHz = 48000; | |
| 88 constexpr static int kId = 1; | |
| 89 }; | |
| 90 | |
| 91 TEST(AudioMixer, AnonymousAndNamed) { | |
| 92 const int kId = 1; | |
|
tommi
2016/07/06 19:42:17
nit: make this 'static const int kId'. For non st
aleloi
2016/07/07 09:20:16
Done. The test was mostly copied from modules/audi
| |
| 93 // Should not matter even if partipants are more than | |
| 94 // kMaximumAmountOfMixedParticipants. | |
| 95 const int kNamed = | |
| 96 NewAudioConferenceMixer::kMaximumAmountOfMixedParticipants + 1; | |
| 97 const int kAnonymous = | |
| 98 NewAudioConferenceMixer::kMaximumAmountOfMixedParticipants + 1; | |
| 99 | |
| 100 std::unique_ptr<NewAudioConferenceMixer> mixer( | |
| 101 NewAudioConferenceMixer::Create(kId)); | |
| 102 | |
| 103 MockMixerAudioSource named[kNamed]; | |
| 104 MockMixerAudioSource anonymous[kAnonymous]; | |
| 105 | |
| 106 for (int i = 0; i < kNamed; ++i) { | |
| 107 EXPECT_EQ(0, mixer->SetMixabilityStatus(&named[i], true)); | |
| 108 EXPECT_TRUE(mixer->MixabilityStatus(named[i])); | |
| 109 } | |
| 110 | |
| 111 for (int i = 0; i < kAnonymous; ++i) { | |
| 112 // Participant must be registered before turning it into anonymous. | |
| 113 EXPECT_EQ(-1, mixer->SetAnonymousMixabilityStatus(&anonymous[i], true)); | |
| 114 EXPECT_EQ(0, mixer->SetMixabilityStatus(&anonymous[i], true)); | |
| 115 EXPECT_TRUE(mixer->MixabilityStatus(anonymous[i])); | |
| 116 EXPECT_FALSE(mixer->AnonymousMixabilityStatus(anonymous[i])); | |
| 117 | |
| 118 EXPECT_EQ(0, mixer->SetAnonymousMixabilityStatus(&anonymous[i], true)); | |
| 119 EXPECT_TRUE(mixer->AnonymousMixabilityStatus(anonymous[i])); | |
| 120 | |
| 121 // Anonymous participants do not show status by MixabilityStatus. | |
| 122 EXPECT_FALSE(mixer->MixabilityStatus(anonymous[i])); | |
| 123 } | |
| 124 | |
| 125 for (int i = 0; i < kNamed; ++i) { | |
| 126 EXPECT_EQ(0, mixer->SetMixabilityStatus(&named[i], false)); | |
| 127 EXPECT_FALSE(mixer->MixabilityStatus(named[i])); | |
| 128 } | |
| 129 | |
| 130 for (int i = 0; i < kAnonymous - 1; i++) { | |
| 131 EXPECT_EQ(0, mixer->SetAnonymousMixabilityStatus(&anonymous[i], false)); | |
| 132 EXPECT_FALSE(mixer->AnonymousMixabilityStatus(anonymous[i])); | |
| 133 | |
| 134 // SetAnonymousMixabilityStatus(anonymous, false) moves anonymous to the | |
| 135 // named group. | |
| 136 EXPECT_TRUE(mixer->MixabilityStatus(anonymous[i])); | |
| 137 } | |
| 138 | |
| 139 // SetMixabilityStatus(anonymous, false) will remove anonymous from both | |
| 140 // anonymous and named groups. | |
| 141 EXPECT_EQ(0, mixer->SetMixabilityStatus(&anonymous[kAnonymous - 1], false)); | |
| 142 EXPECT_FALSE(mixer->AnonymousMixabilityStatus(anonymous[kAnonymous - 1])); | |
| 143 EXPECT_FALSE(mixer->MixabilityStatus(anonymous[kAnonymous - 1])); | |
| 144 } | |
| 145 | |
| 146 TEST(AudioMixer, LargestEnergyVadActiveMixed) { | |
| 147 const int kId = 1; | |
| 148 const int kParticipants = | |
| 149 NewAudioConferenceMixer::kMaximumAmountOfMixedParticipants + 3; | |
| 150 const int kSampleRateHz = 32000; | |
| 151 | |
| 152 std::unique_ptr<NewAudioConferenceMixer> mixer( | |
| 153 NewAudioConferenceMixer::Create(kId)); | |
| 154 | |
| 155 MockMixerAudioSource participants[kParticipants]; | |
| 156 | |
| 157 for (int i = 0; i < kParticipants; ++i) { | |
| 158 participants[i].fake_frame()->id_ = i; | |
| 159 participants[i].fake_frame()->sample_rate_hz_ = kSampleRateHz; | |
| 160 participants[i].fake_frame()->speech_type_ = AudioFrame::kNormalSpeech; | |
| 161 participants[i].fake_frame()->vad_activity_ = AudioFrame::kVadActive; | |
| 162 participants[i].fake_frame()->num_channels_ = 1; | |
| 163 | |
| 164 // Frame duration 10ms. | |
| 165 participants[i].fake_frame()->samples_per_channel_ = kSampleRateHz / 100; | |
| 166 | |
| 167 // We set the 80-th sample value since the first 80 samples may be | |
| 168 // modified by a ramped-in window. | |
| 169 participants[i].fake_frame()->data_[80] = i; | |
| 170 | |
| 171 EXPECT_EQ(0, mixer->SetMixabilityStatus(&participants[i], true)); | |
| 172 EXPECT_CALL(participants[i], GetAudioFrame(_, _)).Times(AtLeast(1)); | |
| 173 EXPECT_CALL(participants[i], NeededFrequency(_)) | |
| 174 .WillRepeatedly(Return(kSampleRateHz)); | |
| 175 } | |
| 176 | |
| 177 // Last participant gives audio frame with passive VAD, although it has the | |
| 178 // largest energy. | |
| 179 participants[kParticipants - 1].fake_frame()->vad_activity_ = | |
| 180 AudioFrame::kVadPassive; | |
| 181 | |
| 182 AudioFrame audio_frame; | |
| 183 mixer->Mix(&audio_frame); | |
| 184 | |
| 185 for (int i = 0; i < kParticipants; ++i) { | |
| 186 bool is_mixed = participants[i].IsMixed(); | |
| 187 if (i == kParticipants - 1 || | |
| 188 i < kParticipants - 1 - | |
| 189 NewAudioConferenceMixer::kMaximumAmountOfMixedParticipants) { | |
| 190 EXPECT_FALSE(is_mixed) << "Mixing status of Participant #" << i | |
| 191 << " wrong."; | |
| 192 } else { | |
| 193 EXPECT_TRUE(is_mixed) << "Mixing status of Participant #" << i | |
| 194 << " wrong."; | |
| 195 } | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 TEST_F(BothMixersTest, CompareInitialFrameAudio) { | |
| 200 EXPECT_CALL(participant_, GetAudioFrame(_, _)).Times(AtLeast(1)); | |
| 201 | |
| 202 // Make sure the participant is marked as 'non-mixed' so that it is | |
| 203 // ramped in next round. | |
| 204 ResetParticipant(); | |
| 205 | |
| 206 // Construct the expected sound for the first mixing round. | |
| 207 mixing_round_frame.CopyFrom(*participant_.fake_frame()); | |
| 208 RampIn(mixing_round_frame); | |
| 209 | |
| 210 // Mix frames and put the result into a frame. | |
| 211 audio_mixer_->MixActiveChannels(); | |
| 212 audio_mixer_->GetMixedAudio(kSampleRateHz, 1, &mixed_results_frame_); | |
| 213 | |
| 214 // Compare the received frame with the expected. | |
| 215 EXPECT_EQ(mixing_round_frame.sample_rate_hz_, | |
| 216 mixed_results_frame_.sample_rate_hz_); | |
| 217 EXPECT_EQ(mixing_round_frame.num_channels_, | |
| 218 mixed_results_frame_.num_channels_); | |
| 219 EXPECT_EQ(mixing_round_frame.samples_per_channel_, | |
| 220 mixed_results_frame_.samples_per_channel_); | |
| 221 EXPECT_EQ(0, memcmp(mixing_round_frame.data_, mixed_results_frame_.data_, | |
| 222 sizeof(mixing_round_frame.data_))); | |
| 223 } | |
| 224 | |
| 225 TEST_F(BothMixersTest, CompareSecondFrameAudio) { | |
| 226 EXPECT_CALL(participant_, GetAudioFrame(_, _)).Times(AtLeast(1)); | |
| 227 | |
| 228 // Make sure the participant is marked as 'non-mixed' so that it is | |
| 229 // ramped in next round. | |
| 230 ResetParticipant(); | |
| 231 | |
| 232 // Do one mixing iteration. | |
| 233 audio_mixer_->MixActiveChannels(); | |
| 234 | |
| 235 // Mix frames a second time and compare with the expected frame | |
| 236 // (which is the participant's frame). | |
| 237 audio_mixer_->MixActiveChannels(); | |
| 238 audio_mixer_->GetMixedAudio(kSampleRateHz, 1, &mixed_results_frame_); | |
| 239 EXPECT_EQ(0, | |
| 240 memcmp(participant_.fake_frame()->data_, mixed_results_frame_.data_, | |
| 241 sizeof(mixing_round_frame.data_))); | |
| 242 } | |
| 243 | |
| 244 } // namespace webrtc | |
| OLD | NEW |