| Index: webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.cc
 | 
| 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 c1a49f221bcaf815158e1e58a5fc4fa66f1a89fb..47eac8fff56edb5653a766ef2e345f78de64c64a 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
 | 
| @@ -11,6 +11,7 @@
 | 
|  #include "webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.h"
 | 
|  
 | 
|  #include <algorithm>
 | 
| +#include <functional>
 | 
|  
 | 
|  #include "webrtc/modules/audio_conference_mixer/source/audio_frame_manipulator.h"
 | 
|  #include "webrtc/modules/audio_mixer/include/audio_mixer_defines.h"
 | 
| @@ -22,15 +23,40 @@
 | 
|  namespace webrtc {
 | 
|  namespace {
 | 
|  
 | 
| -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;
 | 
| -};
 | 
| +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) {
 | 
| +    if (!muted_) {
 | 
| +      energy_ = CalculateEnergy(*a);
 | 
| +    }
 | 
| +  }
 | 
|  
 | 
| -typedef std::list<AudioSourceWithFrame*> AudioSourceWithFrameList;
 | 
| +  // a.shouldMixBefore(b) is used to select mixer participants.
 | 
| +  bool shouldMixBefore(const SourceFrame& other) const {
 | 
| +    if (muted_ != other.muted_) {
 | 
| +      return other.muted_;
 | 
| +    }
 | 
| +
 | 
| +    auto our_activity = audio_frame_->vad_activity_;
 | 
| +    auto other_activity = other.audio_frame_->vad_activity_;
 | 
| +
 | 
| +    if (our_activity != other_activity) {
 | 
| +      return our_activity == AudioFrame::kVadActive;
 | 
| +    }
 | 
| +
 | 
| +    return energy_ > other.energy_;
 | 
| +  }
 | 
| +
 | 
| +  MixerAudioSource* audio_source_;
 | 
| +  AudioFrame* audio_frame_;
 | 
| +  bool muted_;
 | 
| +  uint32_t energy_;
 | 
| +  bool was_mixed_before_;
 | 
| +};
 | 
|  
 | 
|  // Mix |frame| into |mixed_frame|, with saturation protection and upmixing.
 | 
|  // These effects are applied to |frame| itself prior to mixing. Assumes that
 | 
| @@ -167,7 +193,6 @@ void NewAudioConferenceMixerImpl::Mix(AudioFrame* audio_frame_for_mixing) {
 | 
|    size_t remainingAudioSourcesAllowedToMix = kMaximumAmountOfMixedAudioSources;
 | 
|    RTC_DCHECK(thread_checker_.CalledOnValidThread());
 | 
|    AudioFrameList mixList;
 | 
| -  AudioFrameList rampOutList;
 | 
|    AudioFrameList additionalFramesList;
 | 
|    std::map<int, MixerAudioSource*> mixedAudioSourcesMap;
 | 
|    {
 | 
| @@ -214,20 +239,17 @@ void NewAudioConferenceMixerImpl::Mix(AudioFrame* audio_frame_for_mixing) {
 | 
|        }
 | 
|      }
 | 
|  
 | 
| -    UpdateToMix(&mixList, &rampOutList, &mixedAudioSourcesMap,
 | 
| -                &remainingAudioSourcesAllowedToMix);
 | 
| -
 | 
| +    mixList = UpdateToMix(remainingAudioSourcesAllowedToMix);
 | 
| +    remainingAudioSourcesAllowedToMix -= mixList.size();
 | 
|      GetAdditionalAudio(&additionalFramesList);
 | 
| -    UpdateMixedStatus(mixedAudioSourcesMap);
 | 
|    }
 | 
|  
 | 
|    // 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)));
 | 
| +  const size_t num_mixed_channels =
 | 
| +      std::max(MaxNumChannels(&mixList), MaxNumChannels(&additionalFramesList));
 | 
|  
 | 
|    audio_frame_for_mixing->UpdateFrame(
 | 
|        -1, _timeStamp, NULL, 0, _outputFrequency, AudioFrame::kNormalSpeech,
 | 
| @@ -245,7 +267,6 @@ void NewAudioConferenceMixerImpl::Mix(AudioFrame* audio_frame_for_mixing) {
 | 
|    {
 | 
|      CriticalSectionScoped cs(_crit.get());
 | 
|      MixAnonomouslyFromList(audio_frame_for_mixing, additionalFramesList);
 | 
| -    MixAnonomouslyFromList(audio_frame_for_mixing, rampOutList);
 | 
|  
 | 
|      if (audio_frame_for_mixing->samples_per_channel_ == 0) {
 | 
|        // Nothing was mixed, set the audio samples to silence.
 | 
| @@ -256,10 +277,6 @@ void NewAudioConferenceMixerImpl::Mix(AudioFrame* audio_frame_for_mixing) {
 | 
|        LimitMixedAudio(audio_frame_for_mixing);
 | 
|      }
 | 
|    }
 | 
| -
 | 
| -  ClearAudioFrameList(&mixList);
 | 
| -  ClearAudioFrameList(&rampOutList);
 | 
| -  ClearAudioFrameList(&additionalFramesList);
 | 
|    return;
 | 
|  }
 | 
|  
 | 
| @@ -426,177 +443,62 @@ int32_t NewAudioConferenceMixerImpl::GetLowestMixingFrequencyFromList(
 | 
|    return highestFreq;
 | 
|  }
 | 
|  
 | 
| -void NewAudioConferenceMixerImpl::UpdateToMix(
 | 
| -    AudioFrameList* mixList,
 | 
| -    AudioFrameList* rampOutList,
 | 
| -    std::map<int, MixerAudioSource*>* mixAudioSourceList,
 | 
| -    size_t* maxAudioFrameCounter) const {
 | 
| -  WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
 | 
| -               "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.
 | 
| -  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 = (*audio_source)->_mixHistory->WasMixed();
 | 
| +AudioFrameList NewAudioConferenceMixerImpl::UpdateToMix(
 | 
| +    size_t maxAudioFrameCounter) const {
 | 
| +  AudioFrameList result;
 | 
| +  std::vector<SourceFrame> audioSourceMixingDataList;
 | 
|  
 | 
| -    auto audio_frame_with_info =
 | 
| -        (*audio_source)->GetAudioFrameWithMuted(_id, _outputFrequency);
 | 
| -    auto ret = audio_frame_with_info.audio_frame_info;
 | 
| -    AudioFrame* audio_frame = audio_frame_with_info.audio_frame;
 | 
| -    if (ret == MixerAudioSource::AudioFrameInfo::kError) {
 | 
| -      continue;
 | 
| -    }
 | 
| -    const bool muted = (ret == MixerAudioSource::AudioFrameInfo::kMuted);
 | 
| -    if (audio_source_list_.size() != 1) {
 | 
| -      // TODO(wu): Issue 3390, add support for multiple audio sources case.
 | 
| -      audio_frame->ntp_time_ms_ = -1;
 | 
| -    }
 | 
| +  // Get audio source audio and put it in the struct vector.
 | 
| +  for (MixerAudioSource* audio_source : audio_source_list_) {
 | 
| +    auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted(
 | 
| +        _id, static_cast<int>(_outputFrequency));
 | 
|  
 | 
| -    // 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.
 | 
| -    // RTC_DCHECK_NE(audio_frame->vad_activity_, AudioFrame::kVadUnknown);
 | 
| -    if (audio_frame->vad_activity_ == AudioFrame::kVadUnknown) {
 | 
| +    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,
 | 
| -                   "invalid VAD state from audio source");
 | 
| +                   "failed to GetAudioFrameWithMuted() from participant");
 | 
| +      continue;
 | 
|      }
 | 
| +    audioSourceMixingDataList.emplace_back(
 | 
| +        audio_source, audio_source_audio_frame,
 | 
| +        audio_frame_info == MixerAudioSource::AudioFrameInfo::kMuted,
 | 
| +        audio_source->_mixHistory->WasMixed());
 | 
| +  }
 | 
|  
 | 
| -    if (audio_frame->vad_activity_ == AudioFrame::kVadActive) {
 | 
| -      if (!wasMixed && !muted) {
 | 
| -        RampIn(*audio_frame);
 | 
| -      }
 | 
| +  // Sort frames by sorting function.
 | 
| +  std::sort(audioSourceMixingDataList.begin(), audioSourceMixingDataList.end(),
 | 
| +            std::mem_fn(&SourceFrame::shouldMixBefore));
 | 
|  
 | 
| -      if (activeList.size() >= *maxAudioFrameCounter) {
 | 
| -        // 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(*audio_frame);
 | 
| -
 | 
| -        bool found_replace_item = false;
 | 
| -        for (AudioFrameList::iterator iter = activeList.begin();
 | 
| -             iter != activeList.end(); ++iter) {
 | 
| -          const uint32_t energy = muted ? 0 : CalculateEnergy(*iter->frame);
 | 
| -          if (energy < lowestEnergy) {
 | 
| -            replaceItem = iter;
 | 
| -            lowestEnergy = energy;
 | 
| -            found_replace_item = true;
 | 
| -          }
 | 
| -        }
 | 
| -        if (found_replace_item) {
 | 
| -          RTC_DCHECK(!muted);  // Cannot replace with a muted frame.
 | 
| -          FrameAndMuteInfo replaceFrame = *replaceItem;
 | 
| -
 | 
| -          bool replaceWasMixed = false;
 | 
| -          std::map<int, MixerAudioSource*>::const_iterator it =
 | 
| -              mixAudioSourceList->find(replaceFrame.frame->id_);
 | 
| -
 | 
| -          // When a frame is pushed to |activeList| it is also pushed
 | 
| -          // to mixAudioSourceList with the frame's id. This means
 | 
| -          // that the Find call above should never fail.
 | 
| -          RTC_DCHECK(it != mixAudioSourceList->end());
 | 
| -          replaceWasMixed = it->second->_mixHistory->WasMixed();
 | 
| -
 | 
| -          mixAudioSourceList->erase(replaceFrame.frame->id_);
 | 
| -          activeList.erase(replaceItem);
 | 
| -
 | 
| -          activeList.push_front(FrameAndMuteInfo(audio_frame, muted));
 | 
| -          (*mixAudioSourceList)[audio_frame->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);
 | 
| -            RTC_DCHECK_LE(
 | 
| -                rampOutList->size(),
 | 
| -                static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
 | 
| -          }
 | 
| -        } else {
 | 
| -          if (wasMixed) {
 | 
| -            if (!muted) {
 | 
| -              RampOut(*audio_frame);
 | 
| -            }
 | 
| -            rampOutList->push_back(FrameAndMuteInfo(audio_frame, muted));
 | 
| -            RTC_DCHECK_LE(
 | 
| -                rampOutList->size(),
 | 
| -                static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
 | 
| -          }
 | 
| -        }
 | 
| -      } else {
 | 
| -        activeList.push_front(FrameAndMuteInfo(audio_frame, muted));
 | 
| -        (*mixAudioSourceList)[audio_frame->id_] = *audio_source;
 | 
| -        RTC_DCHECK_LE(mixAudioSourceList->size(),
 | 
| -                      static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
 | 
| -      }
 | 
| -    } else {
 | 
| -      if (wasMixed) {
 | 
| -        AudioSourceWithFrame* part_struct =
 | 
| -            new AudioSourceWithFrame(*audio_source, audio_frame, muted);
 | 
| -        passiveWasMixedList.push_back(part_struct);
 | 
| -      } else if (mustAddToPassiveList) {
 | 
| -        if (!muted) {
 | 
| -          RampIn(*audio_frame);
 | 
| -        }
 | 
| -        AudioSourceWithFrame* part_struct =
 | 
| -            new AudioSourceWithFrame(*audio_source, audio_frame, muted);
 | 
| -        passiveWasNotMixedList.push_back(part_struct);
 | 
| -      }
 | 
| +  // Go through list in order and put things in mixList.
 | 
| +  for (SourceFrame& p : audioSourceMixingDataList) {
 | 
| +    // Filter muted.
 | 
| +    if (p.muted_) {
 | 
| +      p.audio_source_->_mixHistory->SetIsMixed(false);
 | 
| +      continue;
 | 
|      }
 | 
| -  }
 | 
| -  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) {
 | 
| -    mixList->push_back(*iter);
 | 
| -  }
 | 
| -  activeList.clear();
 | 
| -  // Always mix a constant number of AudioFrames. If there aren't enough
 | 
| -  // active audio sources mix passive ones. Starting with those that was mixed
 | 
| -  // last iteration.
 | 
| -  for (AudioSourceWithFrameList::const_iterator iter =
 | 
| -           passiveWasMixedList.begin();
 | 
| -       iter != passiveWasMixedList.end(); ++iter) {
 | 
| -    if (mixList->size() < *maxAudioFrameCounter + mixListStartSize) {
 | 
| -      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));
 | 
| +
 | 
| +    // Add frame to result vector for mixing.
 | 
| +    bool is_mixed = false;
 | 
| +    if (maxAudioFrameCounter > 0) {
 | 
| +      --maxAudioFrameCounter;
 | 
| +      if (!p.was_mixed_before_) {
 | 
| +        RampIn(*p.audio_frame_);
 | 
| +      }
 | 
| +      result.emplace_back(p.audio_frame_, false);
 | 
| +      is_mixed = true;
 | 
|      }
 | 
| -    delete *iter;
 | 
| -  }
 | 
| -  // And finally the ones that have not been mixed for a while.
 | 
| -  for (AudioSourceWithFrameList::const_iterator iter =
 | 
| -           passiveWasNotMixedList.begin();
 | 
| -       iter != passiveWasNotMixedList.end(); ++iter) {
 | 
| -    if (mixList->size() < *maxAudioFrameCounter + mixListStartSize) {
 | 
| -      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));
 | 
| +
 | 
| +    // Ramp out unmuted.
 | 
| +    if (p.was_mixed_before_ && !is_mixed) {
 | 
| +      RampOut(*p.audio_frame_);
 | 
| +      result.emplace_back(p.audio_frame_, false);
 | 
|      }
 | 
| -    delete *iter;
 | 
| +
 | 
| +    p.audio_source_->_mixHistory->SetIsMixed(is_mixed);
 | 
|    }
 | 
| -  RTC_DCHECK_GE(*maxAudioFrameCounter + mixListStartSize, mixList->size());
 | 
| -  *maxAudioFrameCounter += mixListStartSize - mixList->size();
 | 
| +  return result;
 | 
|  }
 | 
|  
 | 
|  void NewAudioConferenceMixerImpl::GetAdditionalAudio(
 | 
| @@ -633,38 +535,6 @@ void NewAudioConferenceMixerImpl::GetAdditionalAudio(
 | 
|    }
 | 
|  }
 | 
|  
 | 
| -void NewAudioConferenceMixerImpl::UpdateMixedStatus(
 | 
| -    const std::map<int, MixerAudioSource*>& mixedAudioSourcesMap) const {
 | 
| -  WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
 | 
| -               "UpdateMixedStatus(mixedAudioSourcesMap)");
 | 
| -  RTC_DCHECK_LE(mixedAudioSourcesMap.size(),
 | 
| -                static_cast<size_t>(kMaximumAmountOfMixedAudioSources));
 | 
| -
 | 
| -  // Loop through all audio_sources. If they are in the mix map they
 | 
| -  // were mixed.
 | 
| -  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 =
 | 
| -             mixedAudioSourcesMap.begin();
 | 
| -         it != mixedAudioSourcesMap.end(); ++it) {
 | 
| -      if (it->second == *audio_source) {
 | 
| -        isMixed = true;
 | 
| -        break;
 | 
| -      }
 | 
| -    }
 | 
| -    (*audio_source)->_mixHistory->SetIsMixed(isMixed);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void NewAudioConferenceMixerImpl::ClearAudioFrameList(
 | 
| -    AudioFrameList* audioFrameList) const {
 | 
| -  WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
 | 
| -               "ClearAudioFrameList(audioFrameList)");
 | 
| -  audioFrameList->clear();
 | 
| -}
 | 
| -
 | 
|  bool NewAudioConferenceMixerImpl::IsAudioSourceInList(
 | 
|      const MixerAudioSource& audio_source,
 | 
|      const MixerAudioSourceList& audioSourceList) const {
 | 
| 
 |