Added a level indicator to new mixer.
Added a level indicator to the new mixer. The level indicator is webrtc::voe::AudioLevel. It computes the current audio level, which is used all the way up to peerconnection. This is part of the project to rewrite the old conference mixer and output mixer. NOTRY=True Review-Url: https://codereview.webrtc.org/2230823004 Cr-Commit-Position: refs/heads/master@{#13878}
This commit is contained in:
parent
1f779052c6
commit
616df1e95c
@ -77,5 +77,6 @@ source_set("audio_conference_mixer") {
|
||||
"../../modules/audio_processing",
|
||||
"../../modules/utility",
|
||||
"../../system_wrappers",
|
||||
"../../voice_engine:level_indicator",
|
||||
]
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
'webrtc_utility',
|
||||
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
|
||||
'<(webrtc_root)/base/base.gyp:rtc_base_approved',
|
||||
'<(webrtc_root)/voice_engine/voice_engine.gyp:level_indicator',
|
||||
],
|
||||
'sources': [
|
||||
'audio_frame_manipulator.cc',
|
||||
|
||||
@ -59,6 +59,13 @@ class NewAudioConferenceMixer {
|
||||
virtual bool AnonymousMixabilityStatus(
|
||||
const MixerAudioSource& audio_source) const = 0;
|
||||
|
||||
// Output level functions for VoEVolumeControl. Return value
|
||||
// between 0 and 9 is returned by voe::AudioLevel.
|
||||
virtual int GetOutputAudioLevel() = 0;
|
||||
|
||||
// Return value between 0 and 0x7fff is returned by voe::AudioLevel.
|
||||
virtual int GetOutputAudioLevelFullRange() = 0;
|
||||
|
||||
protected:
|
||||
NewAudioConferenceMixer() {}
|
||||
};
|
||||
|
||||
@ -73,7 +73,6 @@ void RemixFrame(AudioFrame* frame, size_t number_of_channels) {
|
||||
// |mixed_frame| always has at least as many channels as |frame|. Supports
|
||||
// stereo at most.
|
||||
//
|
||||
// TODO(andrew): consider not modifying |frame| here.
|
||||
void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) {
|
||||
RTC_DCHECK_GE(mixed_frame->num_channels_, frame->num_channels_);
|
||||
if (use_limiter) {
|
||||
@ -237,8 +236,7 @@ void NewAudioConferenceMixerImpl::Mix(int sample_rate,
|
||||
|
||||
time_stamp_ += static_cast<uint32_t>(sample_size_);
|
||||
|
||||
use_limiter_ = num_mixed_audio_sources_ > 1 &&
|
||||
output_frequency_ <= AudioProcessing::kMaxNativeSampleRateHz;
|
||||
use_limiter_ = num_mixed_audio_sources_ > 1;
|
||||
|
||||
// We only use the limiter if it supports the output sample rate and
|
||||
// we're actually mixing multiple streams.
|
||||
@ -257,6 +255,10 @@ void NewAudioConferenceMixerImpl::Mix(int sample_rate,
|
||||
LimitMixedAudio(audio_frame_for_mixing);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass the final result to the level indicator.
|
||||
audio_level_.ComputeLevel(*audio_frame_for_mixing);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -591,4 +593,18 @@ bool NewAudioConferenceMixerImpl::LimitMixedAudio(
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int NewAudioConferenceMixerImpl::GetOutputAudioLevel() {
|
||||
const int level = audio_level_.Level();
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
|
||||
"GetAudioOutputLevel() => level=%d", level);
|
||||
return level;
|
||||
}
|
||||
|
||||
int NewAudioConferenceMixerImpl::GetOutputAudioLevelFullRange() {
|
||||
const int level = audio_level_.LevelFullRange();
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
|
||||
"GetAudioOutputLevelFullRange() => level=%d", level);
|
||||
return level;
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/modules/audio_mixer/new_audio_conference_mixer.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/voice_engine/level_indicator.h"
|
||||
|
||||
namespace webrtc {
|
||||
class AudioProcessing;
|
||||
@ -125,6 +126,11 @@ class NewAudioConferenceMixerImpl : public NewAudioConferenceMixer {
|
||||
|
||||
bool LimitMixedAudio(AudioFrame* mixedAudio) const;
|
||||
|
||||
// Output level functions for VoEVolumeControl.
|
||||
int GetOutputAudioLevel() override;
|
||||
|
||||
int GetOutputAudioLevelFullRange() override;
|
||||
|
||||
std::unique_ptr<CriticalSectionWrapper> crit_;
|
||||
std::unique_ptr<CriticalSectionWrapper> cb_crit_;
|
||||
|
||||
@ -152,6 +158,9 @@ class NewAudioConferenceMixerImpl : public NewAudioConferenceMixer {
|
||||
|
||||
// Used for inhibiting saturation in mixing.
|
||||
std::unique_ptr<AudioProcessing> limiter_;
|
||||
|
||||
// Measures audio level for the combined signal.
|
||||
voe::AudioLevel audio_level_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -77,13 +77,14 @@ class MockMixerAudioSource : public MixerAudioSource {
|
||||
}
|
||||
|
||||
private:
|
||||
AudioFrame fake_frame_;
|
||||
AudioFrame fake_frame_, output_frame_;
|
||||
AudioFrameInfo fake_audio_frame_info_;
|
||||
AudioFrameWithMuted FakeAudioFrameWithMuted(const int32_t id,
|
||||
int sample_rate_hz) {
|
||||
output_frame_.CopyFrom(fake_frame_);
|
||||
return {
|
||||
fake_frame(), // audio_frame_pointer
|
||||
fake_info(), // audio_frame_info
|
||||
&output_frame_, // audio_frame_pointer
|
||||
fake_info(), // audio_frame_info
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -274,10 +275,10 @@ TEST(AudioMixer, AnonymousAndNamed) {
|
||||
}
|
||||
|
||||
TEST(AudioMixer, LargestEnergyVadActiveMixed) {
|
||||
const int kId = 1;
|
||||
const int kAudioSources =
|
||||
constexpr int kId = 1;
|
||||
constexpr int kAudioSources =
|
||||
NewAudioConferenceMixer::kMaximumAmountOfMixedAudioSources + 3;
|
||||
const int kSampleRateHz = 32000;
|
||||
constexpr int kSampleRateHz = 32000;
|
||||
|
||||
std::unique_ptr<NewAudioConferenceMixer> mixer(
|
||||
NewAudioConferenceMixer::Create(kId));
|
||||
@ -328,7 +329,7 @@ TEST(AudioMixer, LargestEnergyVadActiveMixed) {
|
||||
}
|
||||
|
||||
TEST(AudioMixer, ParticipantSampleRate) {
|
||||
const int kId = 1;
|
||||
constexpr int kId = 1;
|
||||
std::unique_ptr<NewAudioConferenceMixer> mixer(
|
||||
NewAudioConferenceMixer::Create(kId));
|
||||
AudioFrame frame_for_mixing;
|
||||
@ -350,7 +351,7 @@ TEST(AudioMixer, ParticipantSampleRate) {
|
||||
}
|
||||
|
||||
TEST(AudioMixer, ParticipantNumberOfChannels) {
|
||||
const int kId = 1;
|
||||
constexpr int kId = 1;
|
||||
std::unique_ptr<NewAudioConferenceMixer> mixer(
|
||||
NewAudioConferenceMixer::Create(kId));
|
||||
AudioFrame frame_for_mixing;
|
||||
@ -370,6 +371,69 @@ TEST(AudioMixer, ParticipantNumberOfChannels) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the volume is reported as zero when the mixer input
|
||||
// comprises only zero values.
|
||||
TEST(AudioMixer, LevelIsZeroWhenMixingZeroes) {
|
||||
constexpr int kId = 1;
|
||||
constexpr int kSampleRateHz = 8000;
|
||||
std::unique_ptr<NewAudioConferenceMixer> mixer(
|
||||
NewAudioConferenceMixer::Create(kId));
|
||||
AudioFrame frame_for_mixing;
|
||||
|
||||
MockMixerAudioSource participant;
|
||||
participant.fake_frame()->sample_rate_hz_ = kSampleRateHz;
|
||||
participant.fake_frame()->num_channels_ = 1;
|
||||
|
||||
// Frame duration 10ms.
|
||||
participant.fake_frame()->samples_per_channel_ = kSampleRateHz / 100;
|
||||
|
||||
EXPECT_EQ(0, mixer->SetMixabilityStatus(&participant, true));
|
||||
for (size_t i = 0; i < 11; i++) {
|
||||
EXPECT_CALL(participant, GetAudioFrameWithMuted(_, kSampleRateHz))
|
||||
.Times(Exactly(1));
|
||||
mixer->Mix(8000, 1, &frame_for_mixing);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, mixer->GetOutputAudioLevel());
|
||||
EXPECT_EQ(0, mixer->GetOutputAudioLevelFullRange());
|
||||
}
|
||||
|
||||
// Test that the reported volume is maximal when the mixer
|
||||
// input comprises frames with maximal values.
|
||||
TEST(AudioMixer, LevelIsMaximalWhenMixingMaximalValues) {
|
||||
constexpr int kId = 1;
|
||||
constexpr int kSampleRateHz = 8000;
|
||||
std::unique_ptr<NewAudioConferenceMixer> mixer(
|
||||
NewAudioConferenceMixer::Create(kId));
|
||||
AudioFrame frame_for_mixing;
|
||||
|
||||
MockMixerAudioSource participant;
|
||||
participant.fake_frame()->sample_rate_hz_ = kSampleRateHz;
|
||||
participant.fake_frame()->num_channels_ = 1;
|
||||
|
||||
// Frame duration 10ms.
|
||||
participant.fake_frame()->samples_per_channel_ = kSampleRateHz / 100;
|
||||
|
||||
// Fill participant frame data with maximal sound.
|
||||
std::fill(participant.fake_frame()->data_,
|
||||
participant.fake_frame()->data_ + kSampleRateHz / 100,
|
||||
std::numeric_limits<int16_t>::max());
|
||||
|
||||
EXPECT_EQ(0, mixer->SetMixabilityStatus(&participant, true));
|
||||
for (size_t i = 0; i < 11; i++) {
|
||||
EXPECT_CALL(participant, GetAudioFrameWithMuted(_, kSampleRateHz))
|
||||
.Times(Exactly(1));
|
||||
mixer->Mix(8000, 1, &frame_for_mixing);
|
||||
}
|
||||
|
||||
// 9 is the highest possible audio level
|
||||
EXPECT_EQ(9, mixer->GetOutputAudioLevel());
|
||||
|
||||
// 0x7fff = 32767 is the highest full range audio level.
|
||||
EXPECT_EQ(std::numeric_limits<int16_t>::max(),
|
||||
mixer->GetOutputAudioLevelFullRange());
|
||||
}
|
||||
|
||||
TEST_F(BothMixersTest, CompareInitialFrameAudio) {
|
||||
EXPECT_CALL(participant_, GetAudioFrameWithMuted(_, _)).Times(Exactly(1));
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ AudioLevel::AudioLevel() :
|
||||
_count(0),
|
||||
_currentLevel(0),
|
||||
_currentLevelFullRange(0) {
|
||||
WebRtcSpl_Init();
|
||||
}
|
||||
|
||||
AudioLevel::~AudioLevel() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user