Removed callback in old AudioConferenceMixer.
OutputMixer and AudioConferenceMixer communicated via a callback. OutputMixer implemented an AudioMixerOutputReceiver interface, which defines the callback function NewMixedAudio. This has been removed and replaced by a simple function in the new mixer. The audio frame with mixed audio is now copied one time less. I have also removed one forward declaration.
Review-Url: https://codereview.webrtc.org/2111293003
Cr-Commit-Position: refs/heads/master@{#13550}
diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn
index 08c4bdb..4ffb310 100644
--- a/webrtc/modules/BUILD.gn
+++ b/webrtc/modules/BUILD.gn
@@ -20,6 +20,7 @@
"audio_coding",
"audio_conference_mixer",
"audio_device",
+ "audio_mixer",
"audio_processing",
"bitrate_controller",
"desktop_capture",
@@ -104,6 +105,7 @@
"audio_coding/neteq/tools/packet_unittest.cc",
"audio_conference_mixer/test/audio_conference_mixer_unittest.cc",
"audio_device/fine_audio_buffer_unittest.cc",
+ "audio_mixer/test/audio_mixer_unittest.cc",
"audio_processing/aec/echo_cancellation_unittest.cc",
"audio_processing/aec/system_delay_unittest.cc",
"audio_processing/agc/agc_manager_direct_unittest.cc",
@@ -380,6 +382,7 @@
"audio_coding:webrtc_opus",
"audio_conference_mixer",
"audio_device",
+ "audio_mixer",
"audio_processing",
"audio_processing:audioproc_test_utils",
"bitrate_controller",
diff --git a/webrtc/modules/audio_mixer/audio_mixer.cc b/webrtc/modules/audio_mixer/audio_mixer.cc
index 9048c39..66ee3f1 100644
--- a/webrtc/modules/audio_mixer/audio_mixer.cc
+++ b/webrtc/modules/audio_mixer/audio_mixer.cc
@@ -22,17 +22,6 @@
namespace webrtc {
namespace voe {
-void AudioMixer::NewMixedAudio(int32_t id,
- const AudioFrame& generalAudioFrame,
- const AudioFrame** uniqueAudioFrames,
- uint32_t size) {
- WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
- "AudioMixer::NewMixedAudio(id=%d, size=%u)", id, size);
-
- _audioFrame.CopyFrom(generalAudioFrame);
- _audioFrame.id_ = id;
-}
-
void AudioMixer::PlayNotification(int32_t id, uint32_t durationMs) {
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
"AudioMixer::PlayNotification(id=%d, durationMs=%d)", id,
@@ -58,7 +47,7 @@
void AudioMixer::RecordFileEnded(int32_t id) {
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, -1),
"AudioMixer::RecordFileEnded(id=%d)", id);
- assert(id == _instanceId);
+ RTC_DCHECK_EQ(id, _instanceId);
rtc::CritScope cs(&_fileCritSect);
_outputFileRecording = false;
@@ -93,12 +82,6 @@
_outputFileRecording(false) {
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
"AudioMixer::AudioMixer() - ctor");
-
- if (_mixerModule.RegisterMixedStreamCallback(this) == -1) {
- WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
- "AudioMixer::AudioMixer() failed to register mixer"
- "callbacks");
- }
}
void AudioMixer::Destroy(AudioMixer*& mixer) {
@@ -123,7 +106,6 @@
_outputFileRecorderPtr = NULL;
}
}
- _mixerModule.UnRegisterMixedStreamCallback();
delete &_mixerModule;
}
@@ -167,18 +149,18 @@
return 0;
}
-int32_t AudioMixer::SetMixabilityStatus(MixerAudioSource& participant,
+int32_t AudioMixer::SetMixabilityStatus(MixerAudioSource& audio_source,
bool mixable) {
- return _mixerModule.SetMixabilityStatus(&participant, mixable);
+ return _mixerModule.SetMixabilityStatus(&audio_source, mixable);
}
-int32_t AudioMixer::SetAnonymousMixabilityStatus(MixerAudioSource& participant,
+int32_t AudioMixer::SetAnonymousMixabilityStatus(MixerAudioSource& audio_source,
bool mixable) {
- return _mixerModule.SetAnonymousMixabilityStatus(&participant, mixable);
+ return _mixerModule.SetAnonymousMixabilityStatus(&audio_source, mixable);
}
int32_t AudioMixer::MixActiveChannels() {
- _mixerModule.Process();
+ _mixerModule.Mix(&_audioFrame);
return 0;
}
@@ -414,7 +396,7 @@
// Pure stereo mode (we are receiving a stereo signal).
}
- assert(_audioFrame.num_channels_ == 2);
+ RTC_DCHECK_EQ(_audioFrame.num_channels_, static_cast<size_t>(2));
AudioFrameOperations::Scale(_panLeft, _panRight, _audioFrame);
}
diff --git a/webrtc/modules/audio_mixer/audio_mixer.h b/webrtc/modules/audio_mixer/audio_mixer.h
index ddcebe5..c50a2cf 100644
--- a/webrtc/modules/audio_mixer/audio_mixer.h
+++ b/webrtc/modules/audio_mixer/audio_mixer.h
@@ -32,7 +32,7 @@
// Note: this class is in the process of being rewritten and merged
// with AudioConferenceMixer. Expect inheritance chains to be changed,
// member functions removed or renamed.
-class AudioMixer : public OldAudioMixerOutputReceiver, public FileCallback {
+class AudioMixer : public FileCallback {
public:
static int32_t Create(AudioMixer*& mixer, uint32_t instanceId); // NOLINT
@@ -52,11 +52,12 @@
int32_t DoOperationsOnCombinedSignal(bool feed_data_to_apm);
- int32_t SetMixabilityStatus(MixerAudioSource& participant, // NOLINT
+ int32_t SetMixabilityStatus(MixerAudioSource& audio_source, // NOLINT
bool mixable);
- int32_t SetAnonymousMixabilityStatus(MixerAudioSource& participant, // NOLINT
- bool mixable);
+ int32_t SetAnonymousMixabilityStatus(
+ MixerAudioSource& audio_source, // NOLINT
+ bool mixable);
int GetMixedAudio(int sample_rate_hz,
size_t num_channels,
@@ -79,12 +80,6 @@
virtual ~AudioMixer();
- // from AudioMixerOutputReceiver
- virtual void NewMixedAudio(int32_t id,
- const AudioFrame& generalAudioFrame,
- const AudioFrame** uniqueAudioFrames,
- uint32_t size);
-
// For file recording
void PlayNotification(int32_t id, uint32_t durationMs);
diff --git a/webrtc/modules/audio_mixer/include/audio_mixer_defines.h b/webrtc/modules/audio_mixer/include/audio_mixer_defines.h
index 3aa5c6b..e204435 100644
--- a/webrtc/modules/audio_mixer/include/audio_mixer_defines.h
+++ b/webrtc/modules/audio_mixer/include/audio_mixer_defines.h
@@ -64,21 +64,6 @@
MixerAudioSource();
virtual ~MixerAudioSource();
};
-
-class OldAudioMixerOutputReceiver {
- public:
- // This callback function provides the mixed audio for this mix iteration.
- // Note that uniqueAudioFrames is an array of AudioFrame pointers with the
- // size according to the size parameter.
- virtual void NewMixedAudio(const int32_t id,
- const AudioFrame& generalAudioFrame,
- const AudioFrame** uniqueAudioFrames,
- const uint32_t size) = 0;
-
- protected:
- OldAudioMixerOutputReceiver() {}
- virtual ~OldAudioMixerOutputReceiver() {}
-};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_MIXER_INCLUDE_AUDIO_MIXER_DEFINES_H_
diff --git a/webrtc/modules/audio_mixer/include/new_audio_conference_mixer.h b/webrtc/modules/audio_mixer/include/new_audio_conference_mixer.h
index f691640..6a6bf1e 100644
--- a/webrtc/modules/audio_mixer/include/new_audio_conference_mixer.h
+++ b/webrtc/modules/audio_mixer/include/new_audio_conference_mixer.h
@@ -16,13 +16,11 @@
#include "webrtc/modules/include/module_common_types.h"
namespace webrtc {
-class OldAudioMixerOutputReceiver;
class MixerAudioSource;
-class Trace;
class NewAudioConferenceMixer : public Module {
public:
- enum { kMaximumAmountOfMixedParticipants = 3 };
+ enum { kMaximumAmountOfMixedAudioSources = 3 };
enum Frequency {
kNbInHz = 8000,
kWbInHz = 16000,
@@ -40,32 +38,32 @@
int64_t TimeUntilNextProcess() override = 0;
void Process() override = 0;
- // Register/unregister a callback class for receiving the mixed audio.
- virtual int32_t RegisterMixedStreamCallback(
- OldAudioMixerOutputReceiver* receiver) = 0;
- virtual int32_t UnRegisterMixedStreamCallback() = 0;
-
- // Add/remove participants as candidates for mixing.
- virtual int32_t SetMixabilityStatus(MixerAudioSource* participant,
+ // Add/remove audio sources as candidates for mixing.
+ virtual int32_t SetMixabilityStatus(MixerAudioSource* audio_source,
bool mixable) = 0;
- // Returns true if a participant is a candidate for mixing.
- virtual bool MixabilityStatus(const MixerAudioSource& participant) const = 0;
+ // Returns true if an audio source is a candidate for mixing.
+ virtual bool MixabilityStatus(const MixerAudioSource& audio_source) const = 0;
- // Inform the mixer that the participant should always be mixed and not
- // count toward the number of mixed participants. Note that a participant
+ // Inform the mixer that the audio source should always be mixed and not
+ // count toward the number of mixed audio sources. Note that an audio source
// must have been added to the mixer (by calling SetMixabilityStatus())
// before this function can be successfully called.
- virtual int32_t SetAnonymousMixabilityStatus(MixerAudioSource* participant,
+ virtual int32_t SetAnonymousMixabilityStatus(MixerAudioSource* audio_source,
bool mixable) = 0;
- // Returns true if the participant is mixed anonymously.
- virtual bool AnonymousMixabilityStatus(
- const MixerAudioSource& participant) const = 0;
+
+ // Performs mixing by asking registered audio sources for audio.
+ // The mixed result is placed in the provided AudioFrame.
+ virtual void Mix(AudioFrame* audio_frame_for_mixing) = 0;
// Set the minimum sampling frequency at which to mix. The mixing algorithm
// may still choose to mix at a higher samling frequency to avoid
// downsampling of audio contributing to the mixed audio.
virtual int32_t SetMinimumMixingFrequency(Frequency freq) = 0;
+ // Returns true if the audio source is mixed anonymously.
+ virtual bool AnonymousMixabilityStatus(
+ const MixerAudioSource& audio_source) const = 0;
+
protected:
NewAudioConferenceMixer() {}
};
diff --git a/webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.cc b/webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.cc
index 36d70b2..57d4a9d 100644
--- a/webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.cc
+++ b/webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.cc
@@ -22,15 +22,15 @@
namespace webrtc {
namespace {
-struct ParticipantFrameStruct {
- ParticipantFrameStruct(MixerAudioSource* p, AudioFrame* a, bool m)
- : participant(p), audioFrame(a), muted(m) {}
- MixerAudioSource* participant;
- AudioFrame* audioFrame;
+struct AudioSourceWithFrame {
+ AudioSourceWithFrame(MixerAudioSource* p, AudioFrame* a, bool m)
+ : audio_source(p), audio_frame(a), muted(m) {}
+ MixerAudioSource* audio_source;
+ AudioFrame* audio_frame;
bool muted;
};
-typedef std::list<ParticipantFrameStruct*> ParticipantFrameStructList;
+typedef std::list<AudioSourceWithFrame*> AudioSourceWithFrameList;
// Mix |frame| into |mixed_frame|, with saturation protection and upmixing.
// These effects are applied to |frame| itself prior to mixing. Assumes that
@@ -39,7 +39,7 @@
//
// TODO(andrew): consider not modifying |frame| here.
void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) {
- assert(mixed_frame->num_channels_ >= frame->num_channels_);
+ RTC_DCHECK_GE(mixed_frame->num_channels_, frame->num_channels_);
if (use_limiter) {
// Divide by two to avoid saturation in the mixing.
// This is only meaningful if the limiter will be used.
@@ -47,7 +47,8 @@
}
if (mixed_frame->num_channels_ > frame->num_channels_) {
// We only support mono-to-stereo.
- assert(mixed_frame->num_channels_ == 2 && frame->num_channels_ == 1);
+ RTC_DCHECK_EQ(mixed_frame->num_channels_, static_cast<size_t>(2));
+ RTC_DCHECK_EQ(frame->num_channels_, static_cast<size_t>(1));
AudioFrameOperations::MonoToStereo(frame);
}
@@ -111,13 +112,12 @@
NewAudioConferenceMixerImpl::NewAudioConferenceMixerImpl(int id)
: _id(id),
_minimumMixingFreq(kLowestPossible),
- _mixReceiver(NULL),
_outputFrequency(kDefaultFrequency),
_sampleSize(0),
_audioFramePool(NULL),
- _participantList(),
- _additionalParticipantList(),
- _numMixedParticipants(0),
+ audio_source_list_(),
+ additional_audio_source_list_(),
+ num_mixed_audio_sources_(0),
use_limiter_(true),
_timeStamp(0),
_timeScheduler(kProcessPeriodicityInMs),
@@ -171,7 +171,7 @@
NewAudioConferenceMixerImpl::~NewAudioConferenceMixerImpl() {
MemoryPool<AudioFrame>::DeleteMemoryPool(_audioFramePool);
- assert(_audioFramePool == NULL);
+ RTC_DCHECK_EQ(_audioFramePool, static_cast<MemoryPool<AudioFrame>*>(nullptr));
}
// Process should be called every kProcessPeriodicityInMs ms
@@ -182,17 +182,22 @@
WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
"failed in TimeToNextUpdate() call");
// Sanity check
- assert(false);
+ RTC_NOTREACHED();
return -1;
}
return timeUntilNextProcess;
}
void NewAudioConferenceMixerImpl::Process() {
- size_t remainingParticipantsAllowedToMix = kMaximumAmountOfMixedParticipants;
+ // TODO(aleloi) Remove this method.
+ RTC_NOTREACHED();
+}
+
+void NewAudioConferenceMixerImpl::Mix(AudioFrame* audio_frame_for_mixing) {
+ size_t remainingAudioSourcesAllowedToMix = kMaximumAmountOfMixedAudioSources;
{
CriticalSectionScoped cs(_crit.get());
- assert(_processCalls == 0);
+ RTC_DCHECK_EQ(_processCalls, 0);
_processCalls++;
// Let the scheduler know that we are running one iteration.
@@ -202,7 +207,7 @@
AudioFrameList mixList;
AudioFrameList rampOutList;
AudioFrameList additionalFramesList;
- std::map<int, MixerAudioSource*> mixedParticipantsMap;
+ std::map<int, MixerAudioSource*> mixedAudioSourcesMap;
{
CriticalSectionScoped cs(_cbCrit.get());
@@ -210,7 +215,7 @@
// SILK can run in 12 kHz and 24 kHz. These frequencies are not
// supported so use the closest higher frequency to not lose any
// information.
- // TODO(henrike): this is probably more appropriate to do in
+ // TODO(aleloi): this is probably more appropriate to do in
// GetLowestMixingFrequency().
if (lowFreq == 12000) {
lowFreq = 16000;
@@ -244,7 +249,7 @@
}
break;
default:
- assert(false);
+ RTC_NOTREACHED();
CriticalSectionScoped cs(_crit.get());
_processCalls--;
@@ -252,69 +257,49 @@
}
}
- UpdateToMix(&mixList, &rampOutList, &mixedParticipantsMap,
- &remainingParticipantsAllowedToMix);
+ UpdateToMix(&mixList, &rampOutList, &mixedAudioSourcesMap,
+ &remainingAudioSourcesAllowedToMix);
GetAdditionalAudio(&additionalFramesList);
- UpdateMixedStatus(mixedParticipantsMap);
+ UpdateMixedStatus(mixedAudioSourcesMap);
}
- // Get an AudioFrame for mixing from the memory pool.
- AudioFrame* mixedAudio = NULL;
- if (_audioFramePool->PopMemory(mixedAudio) == -1) {
- WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
- "failed PopMemory() call");
- assert(false);
- return;
- }
+ // TODO(aleloi): it might be better to decide the number of channels
+ // with an API instead of dynamically.
+
+ // Find the max channels over all mixing lists.
+ const size_t num_mixed_channels = std::max(
+ MaxNumChannels(&mixList), std::max(MaxNumChannels(&additionalFramesList),
+ MaxNumChannels(&rampOutList)));
+
+ audio_frame_for_mixing->UpdateFrame(
+ -1, _timeStamp, NULL, 0, _outputFrequency, AudioFrame::kNormalSpeech,
+ AudioFrame::kVadPassive, num_mixed_channels);
+
+ _timeStamp += static_cast<uint32_t>(_sampleSize);
+
+ use_limiter_ = num_mixed_audio_sources_ > 1 &&
+ _outputFrequency <= AudioProcessing::kMaxNativeSampleRateHz;
+
+ // We only use the limiter if it supports the output sample rate and
+ // we're actually mixing multiple streams.
+ MixFromList(audio_frame_for_mixing, mixList, _id, use_limiter_);
{
CriticalSectionScoped cs(_crit.get());
+ MixAnonomouslyFromList(audio_frame_for_mixing, additionalFramesList);
+ MixAnonomouslyFromList(audio_frame_for_mixing, rampOutList);
- // TODO(henrike): it might be better to decide the number of channels
- // with an API instead of dynamically.
-
- // Find the max channels over all mixing lists.
- const size_t num_mixed_channels =
- std::max(MaxNumChannels(&mixList),
- std::max(MaxNumChannels(&additionalFramesList),
- MaxNumChannels(&rampOutList)));
-
- mixedAudio->UpdateFrame(-1, _timeStamp, NULL, 0, _outputFrequency,
- AudioFrame::kNormalSpeech, AudioFrame::kVadPassive,
- num_mixed_channels);
-
- _timeStamp += static_cast<uint32_t>(_sampleSize);
-
- // We only use the limiter if it supports the output sample rate and
- // we're actually mixing multiple streams.
- use_limiter_ = _numMixedParticipants > 1 &&
- _outputFrequency <= AudioProcessing::kMaxNativeSampleRateHz;
-
- MixFromList(mixedAudio, mixList);
- MixAnonomouslyFromList(mixedAudio, additionalFramesList);
- MixAnonomouslyFromList(mixedAudio, rampOutList);
-
- if (mixedAudio->samples_per_channel_ == 0) {
+ if (audio_frame_for_mixing->samples_per_channel_ == 0) {
// Nothing was mixed, set the audio samples to silence.
- mixedAudio->samples_per_channel_ = _sampleSize;
- mixedAudio->Mute();
+ audio_frame_for_mixing->samples_per_channel_ = _sampleSize;
+ audio_frame_for_mixing->Mute();
} else {
// Only call the limiter if we have something to mix.
- LimitMixedAudio(mixedAudio);
+ LimitMixedAudio(audio_frame_for_mixing);
}
}
- {
- CriticalSectionScoped cs(_cbCrit.get());
- if (_mixReceiver != NULL) {
- const AudioFrame** dummy = NULL;
- _mixReceiver->NewMixedAudio(_id, *mixedAudio, dummy, 0);
- }
- }
-
- // Reclaim all outstanding memory.
- _audioFramePool->PushMemory(mixedAudio);
ClearAudioFrameList(&mixList);
ClearAudioFrameList(&rampOutList);
ClearAudioFrameList(&additionalFramesList);
@@ -325,25 +310,6 @@
return;
}
-int32_t NewAudioConferenceMixerImpl::RegisterMixedStreamCallback(
- OldAudioMixerOutputReceiver* mixReceiver) {
- CriticalSectionScoped cs(_cbCrit.get());
- if (_mixReceiver != NULL) {
- return -1;
- }
- _mixReceiver = mixReceiver;
- return 0;
-}
-
-int32_t NewAudioConferenceMixerImpl::UnRegisterMixedStreamCallback() {
- CriticalSectionScoped cs(_cbCrit.get());
- if (_mixReceiver == NULL) {
- return -1;
- }
- _mixReceiver = NULL;
- return 0;
-}
-
int32_t NewAudioConferenceMixerImpl::SetOutputFrequency(
const Frequency& frequency) {
CriticalSectionScoped cs(_crit.get());
@@ -362,17 +328,17 @@
}
int32_t NewAudioConferenceMixerImpl::SetMixabilityStatus(
- MixerAudioSource* participant,
+ MixerAudioSource* audio_source,
bool mixable) {
if (!mixable) {
- // Anonymous participants are in a separate list. Make sure that the
- // participant is in the _participantList if it is being mixed.
- SetAnonymousMixabilityStatus(participant, false);
+ // Anonymous audio sources are in a separate list. Make sure that the
+ // audio source is in the _audioSourceList if it is being mixed.
+ SetAnonymousMixabilityStatus(audio_source, false);
}
- size_t numMixedParticipants;
+ size_t numMixedAudioSources;
{
CriticalSectionScoped cs(_cbCrit.get());
- const bool isMixed = IsParticipantInList(*participant, _participantList);
+ const bool isMixed = IsAudioSourceInList(*audio_source, audio_source_list_);
// API must be called with a new state.
if (!(mixable ^ isMixed)) {
WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
@@ -381,75 +347,77 @@
}
bool success = false;
if (mixable) {
- success = AddParticipantToList(participant, &_participantList);
+ success = AddAudioSourceToList(audio_source, &audio_source_list_);
} else {
- success = RemoveParticipantFromList(participant, &_participantList);
+ success = RemoveAudioSourceFromList(audio_source, &audio_source_list_);
}
if (!success) {
WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
- "failed to %s participant", mixable ? "add" : "remove");
- assert(false);
+ "failed to %s audio_source", mixable ? "add" : "remove");
+ RTC_NOTREACHED();
return -1;
}
- size_t numMixedNonAnonymous = _participantList.size();
- if (numMixedNonAnonymous > kMaximumAmountOfMixedParticipants) {
- numMixedNonAnonymous = kMaximumAmountOfMixedParticipants;
+ size_t numMixedNonAnonymous = audio_source_list_.size();
+ if (numMixedNonAnonymous > kMaximumAmountOfMixedAudioSources) {
+ numMixedNonAnonymous = kMaximumAmountOfMixedAudioSources;
}
- numMixedParticipants =
- numMixedNonAnonymous + _additionalParticipantList.size();
+ numMixedAudioSources =
+ numMixedNonAnonymous + additional_audio_source_list_.size();
}
// A MixerAudioSource was added or removed. Make sure the scratch
// buffer is updated if necessary.
// Note: The scratch buffer may only be updated in Process().
CriticalSectionScoped cs(_crit.get());
- _numMixedParticipants = numMixedParticipants;
+ num_mixed_audio_sources_ = numMixedAudioSources;
return 0;
}
bool NewAudioConferenceMixerImpl::MixabilityStatus(
- const MixerAudioSource& participant) const {
+ const MixerAudioSource& audio_source) const {
CriticalSectionScoped cs(_cbCrit.get());
- return IsParticipantInList(participant, _participantList);
+ return IsAudioSourceInList(audio_source, audio_source_list_);
}
int32_t NewAudioConferenceMixerImpl::SetAnonymousMixabilityStatus(
- MixerAudioSource* participant,
+ MixerAudioSource* audio_source,
bool anonymous) {
CriticalSectionScoped cs(_cbCrit.get());
- if (IsParticipantInList(*participant, _additionalParticipantList)) {
+ if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) {
if (anonymous) {
return 0;
}
- if (!RemoveParticipantFromList(participant, &_additionalParticipantList)) {
+ if (!RemoveAudioSourceFromList(audio_source,
+ &additional_audio_source_list_)) {
WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
- "unable to remove participant from anonymous list");
- assert(false);
+ "unable to remove audio_source from anonymous list");
+ RTC_NOTREACHED();
return -1;
}
- return AddParticipantToList(participant, &_participantList) ? 0 : -1;
+ return AddAudioSourceToList(audio_source, &audio_source_list_) ? 0 : -1;
}
if (!anonymous) {
return 0;
}
const bool mixable =
- RemoveParticipantFromList(participant, &_participantList);
+ RemoveAudioSourceFromList(audio_source, &audio_source_list_);
if (!mixable) {
WEBRTC_TRACE(
kTraceWarning, kTraceAudioMixerServer, _id,
- "participant must be registered before turning it into anonymous");
+ "audio_source must be registered before turning it into anonymous");
// Setting anonymous status is only possible if MixerAudioSource is
// already registered.
return -1;
}
- return AddParticipantToList(participant, &_additionalParticipantList) ? 0
- : -1;
+ return AddAudioSourceToList(audio_source, &additional_audio_source_list_)
+ ? 0
+ : -1;
}
bool NewAudioConferenceMixerImpl::AnonymousMixabilityStatus(
- const MixerAudioSource& participant) const {
+ const MixerAudioSource& audio_source) const {
CriticalSectionScoped cs(_cbCrit.get());
- return IsParticipantInList(participant, _additionalParticipantList);
+ return IsAudioSourceInList(audio_source, additional_audio_source_list_);
}
int32_t NewAudioConferenceMixerImpl::SetMinimumMixingFrequency(Frequency freq) {
@@ -468,7 +436,7 @@
} else {
WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
"SetMinimumMixingFrequency incorrect frequency: %i", freq);
- assert(false);
+ RTC_NOTREACHED();
return -1;
}
}
@@ -476,12 +444,12 @@
// Check all AudioFrames that are to be mixed. The highest sampling frequency
// found is the lowest that can be used without losing information.
int32_t NewAudioConferenceMixerImpl::GetLowestMixingFrequency() const {
- const int participantListFrequency =
- GetLowestMixingFrequencyFromList(_participantList);
+ const int audioSourceListFrequency =
+ GetLowestMixingFrequencyFromList(audio_source_list_);
const int anonymousListFrequency =
- GetLowestMixingFrequencyFromList(_additionalParticipantList);
- const int highestFreq = (participantListFrequency > anonymousListFrequency)
- ? participantListFrequency
+ GetLowestMixingFrequencyFromList(additional_audio_source_list_);
+ const int highestFreq = (audioSourceListFrequency > anonymousListFrequency)
+ ? audioSourceListFrequency
: anonymousListFrequency;
// Check if the user specified a lowest mixing frequency.
if (_minimumMixingFreq != kLowestPossible) {
@@ -508,58 +476,58 @@
void NewAudioConferenceMixerImpl::UpdateToMix(
AudioFrameList* mixList,
AudioFrameList* rampOutList,
- std::map<int, MixerAudioSource*>* mixParticipantList,
+ std::map<int, MixerAudioSource*>* mixAudioSourceList,
size_t* maxAudioFrameCounter) const {
WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
- "UpdateToMix(mixList,rampOutList,mixParticipantList,%d)",
+ "UpdateToMix(mixList,rampOutList,mixAudioSourceList,%d)",
*maxAudioFrameCounter);
const size_t mixListStartSize = mixList->size();
AudioFrameList activeList;
// Struct needed by the passive lists to keep track of which AudioFrame
// belongs to which MixerAudioSource.
- ParticipantFrameStructList passiveWasNotMixedList;
- ParticipantFrameStructList passiveWasMixedList;
- for (MixerAudioSourceList::const_iterator participant =
- _participantList.begin();
- participant != _participantList.end(); ++participant) {
- // Stop keeping track of passive participants if there are already
- // enough participants available (they wont be mixed anyway).
+ AudioSourceWithFrameList passiveWasNotMixedList;
+ AudioSourceWithFrameList passiveWasMixedList;
+ for (MixerAudioSourceList::const_iterator audio_source =
+ audio_source_list_.begin();
+ audio_source != audio_source_list_.end(); ++audio_source) {
+ // Stop keeping track of passive audioSources if there are already
+ // enough audio sources available (they wont be mixed anyway).
bool mustAddToPassiveList =
(*maxAudioFrameCounter >
(activeList.size() + passiveWasMixedList.size() +
passiveWasNotMixedList.size()));
bool wasMixed = false;
- wasMixed = (*participant)->_mixHistory->WasMixed();
+ wasMixed = (*audio_source)->_mixHistory->WasMixed();
AudioFrame* audioFrame = NULL;
if (_audioFramePool->PopMemory(audioFrame) == -1) {
WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
"failed PopMemory() call");
- assert(false);
+ RTC_NOTREACHED();
return;
}
audioFrame->sample_rate_hz_ = _outputFrequency;
- auto ret = (*participant)->GetAudioFrameWithMuted(_id, audioFrame);
+ auto ret = (*audio_source)->GetAudioFrameWithMuted(_id, audioFrame);
if (ret == MixerAudioSource::AudioFrameInfo::kError) {
WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
- "failed to GetAudioFrameWithMuted() from participant");
+ "failed to GetAudioFrameWithMuted() from audio source");
_audioFramePool->PushMemory(audioFrame);
continue;
}
const bool muted = (ret == MixerAudioSource::AudioFrameInfo::kMuted);
- if (_participantList.size() != 1) {
- // TODO(wu): Issue 3390, add support for multiple participants case.
+ if (audio_source_list_.size() != 1) {
+ // TODO(wu): Issue 3390, add support for multiple audio sources case.
audioFrame->ntp_time_ms_ = -1;
}
- // TODO(henrike): this assert triggers in some test cases where SRTP is
+ // TODO(aleloi): this assert triggers in some test cases where SRTP is
// used which prevents NetEQ from making a VAD. Temporarily disable this
// assert until the problem is fixed on a higher level.
- // assert(audioFrame->vad_activity_ != AudioFrame::kVadUnknown);
+ // RTC_DCHECK_NE(audioFrame->vad_activity_, AudioFrame::kVadUnknown);
if (audioFrame->vad_activity_ == AudioFrame::kVadUnknown) {
WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
- "invalid VAD state from participant");
+ "invalid VAD state from audio source");
}
if (audioFrame->vad_activity_ == AudioFrame::kVadActive) {
@@ -568,7 +536,7 @@
}
if (activeList.size() >= *maxAudioFrameCounter) {
- // There are already more active participants than should be
+ // There are already more active audio sources than should be
// mixed. Only keep the ones with the highest energy.
AudioFrameList::iterator replaceItem;
uint32_t lowestEnergy = muted ? 0 : CalculateEnergy(*audioFrame);
@@ -589,28 +557,30 @@
bool replaceWasMixed = false;
std::map<int, MixerAudioSource*>::const_iterator it =
- mixParticipantList->find(replaceFrame.frame->id_);
+ mixAudioSourceList->find(replaceFrame.frame->id_);
// When a frame is pushed to |activeList| it is also pushed
- // to mixParticipantList with the frame's id. This means
+ // to mixAudioSourceList with the frame's id. This means
// that the Find call above should never fail.
- assert(it != mixParticipantList->end());
+ RTC_DCHECK(it != mixAudioSourceList->end());
replaceWasMixed = it->second->_mixHistory->WasMixed();
- mixParticipantList->erase(replaceFrame.frame->id_);
+ mixAudioSourceList->erase(replaceFrame.frame->id_);
activeList.erase(replaceItem);
activeList.push_front(FrameAndMuteInfo(audioFrame, muted));
- (*mixParticipantList)[audioFrame->id_] = *participant;
- assert(mixParticipantList->size() <=
- kMaximumAmountOfMixedParticipants);
+ (*mixAudioSourceList)[audioFrame->id_] = *audio_source;
+ RTC_DCHECK_LE(mixAudioSourceList->size(),
+ static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
if (replaceWasMixed) {
if (!replaceFrame.muted) {
RampOut(*replaceFrame.frame);
}
rampOutList->push_back(replaceFrame);
- assert(rampOutList->size() <= kMaximumAmountOfMixedParticipants);
+ RTC_DCHECK_LE(
+ rampOutList->size(),
+ static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
} else {
_audioFramePool->PushMemory(replaceFrame.frame);
}
@@ -620,35 +590,38 @@
RampOut(*audioFrame);
}
rampOutList->push_back(FrameAndMuteInfo(audioFrame, muted));
- assert(rampOutList->size() <= kMaximumAmountOfMixedParticipants);
+ RTC_DCHECK_LE(
+ rampOutList->size(),
+ static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
} else {
_audioFramePool->PushMemory(audioFrame);
}
}
} else {
activeList.push_front(FrameAndMuteInfo(audioFrame, muted));
- (*mixParticipantList)[audioFrame->id_] = *participant;
- assert(mixParticipantList->size() <= kMaximumAmountOfMixedParticipants);
+ (*mixAudioSourceList)[audioFrame->id_] = *audio_source;
+ RTC_DCHECK_LE(mixAudioSourceList->size(),
+ static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
}
} else {
if (wasMixed) {
- ParticipantFrameStruct* part_struct =
- new ParticipantFrameStruct(*participant, audioFrame, muted);
+ AudioSourceWithFrame* part_struct =
+ new AudioSourceWithFrame(*audio_source, audioFrame, muted);
passiveWasMixedList.push_back(part_struct);
} else if (mustAddToPassiveList) {
if (!muted) {
RampIn(*audioFrame);
}
- ParticipantFrameStruct* part_struct =
- new ParticipantFrameStruct(*participant, audioFrame, muted);
+ AudioSourceWithFrame* part_struct =
+ new AudioSourceWithFrame(*audio_source, audioFrame, muted);
passiveWasNotMixedList.push_back(part_struct);
} else {
_audioFramePool->PushMemory(audioFrame);
}
}
}
- assert(activeList.size() <= *maxAudioFrameCounter);
- // At this point it is known which participants should be mixed. Transfer
+ RTC_DCHECK_LE(activeList.size(), *maxAudioFrameCounter);
+ // At this point it is known which audio sources should be mixed. Transfer
// this information to this functions output parameters.
for (AudioFrameList::const_iterator iter = activeList.begin();
iter != activeList.end(); ++iter) {
@@ -656,34 +629,38 @@
}
activeList.clear();
// Always mix a constant number of AudioFrames. If there aren't enough
- // active participants mix passive ones. Starting with those that was mixed
+ // active audio sources mix passive ones. Starting with those that was mixed
// last iteration.
- for (ParticipantFrameStructList::const_iterator iter =
+ for (AudioSourceWithFrameList::const_iterator iter =
passiveWasMixedList.begin();
iter != passiveWasMixedList.end(); ++iter) {
if (mixList->size() < *maxAudioFrameCounter + mixListStartSize) {
- mixList->push_back(FrameAndMuteInfo((*iter)->audioFrame, (*iter)->muted));
- (*mixParticipantList)[(*iter)->audioFrame->id_] = (*iter)->participant;
- assert(mixParticipantList->size() <= kMaximumAmountOfMixedParticipants);
+ mixList->push_back(
+ FrameAndMuteInfo((*iter)->audio_frame, (*iter)->muted));
+ (*mixAudioSourceList)[(*iter)->audio_frame->id_] = (*iter)->audio_source;
+ RTC_DCHECK_LE(mixAudioSourceList->size(),
+ static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
} else {
- _audioFramePool->PushMemory((*iter)->audioFrame);
+ _audioFramePool->PushMemory((*iter)->audio_frame);
}
delete *iter;
}
// And finally the ones that have not been mixed for a while.
- for (ParticipantFrameStructList::const_iterator iter =
+ for (AudioSourceWithFrameList::const_iterator iter =
passiveWasNotMixedList.begin();
iter != passiveWasNotMixedList.end(); ++iter) {
if (mixList->size() < *maxAudioFrameCounter + mixListStartSize) {
- mixList->push_back(FrameAndMuteInfo((*iter)->audioFrame, (*iter)->muted));
- (*mixParticipantList)[(*iter)->audioFrame->id_] = (*iter)->participant;
- assert(mixParticipantList->size() <= kMaximumAmountOfMixedParticipants);
+ mixList->push_back(
+ FrameAndMuteInfo((*iter)->audio_frame, (*iter)->muted));
+ (*mixAudioSourceList)[(*iter)->audio_frame->id_] = (*iter)->audio_source;
+ RTC_DCHECK_LE(mixAudioSourceList->size(),
+ static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
} else {
- _audioFramePool->PushMemory((*iter)->audioFrame);
+ _audioFramePool->PushMemory((*iter)->audio_frame);
}
delete *iter;
}
- assert(*maxAudioFrameCounter + mixListStartSize >= mixList->size());
+ RTC_DCHECK_GE(*maxAudioFrameCounter + mixListStartSize, mixList->size());
*maxAudioFrameCounter += mixListStartSize - mixList->size();
}
@@ -691,30 +668,30 @@
AudioFrameList* additionalFramesList) const {
WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
"GetAdditionalAudio(additionalFramesList)");
- // The GetAudioFrameWithMuted() callback may result in the participant being
- // removed from additionalParticipantList_. If that happens it will
- // invalidate any iterators. Create a copy of the participants list such
- // that the list of participants can be traversed safely.
- MixerAudioSourceList additionalParticipantList;
- additionalParticipantList.insert(additionalParticipantList.begin(),
- _additionalParticipantList.begin(),
- _additionalParticipantList.end());
+ // The GetAudioFrameWithMuted() callback may result in the audio source being
+ // removed from additionalAudioSourceList_. If that happens it will
+ // invalidate any iterators. Create a copy of the audio sources list such
+ // that the list of audio sources can be traversed safely.
+ MixerAudioSourceList additionalAudioSourceList;
+ additionalAudioSourceList.insert(additionalAudioSourceList.begin(),
+ additional_audio_source_list_.begin(),
+ additional_audio_source_list_.end());
- for (MixerAudioSourceList::const_iterator participant =
- additionalParticipantList.begin();
- participant != additionalParticipantList.end(); ++participant) {
+ for (MixerAudioSourceList::const_iterator audio_source =
+ additionalAudioSourceList.begin();
+ audio_source != additionalAudioSourceList.end(); ++audio_source) {
AudioFrame* audioFrame = NULL;
if (_audioFramePool->PopMemory(audioFrame) == -1) {
WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
"failed PopMemory() call");
- assert(false);
+ RTC_NOTREACHED();
return;
}
audioFrame->sample_rate_hz_ = _outputFrequency;
- auto ret = (*participant)->GetAudioFrameWithMuted(_id, audioFrame);
+ auto ret = (*audio_source)->GetAudioFrameWithMuted(_id, audioFrame);
if (ret == MixerAudioSource::AudioFrameInfo::kError) {
WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
- "failed to GetAudioFrameWithMuted() from participant");
+ "failed to GetAudioFrameWithMuted() from audio_source");
_audioFramePool->PushMemory(audioFrame);
continue;
}
@@ -729,26 +706,27 @@
}
void NewAudioConferenceMixerImpl::UpdateMixedStatus(
- const std::map<int, MixerAudioSource*>& mixedParticipantsMap) const {
+ const std::map<int, MixerAudioSource*>& mixedAudioSourcesMap) const {
WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
- "UpdateMixedStatus(mixedParticipantsMap)");
- assert(mixedParticipantsMap.size() <= kMaximumAmountOfMixedParticipants);
+ "UpdateMixedStatus(mixedAudioSourcesMap)");
+ RTC_DCHECK_LE(mixedAudioSourcesMap.size(),
+ static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
- // Loop through all participants. If they are in the mix map they
+ // Loop through all audio_sources. If they are in the mix map they
// were mixed.
- for (MixerAudioSourceList::const_iterator participant =
- _participantList.begin();
- participant != _participantList.end(); ++participant) {
+ for (MixerAudioSourceList::const_iterator audio_source =
+ audio_source_list_.begin();
+ audio_source != audio_source_list_.end(); ++audio_source) {
bool isMixed = false;
for (std::map<int, MixerAudioSource*>::const_iterator it =
- mixedParticipantsMap.begin();
- it != mixedParticipantsMap.end(); ++it) {
- if (it->second == *participant) {
+ mixedAudioSourcesMap.begin();
+ it != mixedAudioSourcesMap.end(); ++it) {
+ if (it->second == *audio_source) {
isMixed = true;
break;
}
}
- (*participant)->_mixHistory->SetIsMixed(isMixed);
+ (*audio_source)->_mixHistory->SetIsMixed(isMixed);
}
}
@@ -763,42 +741,42 @@
audioFrameList->clear();
}
-bool NewAudioConferenceMixerImpl::IsParticipantInList(
- const MixerAudioSource& participant,
- const MixerAudioSourceList& participantList) const {
+bool NewAudioConferenceMixerImpl::IsAudioSourceInList(
+ const MixerAudioSource& audio_source,
+ const MixerAudioSourceList& audioSourceList) const {
WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
- "IsParticipantInList(participant,participantList)");
- for (MixerAudioSourceList::const_iterator iter = participantList.begin();
- iter != participantList.end(); ++iter) {
- if (&participant == *iter) {
+ "IsAudioSourceInList(audio_source,audioSourceList)");
+ for (MixerAudioSourceList::const_iterator iter = audioSourceList.begin();
+ iter != audioSourceList.end(); ++iter) {
+ if (&audio_source == *iter) {
return true;
}
}
return false;
}
-bool NewAudioConferenceMixerImpl::AddParticipantToList(
- MixerAudioSource* participant,
- MixerAudioSourceList* participantList) const {
+bool NewAudioConferenceMixerImpl::AddAudioSourceToList(
+ MixerAudioSource* audio_source,
+ MixerAudioSourceList* audioSourceList) const {
WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
- "AddParticipantToList(participant, participantList)");
- participantList->push_back(participant);
+ "AddAudioSourceToList(audio_source, audioSourceList)");
+ audioSourceList->push_back(audio_source);
// Make sure that the mixed status is correct for new MixerAudioSource.
- participant->_mixHistory->ResetMixedStatus();
+ audio_source->_mixHistory->ResetMixedStatus();
return true;
}
-bool NewAudioConferenceMixerImpl::RemoveParticipantFromList(
- MixerAudioSource* participant,
- MixerAudioSourceList* participantList) const {
+bool NewAudioConferenceMixerImpl::RemoveAudioSourceFromList(
+ MixerAudioSource* audio_source,
+ MixerAudioSourceList* audioSourceList) const {
WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
- "RemoveParticipantFromList(participant, participantList)");
- for (MixerAudioSourceList::iterator iter = participantList->begin();
- iter != participantList->end(); ++iter) {
- if (*iter == participant) {
- participantList->erase(iter);
- // Participant is no longer mixed, reset to default.
- participant->_mixHistory->ResetMixedStatus();
+ "RemoveAudioSourceFromList(audio_source, audioSourceList)");
+ for (MixerAudioSourceList::iterator iter = audioSourceList->begin();
+ iter != audioSourceList->end(); ++iter) {
+ if (*iter == audio_source) {
+ audioSourceList->erase(iter);
+ // AudioSource is no longer mixed, reset to default.
+ audio_source->_mixHistory->ResetMixedStatus();
return true;
}
}
@@ -807,15 +785,17 @@
int32_t NewAudioConferenceMixerImpl::MixFromList(
AudioFrame* mixedAudio,
- const AudioFrameList& audioFrameList) const {
- WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
+ const AudioFrameList& audioFrameList,
+ int32_t id,
+ bool use_limiter) {
+ WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id,
"MixFromList(mixedAudio, audioFrameList)");
if (audioFrameList.empty())
return 0;
uint32_t position = 0;
- if (_numMixedParticipants == 1) {
+ if (audioFrameList.size() == 1) {
mixedAudio->timestamp_ = audioFrameList.front().frame->timestamp_;
mixedAudio->elapsed_time_ms_ =
audioFrameList.front().frame->elapsed_time_ms_;
@@ -828,17 +808,17 @@
for (AudioFrameList::const_iterator iter = audioFrameList.begin();
iter != audioFrameList.end(); ++iter) {
- if (position >= kMaximumAmountOfMixedParticipants) {
+ if (position >= kMaximumAmountOfMixedAudioSources) {
WEBRTC_TRACE(
- kTraceMemory, kTraceAudioMixerServer, _id,
- "Trying to mix more than max amount of mixed participants:%d!",
- kMaximumAmountOfMixedParticipants);
+ kTraceMemory, kTraceAudioMixerServer, id,
+ "Trying to mix more than max amount of mixed audio sources:%d!",
+ kMaximumAmountOfMixedAudioSources);
// Assert and avoid crash
- assert(false);
+ RTC_NOTREACHED();
position = 0;
}
if (!iter->muted) {
- MixFrames(mixedAudio, iter->frame, use_limiter_);
+ MixFrames(mixedAudio, iter->frame, use_limiter);
}
position++;
@@ -880,7 +860,7 @@
//
// It's possible to apply the gain in the AGC (with a target level of 0 dbFS
// and compression gain of 6 dB). However, in the transition frame when this
- // is enabled (moving from one to two participants) it has the potential to
+ // is enabled (moving from one to two audio sources) it has the potential to
// create discontinuities in the mixed frame.
//
// Instead we double the frame (with addition since left-shifting a
@@ -890,7 +870,7 @@
if (error != _limiter->kNoError) {
WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
"Error from AudioProcessing: %d", error);
- assert(false);
+ RTC_NOTREACHED();
return false;
}
return true;
diff --git a/webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.h b/webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.h
index 322e452..7206d37 100644
--- a/webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.h
+++ b/webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.h
@@ -40,10 +40,10 @@
NewMixHistory();
~NewMixHistory();
- // Returns true if the participant is being mixed.
+ // Returns true if the audio source is being mixed.
bool IsMixed() const;
- // Returns true if the participant was mixed previous mix
+ // Returns true if the audio source was mixed previous mix
// iteration.
bool WasMixed() const;
@@ -72,17 +72,15 @@
void Process() override;
// NewAudioConferenceMixer functions
- int32_t RegisterMixedStreamCallback(
- OldAudioMixerOutputReceiver* mixReceiver) override;
- int32_t UnRegisterMixedStreamCallback() override;
- int32_t SetMixabilityStatus(MixerAudioSource* participant,
+ int32_t SetMixabilityStatus(MixerAudioSource* audio_source,
bool mixable) override;
- bool MixabilityStatus(const MixerAudioSource& participant) const override;
- int32_t SetMinimumMixingFrequency(Frequency freq) override;
- int32_t SetAnonymousMixabilityStatus(MixerAudioSource* participant,
+ bool MixabilityStatus(const MixerAudioSource& audio_source) const override;
+ int32_t SetAnonymousMixabilityStatus(MixerAudioSource* audio_source,
bool mixable) override;
+ void Mix(AudioFrame* audio_frame_for_mixing) override;
+ int32_t SetMinimumMixingFrequency(Frequency freq) override;
bool AnonymousMixabilityStatus(
- const MixerAudioSource& participant) const override;
+ const MixerAudioSource& audio_source) const override;
private:
enum { DEFAULT_AUDIO_FRAME_POOLSIZE = 50 };
@@ -100,7 +98,7 @@
// should be ramped out over this AudioFrame to avoid audio discontinuities.
void UpdateToMix(AudioFrameList* mixList,
AudioFrameList* rampOutList,
- std::map<int, MixerAudioSource*>* mixParticipantList,
+ std::map<int, MixerAudioSource*>* mixAudioSourceList,
size_t* maxAudioFrameCounter) const;
// Return the lowest mixing frequency that can be used without having to
@@ -112,29 +110,31 @@
// Return the AudioFrames that should be mixed anonymously.
void GetAdditionalAudio(AudioFrameList* additionalFramesList) const;
- // Update the NewMixHistory of all MixerAudioSources. mixedParticipantsList
+ // Update the NewMixHistory of all MixerAudioSources. mixedAudioSourcesList
// should contain a map of MixerAudioSources that have been mixed.
void UpdateMixedStatus(
- const std::map<int, MixerAudioSource*>& mixedParticipantsList) const;
+ const std::map<int, MixerAudioSource*>& mixedAudioSourcesList) const;
// Clears audioFrameList and reclaims all memory associated with it.
void ClearAudioFrameList(AudioFrameList* audioFrameList) const;
// This function returns true if it finds the MixerAudioSource in the
// specified list of MixerAudioSources.
- bool IsParticipantInList(const MixerAudioSource& participant,
- const MixerAudioSourceList& participantList) const;
+ bool IsAudioSourceInList(const MixerAudioSource& audio_source,
+ const MixerAudioSourceList& audioSourceList) const;
// Add/remove the MixerAudioSource to the specified
// MixerAudioSource list.
- bool AddParticipantToList(MixerAudioSource* participant,
- MixerAudioSourceList* participantList) const;
- bool RemoveParticipantFromList(MixerAudioSource* removeParticipant,
- MixerAudioSourceList* participantList) const;
+ bool AddAudioSourceToList(MixerAudioSource* audio_source,
+ MixerAudioSourceList* audioSourceList) const;
+ bool RemoveAudioSourceFromList(MixerAudioSource* removeAudioSource,
+ MixerAudioSourceList* audioSourceList) const;
// Mix the AudioFrames stored in audioFrameList into mixedAudio.
- int32_t MixFromList(AudioFrame* mixedAudio,
- const AudioFrameList& audioFrameList) const;
+ static int32_t MixFromList(AudioFrame* mixedAudio,
+ const AudioFrameList& audioFrameList,
+ int32_t id,
+ bool use_limiter);
// Mix the AudioFrames stored in audioFrameList into mixedAudio. No
// record will be kept of this mix (e.g. the corresponding MixerAudioSources
@@ -151,9 +151,6 @@
Frequency _minimumMixingFreq;
- // Mix result callback
- OldAudioMixerOutputReceiver* _mixReceiver;
-
// The current sample frequency and sample size when mixing.
Frequency _outputFrequency;
size_t _sampleSize;
@@ -161,12 +158,12 @@
// Memory pool to avoid allocating/deallocating AudioFrames
MemoryPool<AudioFrame>* _audioFramePool;
- // List of all participants. Note all lists are disjunct
- MixerAudioSourceList _participantList; // May be mixed.
+ // List of all audio sources. Note all lists are disjunct
+ MixerAudioSourceList audio_source_list_; // May be mixed.
// Always mixed, anonomously.
- MixerAudioSourceList _additionalParticipantList;
+ MixerAudioSourceList additional_audio_source_list_;
- size_t _numMixedParticipants;
+ size_t num_mixed_audio_sources_;
// Determines if we will use a limiter for clipping protection during
// mixing.
bool use_limiter_;
diff --git a/webrtc/modules/audio_mixer/test/audio_mixer_unittest.cc b/webrtc/modules/audio_mixer/test/audio_mixer_unittest.cc
new file mode 100644
index 0000000..5071386
--- /dev/null
+++ b/webrtc/modules/audio_mixer/test/audio_mixer_unittest.cc
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2016 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/source/audio_frame_manipulator.h"
+#include "webrtc/modules/audio_mixer/audio_mixer.h"
+#include "webrtc/modules/audio_mixer/include/audio_mixer_defines.h"
+#include "webrtc/modules/audio_mixer/include/new_audio_conference_mixer.h"
+#include "webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::Invoke;
+using testing::Return;
+
+using webrtc::voe::AudioMixer;
+
+namespace webrtc {
+class MockMixerAudioSource : public MixerAudioSource {
+ public:
+ MockMixerAudioSource() {
+ ON_CALL(*this, GetAudioFrame(_, _))
+ .WillByDefault(Invoke(this, &MockMixerAudioSource::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;
+ }
+};
+
+class BothMixersTest : public testing::Test {
+ protected:
+ BothMixersTest() {
+ // Create an OutputMixer.
+ AudioMixer::Create(audio_mixer_, kId);
+
+ // Create one mixer participant and add it to the mixer.
+ EXPECT_EQ(0, audio_mixer_->SetMixabilityStatus(participant_, true));
+
+ // Each iteration, the participant will return a frame with this content:
+ participant_.fake_frame()->id_ = 1;
+ participant_.fake_frame()->sample_rate_hz_ = kSampleRateHz;
+ participant_.fake_frame()->speech_type_ = AudioFrame::kNormalSpeech;
+ participant_.fake_frame()->vad_activity_ = AudioFrame::kVadActive;
+ participant_.fake_frame()->num_channels_ = 1;
+
+ // We modify one sample within the RampIn window and one sample
+ // outside of it.
+ participant_.fake_frame()->data_[10] = 100;
+ participant_.fake_frame()->data_[20] = -200;
+ participant_.fake_frame()->data_[30] = 300;
+ participant_.fake_frame()->data_[90] = -400;
+
+ // Frame duration 10ms.
+ participant_.fake_frame()->samples_per_channel_ = kSampleRateHz / 100;
+ EXPECT_CALL(participant_, NeededFrequency(_))
+ .WillRepeatedly(Return(kSampleRateHz));
+ }
+
+ ~BothMixersTest() { AudioMixer::Destroy(audio_mixer_); }
+
+ // Mark the participant as 'unmixed' last round.
+ void ResetAudioSource() { participant_._mixHistory->SetIsMixed(false); }
+
+ AudioMixer* audio_mixer_;
+ MockMixerAudioSource participant_;
+ AudioFrame mixing_round_frame, mixed_results_frame_;
+
+ constexpr static int kSampleRateHz = 48000;
+ constexpr static int kId = 1;
+};
+
+TEST(AudioMixer, AnonymousAndNamed) {
+ constexpr int kId = 1;
+ // Should not matter even if partipants are more than
+ // kMaximumAmountOfMixedAudioSources.
+ constexpr int kNamed =
+ NewAudioConferenceMixer::kMaximumAmountOfMixedAudioSources + 1;
+ constexpr int kAnonymous =
+ NewAudioConferenceMixer::kMaximumAmountOfMixedAudioSources + 1;
+
+ std::unique_ptr<NewAudioConferenceMixer> mixer(
+ NewAudioConferenceMixer::Create(kId));
+
+ MockMixerAudioSource named[kNamed];
+ MockMixerAudioSource 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) {
+ // AudioSource 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(AudioMixer, LargestEnergyVadActiveMixed) {
+ const int kId = 1;
+ const int kAudioSources =
+ NewAudioConferenceMixer::kMaximumAmountOfMixedAudioSources + 3;
+ const int kSampleRateHz = 32000;
+
+ std::unique_ptr<NewAudioConferenceMixer> mixer(
+ NewAudioConferenceMixer::Create(kId));
+
+ MockMixerAudioSource participants[kAudioSources];
+
+ for (int i = 0; i < kAudioSources; ++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[kAudioSources - 1].fake_frame()->vad_activity_ =
+ AudioFrame::kVadPassive;
+
+ AudioFrame audio_frame;
+ mixer->Mix(&audio_frame);
+
+ for (int i = 0; i < kAudioSources; ++i) {
+ bool is_mixed = participants[i].IsMixed();
+ if (i == kAudioSources - 1 ||
+ i < kAudioSources - 1 -
+ NewAudioConferenceMixer::kMaximumAmountOfMixedAudioSources) {
+ EXPECT_FALSE(is_mixed) << "Mixing status of AudioSource #" << i
+ << " wrong.";
+ } else {
+ EXPECT_TRUE(is_mixed) << "Mixing status of AudioSource #" << i
+ << " wrong.";
+ }
+ }
+}
+
+TEST_F(BothMixersTest, CompareInitialFrameAudio) {
+ EXPECT_CALL(participant_, GetAudioFrame(_, _)).Times(AtLeast(1));
+
+ // Make sure the participant is marked as 'non-mixed' so that it is
+ // ramped in next round.
+ ResetAudioSource();
+
+ // Construct the expected sound for the first mixing round.
+ mixing_round_frame.CopyFrom(*participant_.fake_frame());
+ RampIn(mixing_round_frame);
+
+ // Mix frames and put the result into a frame.
+ audio_mixer_->MixActiveChannels();
+ audio_mixer_->GetMixedAudio(kSampleRateHz, 1, &mixed_results_frame_);
+
+ // Compare the received frame with the expected.
+ EXPECT_EQ(mixing_round_frame.sample_rate_hz_,
+ mixed_results_frame_.sample_rate_hz_);
+ EXPECT_EQ(mixing_round_frame.num_channels_,
+ mixed_results_frame_.num_channels_);
+ EXPECT_EQ(mixing_round_frame.samples_per_channel_,
+ mixed_results_frame_.samples_per_channel_);
+ EXPECT_EQ(0, memcmp(mixing_round_frame.data_, mixed_results_frame_.data_,
+ sizeof(mixing_round_frame.data_)));
+}
+
+TEST_F(BothMixersTest, CompareSecondFrameAudio) {
+ EXPECT_CALL(participant_, GetAudioFrame(_, _)).Times(AtLeast(1));
+
+ // Make sure the participant is marked as 'non-mixed' so that it is
+ // ramped in next round.
+ ResetAudioSource();
+
+ // Do one mixing iteration.
+ audio_mixer_->MixActiveChannels();
+
+ // Mix frames a second time and compare with the expected frame
+ // (which is the participant's frame).
+ audio_mixer_->MixActiveChannels();
+ audio_mixer_->GetMixedAudio(kSampleRateHz, 1, &mixed_results_frame_);
+ EXPECT_EQ(0,
+ memcmp(participant_.fake_frame()->data_, mixed_results_frame_.data_,
+ sizeof(mixing_round_frame.data_)));
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index 88b8142..832813f 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -233,6 +233,7 @@
'audio_coding/neteq/tools/packet_unittest.cc',
'audio_conference_mixer/test/audio_conference_mixer_unittest.cc',
'audio_device/fine_audio_buffer_unittest.cc',
+ 'audio_mixer/test/audio_mixer_unittest.cc',
'audio_processing/aec/echo_cancellation_unittest.cc',
'audio_processing/aec/system_delay_unittest.cc',
'audio_processing/agc/agc_manager_direct_unittest.cc',