| /* |
| * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <memory> |
| |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "webrtc/modules/audio_conference_mixer/include/audio_conference_mixer.h" |
| #include "webrtc/modules/audio_conference_mixer/include/audio_conference_mixer_defines.h" |
| |
| namespace webrtc { |
| |
| using testing::_; |
| using testing::AtLeast; |
| using testing::Invoke; |
| using testing::Return; |
| |
| class MockAudioMixerOutputReceiver : public AudioMixerOutputReceiver { |
| public: |
| MOCK_METHOD4(NewMixedAudio, void(const int32_t id, |
| const AudioFrame& general_audio_frame, |
| const AudioFrame** unique_audio_frames, |
| const uint32_t size)); |
| }; |
| |
| class MockMixerParticipant : public MixerParticipant { |
| public: |
| MockMixerParticipant() { |
| ON_CALL(*this, GetAudioFrame(_, _)) |
| .WillByDefault(Invoke(this, &MockMixerParticipant::FakeAudioFrame)); |
| } |
| MOCK_METHOD2(GetAudioFrame, |
| int32_t(const int32_t id, AudioFrame* audio_frame)); |
| MOCK_CONST_METHOD1(NeededFrequency, int32_t(const int32_t id)); |
| AudioFrame* fake_frame() { return &fake_frame_; } |
| |
| private: |
| AudioFrame fake_frame_; |
| int32_t FakeAudioFrame(const int32_t id, AudioFrame* audio_frame) { |
| audio_frame->CopyFrom(fake_frame_); |
| return 0; |
| } |
| }; |
| |
| TEST(AudioConferenceMixer, AnonymousAndNamed) { |
| const int kId = 1; |
| // Should not matter even if partipants are more than |
| // kMaximumAmountOfMixedParticipants. |
| const int kNamed = |
| AudioConferenceMixer::kMaximumAmountOfMixedParticipants + 1; |
| const int kAnonymous = |
| AudioConferenceMixer::kMaximumAmountOfMixedParticipants + 1; |
| |
| std::unique_ptr<AudioConferenceMixer> mixer( |
| AudioConferenceMixer::Create(kId)); |
| |
| MockMixerParticipant named[kNamed]; |
| MockMixerParticipant anonymous[kAnonymous]; |
| |
| for (int i = 0; i < kNamed; ++i) { |
| EXPECT_EQ(0, mixer->SetMixabilityStatus(&named[i], true)); |
| EXPECT_TRUE(mixer->MixabilityStatus(named[i])); |
| } |
| |
| for (int i = 0; i < kAnonymous; ++i) { |
| // Participant must be registered before turning it into anonymous. |
| EXPECT_EQ(-1, mixer->SetAnonymousMixabilityStatus(&anonymous[i], true)); |
| EXPECT_EQ(0, mixer->SetMixabilityStatus(&anonymous[i], true)); |
| EXPECT_TRUE(mixer->MixabilityStatus(anonymous[i])); |
| EXPECT_FALSE(mixer->AnonymousMixabilityStatus(anonymous[i])); |
| |
| EXPECT_EQ(0, mixer->SetAnonymousMixabilityStatus(&anonymous[i], true)); |
| EXPECT_TRUE(mixer->AnonymousMixabilityStatus(anonymous[i])); |
| |
| // Anonymous participants do not show status by MixabilityStatus. |
| EXPECT_FALSE(mixer->MixabilityStatus(anonymous[i])); |
| } |
| |
| for (int i = 0; i < kNamed; ++i) { |
| EXPECT_EQ(0, mixer->SetMixabilityStatus(&named[i], false)); |
| EXPECT_FALSE(mixer->MixabilityStatus(named[i])); |
| } |
| |
| for (int i = 0; i < kAnonymous - 1; i++) { |
| EXPECT_EQ(0, mixer->SetAnonymousMixabilityStatus(&anonymous[i], false)); |
| EXPECT_FALSE(mixer->AnonymousMixabilityStatus(anonymous[i])); |
| |
| // SetAnonymousMixabilityStatus(anonymous, false) moves anonymous to the |
| // named group. |
| EXPECT_TRUE(mixer->MixabilityStatus(anonymous[i])); |
| } |
| |
| // SetMixabilityStatus(anonymous, false) will remove anonymous from both |
| // anonymous and named groups. |
| EXPECT_EQ(0, mixer->SetMixabilityStatus(&anonymous[kAnonymous - 1], false)); |
| EXPECT_FALSE(mixer->AnonymousMixabilityStatus(anonymous[kAnonymous - 1])); |
| EXPECT_FALSE(mixer->MixabilityStatus(anonymous[kAnonymous - 1])); |
| } |
| |
| TEST(AudioConferenceMixer, LargestEnergyVadActiveMixed) { |
| const int kId = 1; |
| const int kParticipants = |
| AudioConferenceMixer::kMaximumAmountOfMixedParticipants + 3; |
| const int kSampleRateHz = 32000; |
| |
| std::unique_ptr<AudioConferenceMixer> mixer( |
| AudioConferenceMixer::Create(kId)); |
| |
| MockAudioMixerOutputReceiver output_receiver; |
| EXPECT_EQ(0, mixer->RegisterMixedStreamCallback(&output_receiver)); |
| |
| MockMixerParticipant participants[kParticipants]; |
| |
| for (int i = 0; i < kParticipants; ++i) { |
| participants[i].fake_frame()->id_ = i; |
| participants[i].fake_frame()->sample_rate_hz_ = kSampleRateHz; |
| participants[i].fake_frame()->speech_type_ = AudioFrame::kNormalSpeech; |
| participants[i].fake_frame()->vad_activity_ = AudioFrame::kVadActive; |
| participants[i].fake_frame()->num_channels_ = 1; |
| |
| // Frame duration 10ms. |
| participants[i].fake_frame()->samples_per_channel_ = kSampleRateHz / 100; |
| |
| // We set the 80-th sample value since the first 80 samples may be |
| // modified by a ramped-in window. |
| participants[i].fake_frame()->data_[80] = i; |
| |
| EXPECT_EQ(0, mixer->SetMixabilityStatus(&participants[i], true)); |
| EXPECT_CALL(participants[i], GetAudioFrame(_, _)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(participants[i], NeededFrequency(_)) |
| .WillRepeatedly(Return(kSampleRateHz)); |
| } |
| |
| // Last participant gives audio frame with passive VAD, although it has the |
| // largest energy. |
| participants[kParticipants - 1].fake_frame()->vad_activity_ = |
| AudioFrame::kVadPassive; |
| |
| EXPECT_CALL(output_receiver, NewMixedAudio(_, _, _, _)) |
| .Times(AtLeast(1)); |
| |
| mixer->Process(); |
| |
| for (int i = 0; i < kParticipants; ++i) { |
| bool is_mixed = participants[i].IsMixed(); |
| if (i == kParticipants - 1 || i < kParticipants - 1 - |
| AudioConferenceMixer::kMaximumAmountOfMixedParticipants) { |
| EXPECT_FALSE(is_mixed) << "Mixing status of Participant #" |
| << i << " wrong."; |
| } else { |
| EXPECT_TRUE(is_mixed) << "Mixing status of Participant #" |
| << i << " wrong."; |
| } |
| } |
| |
| EXPECT_EQ(0, mixer->UnRegisterMixedStreamCallback()); |
| } |
| |
| } // namespace webrtc |