blob: ffaacb62ca3cfe56e90340fb403b8766ada9cf47 [file] [log] [blame]
/*
* 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 "webrtc/audio/audio_state.h"
#include "webrtc/modules/audio_mixer/audio_mixer_impl.h"
#include "webrtc/modules/audio_processing/include/mock_audio_processing.h"
#include "webrtc/test/gtest.h"
#include "webrtc/test/mock_voice_engine.h"
namespace webrtc {
namespace test {
namespace {
const int kSampleRate = 8000;
const int kNumberOfChannels = 1;
const int kBytesPerSample = 2;
struct ConfigHelper {
ConfigHelper() : audio_mixer(AudioMixerImpl::Create()) {
EXPECT_CALL(mock_voice_engine, RegisterVoiceEngineObserver(testing::_))
.WillOnce(testing::Return(0));
EXPECT_CALL(mock_voice_engine, DeRegisterVoiceEngineObserver())
.WillOnce(testing::Return(0));
EXPECT_CALL(mock_voice_engine, audio_device_module())
.Times(testing::AtLeast(1));
EXPECT_CALL(mock_voice_engine, audio_transport())
.WillRepeatedly(testing::Return(&audio_transport));
auto device = static_cast<MockAudioDeviceModule*>(
voice_engine().audio_device_module());
// Populate the audio transport proxy pointer to the most recent
// transport connected to the Audio Device.
ON_CALL(*device, RegisterAudioCallback(testing::_))
.WillByDefault(testing::Invoke([this](AudioTransport* transport) {
registered_audio_transport = transport;
return 0;
}));
audio_state_config.voice_engine = &mock_voice_engine;
audio_state_config.audio_mixer = audio_mixer;
audio_state_config.audio_processing =
new rtc::RefCountedObject<MockAudioProcessing>();
}
AudioState::Config& config() { return audio_state_config; }
MockVoiceEngine& voice_engine() { return mock_voice_engine; }
rtc::scoped_refptr<AudioMixer> mixer() { return audio_mixer; }
MockAudioTransport& original_audio_transport() { return audio_transport; }
AudioTransport* audio_transport_proxy() { return registered_audio_transport; }
private:
testing::StrictMock<MockVoiceEngine> mock_voice_engine;
AudioState::Config audio_state_config;
rtc::scoped_refptr<AudioMixer> audio_mixer;
MockAudioTransport audio_transport;
AudioTransport* registered_audio_transport = nullptr;
};
class FakeAudioSource : public AudioMixer::Source {
public:
// TODO(aleloi): Valid overrides commented out, because the gmock
// methods don't use any override declarations, and we want to avoid
// warnings from -Winconsistent-missing-override. See
// http://crbug.com/428099.
int Ssrc() const /*override*/ { return 0; }
int PreferredSampleRate() const /*override*/ { return kSampleRate; }
MOCK_METHOD2(GetAudioFrameWithInfo,
AudioFrameInfo(int sample_rate_hz, AudioFrame* audio_frame));
};
} // namespace
TEST(AudioStateTest, Create) {
ConfigHelper helper;
rtc::scoped_refptr<AudioState> audio_state =
AudioState::Create(helper.config());
EXPECT_TRUE(audio_state.get());
}
TEST(AudioStateTest, ConstructDestruct) {
ConfigHelper helper;
std::unique_ptr<internal::AudioState> audio_state(
new internal::AudioState(helper.config()));
}
TEST(AudioStateTest, GetVoiceEngine) {
ConfigHelper helper;
std::unique_ptr<internal::AudioState> audio_state(
new internal::AudioState(helper.config()));
EXPECT_EQ(audio_state->voice_engine(), &helper.voice_engine());
}
TEST(AudioStateTest, TypingNoiseDetected) {
ConfigHelper helper;
std::unique_ptr<internal::AudioState> audio_state(
new internal::AudioState(helper.config()));
VoiceEngineObserver* voe_observer =
static_cast<VoiceEngineObserver*>(audio_state.get());
EXPECT_FALSE(audio_state->typing_noise_detected());
voe_observer->CallbackOnError(-1, VE_NOT_INITED);
EXPECT_FALSE(audio_state->typing_noise_detected());
voe_observer->CallbackOnError(-1, VE_TYPING_NOISE_WARNING);
EXPECT_TRUE(audio_state->typing_noise_detected());
voe_observer->CallbackOnError(-1, VE_NOT_INITED);
EXPECT_TRUE(audio_state->typing_noise_detected());
voe_observer->CallbackOnError(-1, VE_TYPING_NOISE_OFF_WARNING);
EXPECT_FALSE(audio_state->typing_noise_detected());
voe_observer->CallbackOnError(-1, VE_NOT_INITED);
EXPECT_FALSE(audio_state->typing_noise_detected());
}
// Test that RecordedDataIsAvailable calls get to the original transport.
TEST(AudioStateAudioPathTest, RecordedAudioArrivesAtOriginalTransport) {
ConfigHelper helper;
rtc::scoped_refptr<AudioState> audio_state =
AudioState::Create(helper.config());
// Setup completed. Ensure call of original transport is forwarded to new.
uint32_t new_mic_level;
EXPECT_CALL(
helper.original_audio_transport(),
RecordedDataIsAvailable(nullptr, kSampleRate / 100, kBytesPerSample,
kNumberOfChannels, kSampleRate, 0, 0, 0, false,
testing::Ref(new_mic_level)));
helper.audio_transport_proxy()->RecordedDataIsAvailable(
nullptr, kSampleRate / 100, kBytesPerSample, kNumberOfChannels,
kSampleRate, 0, 0, 0, false, new_mic_level);
}
TEST(AudioStateAudioPathTest,
QueryingProxyForAudioShouldResultInGetAudioCallOnMixerSource) {
ConfigHelper helper;
rtc::scoped_refptr<AudioState> audio_state =
AudioState::Create(helper.config());
FakeAudioSource fake_source;
helper.mixer()->AddSource(&fake_source);
EXPECT_CALL(fake_source, GetAudioFrameWithInfo(testing::_, testing::_))
.WillOnce(
testing::Invoke([](int sample_rate_hz, AudioFrame* audio_frame) {
audio_frame->sample_rate_hz_ = sample_rate_hz;
audio_frame->samples_per_channel_ = sample_rate_hz / 100;
audio_frame->num_channels_ = kNumberOfChannels;
return AudioMixer::Source::AudioFrameInfo::kNormal;
}));
int16_t audio_buffer[kSampleRate / 100 * kNumberOfChannels];
size_t n_samples_out;
int64_t elapsed_time_ms;
int64_t ntp_time_ms;
helper.audio_transport_proxy()->NeedMorePlayData(
kSampleRate / 100, kBytesPerSample, kNumberOfChannels, kSampleRate,
audio_buffer, n_samples_out, &elapsed_time_ms, &ntp_time_ms);
}
} // namespace test
} // namespace webrtc