From 2ae5fdff86b784545cbd724de54bb5ffedde1adf Mon Sep 17 00:00:00 2001 From: aleloi Date: Fri, 7 Oct 2016 04:30:10 -0700 Subject: [PATCH] Made MixerAudioSource a pure interface. This required quite a few small changes in the mixing algorithm structure, the mixer interface and the mixer unit tests. BUG=webrtc:6346 Review-Url: https://codereview.webrtc.org/2396483002 Cr-Commit-Position: refs/heads/master@{#14567} --- webrtc/modules/audio_mixer/BUILD.gn | 3 +- .../audio_mixer/audio_frame_manipulator.cc | 4 +- .../audio_mixer/audio_frame_manipulator.h | 2 +- webrtc/modules/audio_mixer/audio_mixer.gypi | 3 +- .../modules/audio_mixer/audio_mixer_defines.h | 21 +-- .../modules/audio_mixer/audio_mixer_impl.cc | 163 ++++++++++-------- webrtc/modules/audio_mixer/audio_mixer_impl.h | 19 +- ...nes.cc => audio_source_with_mix_status.cc} | 21 ++- .../audio_source_with_mix_status.h | 45 +++++ .../audio_mixer/test/audio_mixer_unittest.cc | 23 +-- 10 files changed, 179 insertions(+), 125 deletions(-) rename webrtc/modules/audio_mixer/{audio_mixer_defines.cc => audio_source_with_mix_status.cc} (54%) create mode 100644 webrtc/modules/audio_mixer/audio_source_with_mix_status.h diff --git a/webrtc/modules/audio_mixer/BUILD.gn b/webrtc/modules/audio_mixer/BUILD.gn index 866dcd812f..12af9cfe70 100644 --- a/webrtc/modules/audio_mixer/BUILD.gn +++ b/webrtc/modules/audio_mixer/BUILD.gn @@ -17,10 +17,11 @@ rtc_static_library("audio_mixer") { "audio_frame_manipulator.cc", "audio_frame_manipulator.h", "audio_mixer.h", - "audio_mixer_defines.cc", "audio_mixer_defines.h", "audio_mixer_impl.cc", "audio_mixer_impl.h", + "audio_source_with_mix_status.cc", + "audio_source_with_mix_status.h", ] public = [ diff --git a/webrtc/modules/audio_mixer/audio_frame_manipulator.cc b/webrtc/modules/audio_mixer/audio_frame_manipulator.cc index aafeedaeda..7ced9e29fa 100644 --- a/webrtc/modules/audio_mixer/audio_frame_manipulator.cc +++ b/webrtc/modules/audio_mixer/audio_frame_manipulator.cc @@ -30,11 +30,11 @@ const float kRampArray[] = { const size_t kRampSize = sizeof(kRampArray) / sizeof(kRampArray[0]); } // namespace -uint32_t NewMixerCalculateEnergy(const AudioFrame& audio_frame) { +uint32_t AudioMixerCalculateEnergy(const AudioFrame& audio_frame) { uint32_t energy = 0; for (size_t position = 0; position < audio_frame.samples_per_channel_; position++) { - // TODO(andrew): this can easily overflow. + // TODO(aleloi): This can overflow. Convert to floats. energy += audio_frame.data_[position] * audio_frame.data_[position]; } return energy; diff --git a/webrtc/modules/audio_mixer/audio_frame_manipulator.h b/webrtc/modules/audio_mixer/audio_frame_manipulator.h index 444891f2a0..4c8151d546 100644 --- a/webrtc/modules/audio_mixer/audio_frame_manipulator.h +++ b/webrtc/modules/audio_mixer/audio_frame_manipulator.h @@ -17,7 +17,7 @@ namespace webrtc { // Updates the audioFrame's energy (based on its samples). -uint32_t NewMixerCalculateEnergy(const AudioFrame& audio_frame); +uint32_t AudioMixerCalculateEnergy(const AudioFrame& audio_frame); // Apply linear step function that ramps in/out the audio samples in audio_frame void NewMixerRampIn(AudioFrame* audio_frame); diff --git a/webrtc/modules/audio_mixer/audio_mixer.gypi b/webrtc/modules/audio_mixer/audio_mixer.gypi index 43b25a40f6..dedf8653d0 100644 --- a/webrtc/modules/audio_mixer/audio_mixer.gypi +++ b/webrtc/modules/audio_mixer/audio_mixer.gypi @@ -22,10 +22,11 @@ 'audio_frame_manipulator.cc', 'audio_frame_manipulator.h', 'audio_mixer.h', - 'audio_mixer_defines.cc', 'audio_mixer_defines.h', 'audio_mixer_impl.cc', 'audio_mixer_impl.h', + 'audio_source_with_mix_status.cc', + 'audio_source_with_mix_status.h', ], }, ], # targets diff --git a/webrtc/modules/audio_mixer/audio_mixer_defines.h b/webrtc/modules/audio_mixer/audio_mixer_defines.h index 57e7f5027e..970a01de02 100644 --- a/webrtc/modules/audio_mixer/audio_mixer_defines.h +++ b/webrtc/modules/audio_mixer/audio_mixer_defines.h @@ -35,6 +35,8 @@ class MixerAudioSource { AudioFrameInfo audio_frame_info; }; + virtual ~MixerAudioSource() = default; + // The implementation of GetAudioFrameWithMuted should update // audio_frame with new audio every time it's called. Implementing // classes are allowed to return the same AudioFrame pointer on @@ -43,25 +45,6 @@ class MixerAudioSource { // mixer. virtual AudioFrameWithMuted GetAudioFrameWithMuted(int32_t id, int sample_rate_hz) = 0; - - // Returns true if the audio source was mixed this mix iteration. - bool IsMixed() const; - - // Returns true if the audio source was mixed previous mix - // iteration. - bool WasMixed() const; - - // Updates the mixed status. - int32_t SetIsMixed(bool mixed); - - void ResetMixedStatus(); - - private: - bool is_mixed_; - - protected: - MixerAudioSource(); - virtual ~MixerAudioSource(); }; } // namespace webrtc diff --git a/webrtc/modules/audio_mixer/audio_mixer_impl.cc b/webrtc/modules/audio_mixer/audio_mixer_impl.cc index 44e04fa32d..fa37f177f1 100644 --- a/webrtc/modules/audio_mixer/audio_mixer_impl.cc +++ b/webrtc/modules/audio_mixer/audio_mixer_impl.cc @@ -14,6 +14,7 @@ #include #include +#include "webrtc/base/logging.h" #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" #include "webrtc/modules/utility/include/audio_frame_operations.h" #include "webrtc/system_wrappers/include/trace.h" @@ -23,29 +24,26 @@ namespace { class SourceFrame { public: - SourceFrame(MixerAudioSource* p, AudioFrame* a, bool m, bool was_mixed_before) - : audio_source_(p), - audio_frame_(a), - muted_(m), - was_mixed_before_(was_mixed_before) { + SourceFrame(AudioSourceWithMixStatus* audio_source, + AudioFrame* audio_frame, + bool muted) + : audio_source_(audio_source), audio_frame_(audio_frame), muted_(muted) { if (!muted_) { - energy_ = NewMixerCalculateEnergy(*a); + energy_ = AudioMixerCalculateEnergy(*audio_frame); } } - SourceFrame(MixerAudioSource* p, - AudioFrame* a, - bool m, - bool was_mixed_before, + SourceFrame(AudioSourceWithMixStatus* audio_source, + AudioFrame* audio_frame, + bool muted, uint32_t energy) - : audio_source_(p), - audio_frame_(a), - muted_(m), - energy_(energy), - was_mixed_before_(was_mixed_before) {} + : audio_source_(audio_source), + audio_frame_(audio_frame), + muted_(muted), + energy_(energy) {} - // a.shouldMixBefore(b) is used to select mixer participants. - bool shouldMixBefore(const SourceFrame& other) const { + // a.ShouldMixBefore(b) is used to select mixer sources. + bool ShouldMixBefore(const SourceFrame& other) const { if (muted_ != other.muted_) { return other.muted_; } @@ -60,11 +58,10 @@ class SourceFrame { return energy_ > other.energy_; } - MixerAudioSource* audio_source_; - AudioFrame* audio_frame_; - bool muted_; - uint32_t energy_; - bool was_mixed_before_; + AudioSourceWithMixStatus* audio_source_ = nullptr; + AudioFrame* audio_frame_ = nullptr; + bool muted_ = true; + uint32_t energy_ = 0; }; // Remixes a frame between stereo and mono. @@ -80,13 +77,13 @@ void RemixFrame(AudioFrame* frame, size_t number_of_channels) { void Ramp(const std::vector& mixed_sources_and_frames) { for (const auto& source_frame : mixed_sources_and_frames) { // Ramp in previously unmixed. - if (!source_frame.was_mixed_before_) { + if (!source_frame.audio_source_->WasMixed()) { NewMixerRampIn(source_frame.audio_frame_); } const bool is_mixed = source_frame.audio_source_->IsMixed(); // Ramp out currently unmixed. - if (source_frame.was_mixed_before_ && !is_mixed) { + if (source_frame.audio_source_->WasMixed() && !is_mixed) { NewMixerRampOut(source_frame.audio_frame_); } } @@ -133,6 +130,24 @@ int32_t MixFromList(AudioFrame* mixed_audio, return 0; } +MixerAudioSourceList::const_iterator FindSourceInList( + MixerAudioSource const* audio_source, + MixerAudioSourceList const* audio_source_list) { + return std::find_if(audio_source_list->begin(), audio_source_list->end(), + [audio_source](const AudioSourceWithMixStatus& p) { + return p.audio_source() == audio_source; + }); +} + +MixerAudioSourceList::iterator FindSourceInList( + MixerAudioSource const* audio_source, + MixerAudioSourceList* audio_source_list) { + return std::find_if(audio_source_list->begin(), audio_source_list->end(), + [audio_source](const AudioSourceWithMixStatus& p) { + return p.audio_source() == audio_source; + }); +} + } // namespace std::unique_ptr AudioMixer::Create(int id) { @@ -153,7 +168,7 @@ AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr limiter) AudioMixerImpl::~AudioMixerImpl() {} -std::unique_ptr AudioMixerImpl::Create(int id) { +std::unique_ptr AudioMixerImpl::Create(int id) { Config config; config.Set(new ExperimentalAgc(false)); std::unique_ptr limiter(AudioProcessing::Create(config)); @@ -179,7 +194,7 @@ std::unique_ptr AudioMixerImpl::Create(int id) { if (limiter->gain_control()->Enable(true) != limiter->kNoError) return nullptr; - return std::unique_ptr( + return std::unique_ptr( new AudioMixerImpl(id, std::move(limiter))); } @@ -266,8 +281,8 @@ int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source, } { rtc::CritScope lock(&crit_); - const bool is_mixed = - IsAudioSourceInList(*audio_source, audio_source_list_); + const bool is_mixed = FindSourceInList(audio_source, &audio_source_list_) != + audio_source_list_.end(); // API must be called with a new state. if (!(mixable ^ is_mixed)) { WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, @@ -300,14 +315,16 @@ int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source, bool AudioMixerImpl::MixabilityStatus( const MixerAudioSource& audio_source) const { rtc::CritScope lock(&crit_); - return IsAudioSourceInList(audio_source, audio_source_list_); + return FindSourceInList(&audio_source, &audio_source_list_) != + audio_source_list_.end(); } int32_t AudioMixerImpl::SetAnonymousMixabilityStatus( MixerAudioSource* audio_source, bool anonymous) { rtc::CritScope lock(&crit_); - if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) { + if (FindSourceInList(audio_source, &additional_audio_source_list_) != + additional_audio_source_list_.end()) { if (anonymous) { return 0; } @@ -341,10 +358,11 @@ int32_t AudioMixerImpl::SetAnonymousMixabilityStatus( bool AudioMixerImpl::AnonymousMixabilityStatus( const MixerAudioSource& audio_source) const { rtc::CritScope lock(&crit_); - return IsAudioSourceInList(audio_source, additional_audio_source_list_); + return FindSourceInList(&audio_source, &additional_audio_source_list_) != + additional_audio_source_list_.end(); } -AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() const { +AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() { RTC_DCHECK_RUN_ON(&thread_checker_); WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, "GetNonAnonymousAudio()"); @@ -353,33 +371,33 @@ AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() const { std::vector ramp_list; // Get audio source audio and put it in the struct vector. - for (auto* const audio_source : audio_source_list_) { - auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( - id_, static_cast(OutputFrequency())); + for (auto& source_and_status : audio_source_list_) { + auto audio_frame_with_info = + source_and_status.audio_source()->GetAudioFrameWithMuted( + id_, static_cast(OutputFrequency())); const auto audio_frame_info = audio_frame_with_info.audio_frame_info; AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame; if (audio_frame_info == MixerAudioSource::AudioFrameInfo::kError) { WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, - "failed to GetAudioFrameWithMuted() from participant"); + "failed to GetAudioFrameWithMuted() from source"); continue; } audio_source_mixing_data_list.emplace_back( - audio_source, audio_source_audio_frame, - audio_frame_info == MixerAudioSource::AudioFrameInfo::kMuted, - audio_source->WasMixed()); + &source_and_status, audio_source_audio_frame, + audio_frame_info == MixerAudioSource::AudioFrameInfo::kMuted); } // Sort frames by sorting function. std::sort(audio_source_mixing_data_list.begin(), audio_source_mixing_data_list.end(), - std::mem_fn(&SourceFrame::shouldMixBefore)); + std::mem_fn(&SourceFrame::ShouldMixBefore)); int max_audio_frame_counter = kMaximumAmountOfMixedAudioSources; // Go through list in order and put unmuted frames in result list. - for (const SourceFrame& p : audio_source_mixing_data_list) { + for (const auto& p : audio_source_mixing_data_list) { // Filter muted. if (p.muted_) { p.audio_source_->SetIsMixed(false); @@ -391,8 +409,7 @@ AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() const { if (max_audio_frame_counter > 0) { --max_audio_frame_counter; result.push_back(p.audio_frame_); - ramp_list.emplace_back(p.audio_source_, p.audio_frame_, false, - p.was_mixed_before_, -1); + ramp_list.emplace_back(p.audio_source_, p.audio_frame_, false, -1); is_mixed = true; } p.audio_source_->SetIsMixed(is_mixed); @@ -401,24 +418,16 @@ AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() const { return result; } -AudioFrameList AudioMixerImpl::GetAnonymousAudio() const { +AudioFrameList AudioMixerImpl::GetAnonymousAudio() { RTC_DCHECK_RUN_ON(&thread_checker_); WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, "GetAnonymousAudio()"); - // The GetAudioFrameWithMuted() callback may result in the audio source being - // removed from additionalAudioFramesList_. If that happens it will - // invalidate any iterators. Create a copy of the audio sources list such - // that the list of participants can be traversed safely. std::vector ramp_list; - MixerAudioSourceList additional_audio_sources_list; AudioFrameList result; - additional_audio_sources_list.insert(additional_audio_sources_list.begin(), - additional_audio_source_list_.begin(), - additional_audio_source_list_.end()); - - for (const auto& audio_source : additional_audio_sources_list) { + for (auto& source_and_status : additional_audio_source_list_) { const auto audio_frame_with_info = - audio_source->GetAudioFrameWithMuted(id_, OutputFrequency()); + source_and_status.audio_source()->GetAudioFrameWithMuted( + id_, OutputFrequency()); const auto ret = audio_frame_with_info.audio_frame_info; AudioFrame* audio_frame = audio_frame_with_info.audio_frame; if (ret == MixerAudioSource::AudioFrameInfo::kError) { @@ -428,32 +437,20 @@ AudioFrameList AudioMixerImpl::GetAnonymousAudio() const { } if (ret != MixerAudioSource::AudioFrameInfo::kMuted) { result.push_back(audio_frame); - ramp_list.emplace_back(audio_source, audio_frame, false, - audio_source->IsMixed(), 0); - audio_source->SetIsMixed(true); + ramp_list.emplace_back(&source_and_status, audio_frame, false, 0); + source_and_status.SetIsMixed(true); } } Ramp(ramp_list); return result; } -bool AudioMixerImpl::IsAudioSourceInList( - const MixerAudioSource& audio_source, - const MixerAudioSourceList& audio_source_list) const { - WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, - "IsAudioSourceInList(audio_source,audio_source_list)"); - return std::find(audio_source_list.begin(), audio_source_list.end(), - &audio_source) != audio_source_list.end(); -} - bool AudioMixerImpl::AddAudioSourceToList( MixerAudioSource* audio_source, MixerAudioSourceList* audio_source_list) const { WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, "AddAudioSourceToList(audio_source, audio_source_list)"); - audio_source_list->push_back(audio_source); - // Make sure that the mixed status is correct for new MixerAudioSource. - audio_source->ResetMixedStatus(); + audio_source_list->emplace_back(audio_source); return true; } @@ -462,12 +459,9 @@ bool AudioMixerImpl::RemoveAudioSourceFromList( MixerAudioSourceList* audio_source_list) const { WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, "RemoveAudioSourceFromList(audio_source, audio_source_list)"); - const auto iter = std::find(audio_source_list->begin(), - audio_source_list->end(), audio_source); + const auto iter = FindSourceInList(audio_source, audio_source_list); if (iter != audio_source_list->end()) { audio_source_list->erase(iter); - // AudioSource is no longer mixed, reset to default. - audio_source->ResetMixedStatus(); return true; } else { return false; @@ -519,4 +513,25 @@ int AudioMixerImpl::GetOutputAudioLevelFullRange() { "GetAudioOutputLevelFullRange() => level=%d", level); return level; } + +bool AudioMixerImpl::GetAudioSourceMixabilityStatusForTest( + MixerAudioSource* audio_source) { + RTC_DCHECK_RUN_ON(&thread_checker_); + rtc::CritScope lock(&crit_); + + const auto non_anonymous_iter = + FindSourceInList(audio_source, &audio_source_list_); + if (non_anonymous_iter != audio_source_list_.end()) { + return non_anonymous_iter->IsMixed(); + } + + const auto anonymous_iter = + FindSourceInList(audio_source, &additional_audio_source_list_); + if (anonymous_iter != audio_source_list_.end()) { + return anonymous_iter->IsMixed(); + } + + LOG_T_F(LS_ERROR) << "Audio source unknown"; + return false; +} } // namespace webrtc diff --git a/webrtc/modules/audio_mixer/audio_mixer_impl.h b/webrtc/modules/audio_mixer/audio_mixer_impl.h index 942196afd2..83c53126e7 100644 --- a/webrtc/modules/audio_mixer/audio_mixer_impl.h +++ b/webrtc/modules/audio_mixer/audio_mixer_impl.h @@ -19,6 +19,7 @@ #include "webrtc/base/thread_checker.h" #include "webrtc/modules/audio_mixer/audio_mixer.h" #include "webrtc/modules/audio_mixer/audio_mixer_defines.h" +#include "webrtc/modules/audio_mixer/audio_source_with_mix_status.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" #include "webrtc/modules/include/module_common_types.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" @@ -28,14 +29,14 @@ namespace webrtc { typedef std::vector AudioFrameList; -typedef std::vector MixerAudioSourceList; +typedef std::vector MixerAudioSourceList; class AudioMixerImpl : public AudioMixer { public: // AudioProcessing only accepts 10 ms frames. static const int kFrameDurationInMs = 10; - static std::unique_ptr Create(int id); + static std::unique_ptr Create(int id); ~AudioMixerImpl() override; @@ -51,6 +52,11 @@ class AudioMixerImpl : public AudioMixer { bool AnonymousMixabilityStatus( const MixerAudioSource& audio_source) const override; + // Returns true if the source was mixed last round. Returns + // false and logs an error if the source was never added to the + // mixer. + bool GetAudioSourceMixabilityStatusForTest(MixerAudioSource* audio_source); + private: AudioMixerImpl(int id, std::unique_ptr limiter); @@ -61,16 +67,11 @@ class AudioMixerImpl : public AudioMixer { // Compute what audio sources to mix from audio_source_list_. Ramp // in and out. Update mixed status. Mixes up to // kMaximumAmountOfMixedAudioSources audio sources. - AudioFrameList GetNonAnonymousAudio() const EXCLUSIVE_LOCKS_REQUIRED(crit_); + AudioFrameList GetNonAnonymousAudio() EXCLUSIVE_LOCKS_REQUIRED(crit_); // Return the AudioFrames that should be mixed anonymously. Ramp in // and out. Update mixed status. - AudioFrameList GetAnonymousAudio() const EXCLUSIVE_LOCKS_REQUIRED(crit_); - - // This function returns true if it finds the MixerAudioSource in the - // specified list of MixerAudioSources. - bool IsAudioSourceInList(const MixerAudioSource& audio_source, - const MixerAudioSourceList& audio_source_list) const; + AudioFrameList GetAnonymousAudio() EXCLUSIVE_LOCKS_REQUIRED(crit_); // Add/remove the MixerAudioSource to the specified // MixerAudioSource list. diff --git a/webrtc/modules/audio_mixer/audio_mixer_defines.cc b/webrtc/modules/audio_mixer/audio_source_with_mix_status.cc similarity index 54% rename from webrtc/modules/audio_mixer/audio_mixer_defines.cc rename to webrtc/modules/audio_mixer/audio_source_with_mix_status.cc index 7779bedfdd..40ccad4ad7 100644 --- a/webrtc/modules/audio_mixer/audio_mixer_defines.cc +++ b/webrtc/modules/audio_mixer/audio_source_with_mix_status.cc @@ -8,31 +8,36 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/modules/audio_mixer/audio_mixer_defines.h" +#include "webrtc/modules/audio_mixer/audio_source_with_mix_status.h" namespace webrtc { -MixerAudioSource::MixerAudioSource() {} +AudioSourceWithMixStatus::AudioSourceWithMixStatus( + MixerAudioSource* audio_source) + : audio_source_(audio_source) {} -MixerAudioSource::~MixerAudioSource() {} +AudioSourceWithMixStatus::~AudioSourceWithMixStatus() {} -bool MixerAudioSource::IsMixed() const { +bool AudioSourceWithMixStatus::IsMixed() const { return is_mixed_; } -bool MixerAudioSource::WasMixed() const { +bool AudioSourceWithMixStatus::WasMixed() const { // Was mixed is the same as is mixed depending on perspective. This function // is for the perspective of AudioMixerImpl. return IsMixed(); } -int32_t MixerAudioSource::SetIsMixed(const bool mixed) { +void AudioSourceWithMixStatus::SetIsMixed(const bool mixed) { is_mixed_ = mixed; - return 0; } -void MixerAudioSource::ResetMixedStatus() { +void AudioSourceWithMixStatus::ResetMixedStatus() { is_mixed_ = false; } +MixerAudioSource* AudioSourceWithMixStatus::audio_source() const { + return audio_source_; +} + } // namespace webrtc diff --git a/webrtc/modules/audio_mixer/audio_source_with_mix_status.h b/webrtc/modules/audio_mixer/audio_source_with_mix_status.h new file mode 100644 index 0000000000..3489ec46ec --- /dev/null +++ b/webrtc/modules/audio_mixer/audio_source_with_mix_status.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_MIXER_AUDIO_SOURCE_WITH_MIX_STATUS_H_ +#define WEBRTC_MODULES_AUDIO_MIXER_AUDIO_SOURCE_WITH_MIX_STATUS_H_ + +#include "webrtc/modules/audio_mixer/audio_mixer_defines.h" + +namespace webrtc { + +// A class that holds a mixer participant and its mixing status. +class AudioSourceWithMixStatus { + public: + explicit AudioSourceWithMixStatus(MixerAudioSource* audio_source); + ~AudioSourceWithMixStatus(); + + AudioSourceWithMixStatus(const AudioSourceWithMixStatus&) = default; + + // Returns true if the audio source was mixed this mix iteration. + bool IsMixed() const; + + // Returns true if the audio source was mixed previous mix + // iteration. + bool WasMixed() const; + + // Updates the mixed status. + void SetIsMixed(const bool mixed); + void ResetMixedStatus(); + MixerAudioSource* audio_source() const; + + private: + MixerAudioSource* audio_source_ = nullptr; + bool is_mixed_ = false; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_MIXER_AUDIO_SOURCE_WITH_MIX_STATUS_H_ diff --git a/webrtc/modules/audio_mixer/test/audio_mixer_unittest.cc b/webrtc/modules/audio_mixer/test/audio_mixer_unittest.cc index 9bf1b8bba3..98c8bec270 100644 --- a/webrtc/modules/audio_mixer/test/audio_mixer_unittest.cc +++ b/webrtc/modules/audio_mixer/test/audio_mixer_unittest.cc @@ -15,7 +15,7 @@ #include "webrtc/base/bind.h" #include "webrtc/base/thread.h" -#include "webrtc/modules/audio_mixer/audio_mixer.h" +#include "webrtc/modules/audio_mixer/audio_mixer_impl.h" #include "webrtc/modules/audio_mixer/audio_mixer_defines.h" #include "webrtc/test/gmock.h" @@ -89,7 +89,7 @@ void MixAndCompare( RTC_DCHECK(frames.size() == frame_info.size()); RTC_DCHECK(frame_info.size() == expected_status.size()); - const std::unique_ptr mixer(AudioMixer::Create(kId)); + const std::unique_ptr mixer(AudioMixerImpl::Create(kId)); std::vector participants(num_audio_sources); for (int i = 0; i < num_audio_sources; i++) { @@ -107,7 +107,8 @@ void MixAndCompare( mixer->Mix(kDefaultSampleRateHz, 1, &frame_for_mixing); for (int i = 0; i < num_audio_sources; i++) { - EXPECT_EQ(expected_status[i], participants[i].IsMixed()) + EXPECT_EQ(expected_status[i], + mixer->GetAudioSourceMixabilityStatusForTest(&participants[i])) << "Mixed status of AudioSource #" << i << " wrong."; } } @@ -167,7 +168,7 @@ TEST(AudioMixer, LargestEnergyVadActiveMixed) { constexpr int kAudioSources = AudioMixer::kMaximumAmountOfMixedAudioSources + 3; - const std::unique_ptr mixer(AudioMixer::Create(kId)); + const std::unique_ptr mixer(AudioMixerImpl::Create(kId)); MockMixerAudioSource participants[kAudioSources]; @@ -194,7 +195,8 @@ TEST(AudioMixer, LargestEnergyVadActiveMixed) { &audio_frame); for (int i = 0; i < kAudioSources; ++i) { - bool is_mixed = participants[i].IsMixed(); + bool is_mixed = + mixer->GetAudioSourceMixabilityStatusForTest(&participants[i]); if (i == kAudioSources - 1 || i < kAudioSources - 1 - AudioMixer::kMaximumAmountOfMixedAudioSources) { EXPECT_FALSE(is_mixed) << "Mixing status of AudioSource #" << i @@ -351,7 +353,7 @@ TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) { constexpr int kAudioSources = AudioMixer::kMaximumAmountOfMixedAudioSources + 1; - const std::unique_ptr mixer(AudioMixer::Create(kId)); + const std::unique_ptr mixer(AudioMixerImpl::Create(kId)); MockMixerAudioSource participants[kAudioSources]; for (int i = 0; i < kAudioSources; i++) { @@ -374,8 +376,8 @@ TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) { // All participants but the loudest should have been mixed. for (int i = 0; i < kAudioSources - 1; i++) { - EXPECT_TRUE(participants[i].IsMixed()) << "Mixed status of AudioSource #" - << i << " wrong."; + EXPECT_TRUE(mixer->GetAudioSourceMixabilityStatusForTest(&participants[i])) + << "Mixed status of AudioSource #" << i << " wrong."; } // Add new participant with higher energy. @@ -390,12 +392,13 @@ TEST(AudioMixer, RampedOutSourcesShouldNotBeMarkedMixed) { mixer->Mix(kDefaultSampleRateHz, 1, &frame_for_mixing); // The most quiet participant should not have been mixed. - EXPECT_FALSE(participants[0].IsMixed()) + EXPECT_FALSE(mixer->GetAudioSourceMixabilityStatusForTest(&participants[0])) << "Mixed status of AudioSource #0 wrong."; // The loudest participants should have been mixed. for (int i = 1; i < kAudioSources; i++) { - EXPECT_EQ(true, participants[i].IsMixed()) + EXPECT_EQ(true, + mixer->GetAudioSourceMixabilityStatusForTest(&participants[i])) << "Mixed status of AudioSource #" << i << " wrong."; } }