1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
110c836bfad33cbd3517e2c145cc24241fb98967d8pbos@webrtc.org#include "webrtc/modules/audio_conference_mixer/interface/audio_conference_mixer_defines.h"
120c836bfad33cbd3517e2c145cc24241fb98967d8pbos@webrtc.org#include "webrtc/modules/audio_conference_mixer/source/audio_conference_mixer_impl.h"
130c836bfad33cbd3517e2c145cc24241fb98967d8pbos@webrtc.org#include "webrtc/modules/audio_conference_mixer/source/audio_frame_manipulator.h"
140c836bfad33cbd3517e2c145cc24241fb98967d8pbos@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
150c836bfad33cbd3517e2c145cc24241fb98967d8pbos@webrtc.org#include "webrtc/modules/utility/interface/audio_frame_operations.h"
160c836bfad33cbd3517e2c145cc24241fb98967d8pbos@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
170c836bfad33cbd3517e2c145cc24241fb98967d8pbos@webrtc.org#include "webrtc/system_wrappers/interface/trace.h"
18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace {
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
224b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgstruct ParticipantFramePair {
234b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org  MixerParticipant* participant;
244b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org  AudioFrame* audioFrame;
254b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org};
264b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org
274b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgtypedef std::list<ParticipantFramePair*> ParticipantFramePairList;
284b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Mix |frame| into |mixed_frame|, with saturation protection and upmixing.
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// These effects are applied to |frame| itself prior to mixing. Assumes that
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// |mixed_frame| always has at least as many channels as |frame|. Supports
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// stereo at most.
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org//
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// TODO(andrew): consider not modifying |frame| here.
35d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.orgvoid MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) {
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(mixed_frame->num_channels_ >= frame->num_channels_);
37d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org  if (use_limiter) {
38d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    // Divide by two to avoid saturation in the mixing.
39d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    // This is only meaningful if the limiter will be used.
40d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    *frame >>= 1;
41d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org  }
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (mixed_frame->num_channels_ > frame->num_channels_) {
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // We only support mono-to-stereo.
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(mixed_frame->num_channels_ == 2 &&
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org           frame->num_channels_ == 1);
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioFrameOperations::MonoToStereo(frame);
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  *mixed_frame += *frame;
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Return the max number of channels from a |list| composed of AudioFrames.
534b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint MaxNumChannels(const AudioFrameList* list) {
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int max_num_channels = 1;
554b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org  for (AudioFrameList::const_iterator iter = list->begin();
564b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org       iter != list->end();
574b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org       ++iter) {
584b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    max_num_channels = std::max(max_num_channels, (*iter)->num_channels_);
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return max_num_channels;
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid SetParticipantStatistics(ParticipantStatistics* stats,
644b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                              const AudioFrame& frame) {
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    stats->participant = frame.id_;
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    stats->level = 0;  // TODO(andrew): to what should this be set?
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgMixerParticipant::MixerParticipant()
724b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    : _mixHistory(new MixHistory()) {
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
754b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgMixerParticipant::~MixerParticipant() {
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    delete _mixHistory;
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
794b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t MixerParticipant::IsMixed(bool& mixed) const {
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _mixHistory->IsMixed(mixed);
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgMixHistory::MixHistory()
844b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    : _isMixed(0) {
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
874b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgMixHistory::~MixHistory() {
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
904b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t MixHistory::IsMixed(bool& mixed) const {
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    mixed = _isMixed;
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
954b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t MixHistory::WasMixed(bool& wasMixed) const {
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Was mixed is the same as is mixed depending on perspective. This function
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // is for the perspective of AudioConferenceMixerImpl.
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return IsMixed(wasMixed);
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1014b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t MixHistory::SetIsMixed(const bool mixed) {
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _isMixed = mixed;
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1064b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgvoid MixHistory::ResetMixedStatus() {
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _isMixed = false;
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1104b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgAudioConferenceMixer* AudioConferenceMixer::Create(int id) {
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioConferenceMixerImpl* mixer = new AudioConferenceMixerImpl(id);
1124b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(!mixer->Init()) {
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete mixer;
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return NULL;
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return mixer;
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioConferenceMixerImpl::AudioConferenceMixerImpl(int id)
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    : _scratchParticipantsToMixAmount(0),
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _scratchMixedParticipants(),
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _scratchVadPositiveParticipantsAmount(0),
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _scratchVadPositiveParticipants(),
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _id(id),
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _minimumMixingFreq(kLowestPossible),
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _mixReceiver(NULL),
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _mixerStatusCallback(NULL),
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _amountOf10MsBetweenCallbacks(1),
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _amountOf10MsUntilNextCallback(0),
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _mixerStatusCb(false),
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _outputFrequency(kDefaultFrequency),
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _sampleSize(0),
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _audioFramePool(NULL),
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _participantList(),
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _additionalParticipantList(),
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _numMixedParticipants(0),
137d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org      use_limiter_(true),
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _timeStamp(0),
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _timeScheduler(kProcessPeriodicityInMs),
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _mixedAudioLevel(),
1414b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org      _processCalls(0) {}
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1434b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgbool AudioConferenceMixerImpl::Init() {
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _crit.reset(CriticalSectionWrapper::CreateCriticalSection());
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_crit.get() == NULL)
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _cbCrit.reset(CriticalSectionWrapper::CreateCriticalSection());
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if(_cbCrit.get() == NULL)
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1524d088c69fbe6659f2e2841b36ff0d0578dc6c51dandrew@webrtc.org    Config config;
1534d088c69fbe6659f2e2841b36ff0d0578dc6c51dandrew@webrtc.org    config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
1544d088c69fbe6659f2e2841b36ff0d0578dc6c51dandrew@webrtc.org    _limiter.reset(AudioProcessing::Create(config));
1554d088c69fbe6659f2e2841b36ff0d0578dc6c51dandrew@webrtc.org    if(!_limiter.get())
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MemoryPool<AudioFrame>::CreateMemoryPool(_audioFramePool,
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                             DEFAULT_AUDIO_FRAME_POOLSIZE);
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if(_audioFramePool == NULL)
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if(SetOutputFrequency(kDefaultFrequency) == -1)
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
166d4682361fd4d284657e4e33ca5f022cc8ea8f468andrew@webrtc.org    if(_limiter->gain_control()->set_mode(GainControl::kFixedDigital) !=
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _limiter->kNoError)
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // divide-by-2 but -7 is used instead to give a bit of headroom since the
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // AGC is not a hard limiter.
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if(_limiter->gain_control()->set_target_level_dbfs(7) != _limiter->kNoError)
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if(_limiter->gain_control()->set_compression_gain_db(0)
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        != _limiter->kNoError)
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if(_limiter->gain_control()->enable_limiter(true) != _limiter->kNoError)
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if(_limiter->gain_control()->Enable(true) != _limiter->kNoError)
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1894b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgAudioConferenceMixerImpl::~AudioConferenceMixerImpl() {
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MemoryPool<AudioFrame>::DeleteMemoryPool(_audioFramePool);
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(_audioFramePool == NULL);
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1944b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t AudioConferenceMixerImpl::ChangeUniqueId(const int32_t id) {
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _id = id;
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Process should be called every kProcessPeriodicityInMs ms
2004b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t AudioConferenceMixerImpl::TimeUntilNextProcess() {
20174f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.org    int32_t timeUntilNextProcess = 0;
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_crit.get());
2034b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(_timeScheduler.TimeToNextUpdate(timeUntilNextProcess) != 0) {
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "failed in TimeToNextUpdate() call");
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Sanity check
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(false);
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return timeUntilNextProcess;
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2134b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t AudioConferenceMixerImpl::Process() {
2144b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    size_t remainingParticipantsAllowedToMix =
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        kMaximumAmountOfMixedParticipants;
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_crit.get());
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(_processCalls == 0);
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _processCalls++;
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Let the scheduler know that we are running one iteration.
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _timeScheduler.UpdateScheduler();
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2254b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList mixList;
2264b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList rampOutList;
2274b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList additionalFramesList;
22852c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org    std::map<int, MixerParticipant*> mixedParticipantsMap;
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_cbCrit.get());
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
23274f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.org        int32_t lowFreq = GetLowestMixingFrequency();
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // SILK can run in 12 kHz and 24 kHz. These frequencies are not
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // supported so use the closest higher frequency to not lose any
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // information.
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // TODO(henrike): this is probably more appropriate to do in
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        //                GetLowestMixingFrequency().
2384b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if (lowFreq == 12000) {
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            lowFreq = 16000;
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        } else if (lowFreq == 24000) {
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            lowFreq = 32000;
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
2434b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(lowFreq <= 0) {
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            CriticalSectionScoped cs(_crit.get());
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _processCalls--;
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return 0;
2474b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        } else {
2484b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            switch(lowFreq) {
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            case 8000:
2504b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                if(OutputFrequency() != kNbInHz) {
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    SetOutputFrequency(kNbInHz);
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                break;
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            case 16000:
2554b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                if(OutputFrequency() != kWbInHz) {
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    SetOutputFrequency(kWbInHz);
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                break;
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            case 32000:
2604b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                if(OutputFrequency() != kSwbInHz) {
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    SetOutputFrequency(kSwbInHz);
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                break;
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            case 48000:
2654b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                if(OutputFrequency() != kFbInHz) {
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    SetOutputFrequency(kFbInHz);
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                break;
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            default:
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                assert(false);
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                CriticalSectionScoped cs(_crit.get());
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _processCalls--;
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                return -1;
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2784b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        UpdateToMix(&mixList, &rampOutList, &mixedParticipantsMap,
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    remainingParticipantsAllowedToMix);
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2814b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        GetAdditionalAudio(&additionalFramesList);
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        UpdateMixedStatus(mixedParticipantsMap);
2834b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        _scratchParticipantsToMixAmount = mixedParticipantsMap.size();
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Get an AudioFrame for mixing from the memory pool.
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioFrame* mixedAudio = NULL;
2884b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(_audioFramePool->PopMemory(mixedAudio) == -1) {
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "failed PopMemory() call");
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(false);
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool timeForMixerCallback = false;
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int retval = 0;
29774f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.org    int32_t audioLevel = 0;
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_crit.get());
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // TODO(henrike): it might be better to decide the number of channels
302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        //                with an API instead of dynamically.
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Find the max channels over all mixing lists.
3054b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        const int num_mixed_channels = std::max(MaxNumChannels(&mixList),
3064b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            std::max(MaxNumChannels(&additionalFramesList),
3074b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                     MaxNumChannels(&rampOutList)));
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        mixedAudio->UpdateFrame(-1, _timeStamp, NULL, 0, _outputFrequency,
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                AudioFrame::kNormalSpeech,
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                AudioFrame::kVadPassive, num_mixed_channels);
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _timeStamp += _sampleSize;
314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
315d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org        // We only use the limiter if it supports the output sample rate and
316d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org        // we're actually mixing multiple streams.
317d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org        use_limiter_ = _numMixedParticipants > 1 &&
318d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                       _outputFrequency <= kAudioProcMaxNativeSampleRateHz;
319d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org
3204b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        MixFromList(*mixedAudio, &mixList);
3214b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        MixAnonomouslyFromList(*mixedAudio, &additionalFramesList);
3224b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        MixAnonomouslyFromList(*mixedAudio, &rampOutList);
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
3244b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(mixedAudio->samples_per_channel_ == 0) {
325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Nothing was mixed, set the audio samples to silence.
326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            mixedAudio->samples_per_channel_ = _sampleSize;
3271dfe1f0671203682bb9358965e37d7500e44a95bandrew@webrtc.org            mixedAudio->Mute();
3284b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        } else {
329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Only call the limiter if we have something to mix.
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if(!LimitMixedAudio(*mixedAudio))
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                retval = -1;
332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixedAudioLevel.ComputeLevel(mixedAudio->data_,_sampleSize);
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        audioLevel = _mixedAudioLevel.GetLevel();
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
3374b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(_mixerStatusCb) {
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _scratchVadPositiveParticipantsAmount = 0;
3394b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            UpdateVADPositiveParticipants(&mixList);
3404b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            if(_amountOf10MsUntilNextCallback-- == 0) {
341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _amountOf10MsUntilNextCallback = _amountOf10MsBetweenCallbacks;
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                timeForMixerCallback = true;
343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_cbCrit.get());
3494b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(_mixReceiver != NULL) {
350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            const AudioFrame** dummy = NULL;
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _mixReceiver->NewMixedAudio(
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _id,
353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                *mixedAudio,
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                dummy,
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                0);
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if((_mixerStatusCallback != NULL) &&
3594b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            timeForMixerCallback) {
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _mixerStatusCallback->MixedParticipants(
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _id,
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _scratchMixedParticipants,
3634b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                static_cast<uint32_t>(_scratchParticipantsToMixAmount));
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _mixerStatusCallback->VADPositiveParticipants(
366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _id,
367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _scratchVadPositiveParticipants,
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _scratchVadPositiveParticipantsAmount);
369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _mixerStatusCallback->MixedAudioLevel(_id,audioLevel);
370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Reclaim all outstanding memory.
374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _audioFramePool->PushMemory(mixedAudio);
3754b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    ClearAudioFrameList(&mixList);
3764b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    ClearAudioFrameList(&rampOutList);
3774b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    ClearAudioFrameList(&additionalFramesList);
378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_crit.get());
380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _processCalls--;
381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return retval;
383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
38574f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::RegisterMixedStreamCallback(
3864b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioMixerOutputReceiver& mixReceiver) {
387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_cbCrit.get());
3884b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(_mixReceiver != NULL) {
389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
390b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _mixReceiver = &mixReceiver;
392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
3954b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t AudioConferenceMixerImpl::UnRegisterMixedStreamCallback() {
396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_cbCrit.get());
3974b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(_mixReceiver == NULL) {
398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _mixReceiver = NULL;
401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
40474f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::SetOutputFrequency(
4054b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    const Frequency frequency) {
406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_crit.get());
407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _outputFrequency = frequency;
409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _sampleSize = (_outputFrequency*kProcessPeriodicityInMs) / 1000;
410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgAudioConferenceMixer::Frequency
4154b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgAudioConferenceMixerImpl::OutputFrequency() const {
416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_crit.get());
417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _outputFrequency;
418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
42074f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::RegisterMixerStatusCallback(
421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioMixerStatusReceiver& mixerStatusCallback,
4224b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    const uint32_t amountOf10MsBetweenCallbacks) {
4234b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(amountOf10MsBetweenCallbacks == 0) {
424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(
425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kTraceWarning,
426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kTraceAudioMixerServer,
427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _id,
428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "amountOf10MsBetweenCallbacks(%d) needs to be larger than 0");
429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_cbCrit.get());
4334b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(_mixerStatusCallback != NULL) {
434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "Mixer status callback already registered");
436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerStatusCallback = &mixerStatusCallback;
439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_crit.get());
442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _amountOf10MsBetweenCallbacks  = amountOf10MsBetweenCallbacks;
443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _amountOf10MsUntilNextCallback = 0;
444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerStatusCb                 = true;
445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
4494b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t AudioConferenceMixerImpl::UnRegisterMixerStatusCallback() {
450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_crit.get());
452b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if(!_mixerStatusCb)
453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "Mixer status callback not registered");
456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerStatusCb = false;
459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_cbCrit.get());
462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _mixerStatusCallback = NULL;
463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
46774f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::SetMixabilityStatus(
468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MixerParticipant& participant,
4694b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    bool mixable) {
4704b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if (!mixable) {
471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Anonymous participants are in a separate list. Make sure that the
472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // participant is in the _participantList if it is being mixed.
473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SetAnonymousMixabilityStatus(participant, false);
474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
4754b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    size_t numMixedParticipants;
476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CriticalSectionScoped cs(_cbCrit.get());
478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        const bool isMixed =
4794b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            IsParticipantInList(participant, &_participantList);
480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // API must be called with a new state.
4814b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(!(mixable ^ isMixed)) {
482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "Mixable is aready %s",
484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         isMixed ? "ON" : "off");
485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        bool success = false;
4884b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(mixable) {
4894b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            success = AddParticipantToList(participant, &_participantList);
4904b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        } else {
4914b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            success = RemoveParticipantFromList(participant, &_participantList);
492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
4934b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(!success) {
494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "failed to %s participant",
496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         mixable ? "add" : "remove");
497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            assert(false);
498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
5014b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        size_t numMixedNonAnonymous = _participantList.size();
5024b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if (numMixedNonAnonymous > kMaximumAmountOfMixedParticipants) {
503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            numMixedNonAnonymous = kMaximumAmountOfMixedParticipants;
504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
5054b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        numMixedParticipants =
5064b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            numMixedNonAnonymous + _additionalParticipantList.size();
507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // A MixerParticipant was added or removed. Make sure the scratch
509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // buffer is updated if necessary.
510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Note: The scratch buffer may only be updated in Process().
511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_crit.get());
512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _numMixedParticipants = numMixedParticipants;
513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
51674f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::MixabilityStatus(
517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MixerParticipant& participant,
5184b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    bool& mixable) {
519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_cbCrit.get());
5204b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    mixable = IsParticipantInList(participant, &_participantList);
521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
52474f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::SetAnonymousMixabilityStatus(
5254b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    MixerParticipant& participant, const bool anonymous) {
526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_cbCrit.get());
5274b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(IsParticipantInList(participant, &_additionalParticipantList)) {
5284b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(anonymous) {
529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return 0;
530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
5314b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(!RemoveParticipantFromList(participant,
5324b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                      &_additionalParticipantList)) {
533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "unable to remove participant from anonymous list");
535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            assert(false);
536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
5384b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        return AddParticipantToList(participant, &_participantList) ? 0 : -1;
539b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
5404b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(!anonymous) {
541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const bool mixable = RemoveParticipantFromList(participant,
5444b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                                   &_participantList);
5454b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(!mixable) {
546b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(
547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kTraceWarning,
548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kTraceAudioMixerServer,
549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _id,
550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "participant must be registered before turning it into anonymous");
551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Setting anonymous status is only possible if MixerParticipant is
552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // already registered.
553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
5554b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    return AddParticipantToList(participant, &_additionalParticipantList) ?
556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        0 : -1;
557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
55974f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::AnonymousMixabilityStatus(
5604b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    MixerParticipant& participant, bool& mixable) {
561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_cbCrit.get());
562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    mixable = IsParticipantInList(participant,
5634b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                  &_additionalParticipantList);
564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
56774f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::SetMinimumMixingFrequency(
5684b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    Frequency freq) {
569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make sure that only allowed sampling frequencies are used. Use closest
570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // higher sampling frequency to avoid losing information.
5714b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if (static_cast<int>(freq) == 12000) {
572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         freq = kWbInHz;
573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    } else if (static_cast<int>(freq) == 24000) {
574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        freq = kSwbInHz;
575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if((freq == kNbInHz) || (freq == kWbInHz) || (freq == kSwbInHz) ||
5784b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org       (freq == kLowestPossible)) {
579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _minimumMixingFreq=freq;
580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
5814b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    } else {
582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "SetMinimumMixingFrequency incorrect frequency: %i",freq);
584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(false);
585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Check all AudioFrames that are to be mixed. The highest sampling frequency
590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// found is the lowest that can be used without losing information.
5914b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgint32_t AudioConferenceMixerImpl::GetLowestMixingFrequency() {
592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const int participantListFrequency =
5934b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        GetLowestMixingFrequencyFromList(&_participantList);
594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const int anonymousListFrequency =
5954b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        GetLowestMixingFrequencyFromList(&_additionalParticipantList);
596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const int highestFreq =
597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        (participantListFrequency > anonymousListFrequency) ?
598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            participantListFrequency : anonymousListFrequency;
599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check if the user specified a lowest mixing frequency.
6004b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(_minimumMixingFreq != kLowestPossible) {
6014b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(_minimumMixingFreq > highestFreq) {
602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return _minimumMixingFreq;
603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return highestFreq;
606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
60874f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::GetLowestMixingFrequencyFromList(
6094b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    MixerParticipantList* mixList) {
61074f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.org    int32_t highestFreq = 8000;
6114b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (MixerParticipantList::iterator iter = mixList->begin();
6124b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != mixList->end();
6134b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
6144b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        const int32_t neededFrequency = (*iter)->NeededFrequency(_id);
6154b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(neededFrequency > highestFreq) {
616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            highestFreq = neededFrequency;
617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return highestFreq;
620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioConferenceMixerImpl::UpdateToMix(
6234b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList* mixList,
6244b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList* rampOutList,
62552c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org    std::map<int, MixerParticipant*>* mixParticipantList,
6264b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    size_t& maxAudioFrameCounter) {
627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "UpdateToMix(mixList,rampOutList,mixParticipantList,%d)",
629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 maxAudioFrameCounter);
6304b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    const size_t mixListStartSize = mixList->size();
6314b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList activeList;
632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Struct needed by the passive lists to keep track of which AudioFrame
633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // belongs to which MixerParticipant.
6344b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    ParticipantFramePairList passiveWasNotMixedList;
6354b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    ParticipantFramePairList passiveWasMixedList;
6364b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (MixerParticipantList::iterator participant = _participantList.begin();
6374b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         participant != _participantList.end();
6384b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++participant) {
639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Stop keeping track of passive participants if there are already
640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // enough participants available (they wont be mixed anyway).
641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        bool mustAddToPassiveList = (maxAudioFrameCounter >
6424b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                    (activeList.size() +
6434b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                     passiveWasMixedList.size() +
6444b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                     passiveWasNotMixedList.size()));
645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        bool wasMixed = false;
6474b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        (*participant)->_mixHistory->WasMixed(wasMixed);
648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        AudioFrame* audioFrame = NULL;
6494b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(_audioFramePool->PopMemory(audioFrame) == -1) {
650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "failed PopMemory() call");
652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            assert(false);
653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return;
654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        audioFrame->sample_rate_hz_ = _outputFrequency;
656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
6574b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if((*participant)->GetAudioFrame(_id,*audioFrame) != 0) {
658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "failed to GetAudioFrame() from participant");
660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _audioFramePool->PushMemory(audioFrame);
661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            continue;
662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
66381f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org        if (_participantList.size() != 1) {
66481f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org          // TODO(wu): Issue 3390, add support for multiple participants case.
66581f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org          audioFrame->ntp_time_ms_ = -1;
66681f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org        }
66781f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org
668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // TODO(henrike): this assert triggers in some test cases where SRTP is
669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // used which prevents NetEQ from making a VAD. Temporarily disable this
670b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // assert until the problem is fixed on a higher level.
671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // assert(audioFrame->vad_activity_ != AudioFrame::kVadUnknown);
6724b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if (audioFrame->vad_activity_ == AudioFrame::kVadUnknown) {
673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "invalid VAD state from participant");
675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
6774b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(audioFrame->vad_activity_ == AudioFrame::kVadActive) {
6784b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            if(!wasMixed) {
679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                RampIn(*audioFrame);
680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
6824b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            if(activeList.size() >= maxAudioFrameCounter) {
683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // There are already more active participants than should be
684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // mixed. Only keep the ones with the highest energy.
6854b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                AudioFrameList::iterator replaceItem;
686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                CalculateEnergy(*audioFrame);
68774f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.org                uint32_t lowestEnergy = audioFrame->energy_;
688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
6894b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                bool found_replace_item = false;
6904b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                for (AudioFrameList::iterator iter = activeList.begin();
6914b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                     iter != activeList.end();
6924b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                     ++iter) {
6934b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                    CalculateEnergy(**iter);
6944b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                    if((*iter)->energy_ < lowestEnergy) {
6954b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                        replaceItem = iter;
6964b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                        lowestEnergy = (*iter)->energy_;
6974b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                        found_replace_item = true;
698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    }
699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
7004b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                if(found_replace_item) {
7014b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                    AudioFrame* replaceFrame = *replaceItem;
702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    bool replaceWasMixed = false;
70452c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                    std::map<int, MixerParticipant*>::iterator it =
70552c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                        mixParticipantList->find(replaceFrame->id_);
70652c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org
707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // When a frame is pushed to |activeList| it is also pushed
708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // to mixParticipantList with the frame's id. This means
709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    // that the Find call above should never fail.
71052c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                    assert(it != mixParticipantList->end());
71152c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                    it->second->_mixHistory->WasMixed(replaceWasMixed);
71252c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org
71352c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                    mixParticipantList->erase(replaceFrame->id_);
7144b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                    activeList.erase(replaceItem);
71552c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org
716be35c5725e0944e40e9ad4de6ca43ec8a0026c79andresp@webrtc.org                    activeList.push_front(audioFrame);
7174b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                    (*mixParticipantList)[audioFrame->id_] = *participant;
71852c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                    assert(mixParticipantList->size() <=
71952c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                           kMaximumAmountOfMixedParticipants);
72052c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org
72152c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                    if (replaceWasMixed) {
72252c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                      RampOut(*replaceFrame);
7234b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                      rampOutList->push_back(replaceFrame);
7244b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                      assert(rampOutList->size() <=
72552c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                             kMaximumAmountOfMixedParticipants);
726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    } else {
72752c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                      _audioFramePool->PushMemory(replaceFrame);
728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    }
729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                } else {
7304b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                    if(wasMixed) {
731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        RampOut(*audioFrame);
7324b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                        rampOutList->push_back(audioFrame);
7334b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                        assert(rampOutList->size() <=
734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                               kMaximumAmountOfMixedParticipants);
735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    } else {
736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        _audioFramePool->PushMemory(audioFrame);
737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    }
738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else {
7404b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                activeList.push_front(audioFrame);
7414b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                (*mixParticipantList)[audioFrame->id_] = *participant;
74252c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                assert(mixParticipantList->size() <=
743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                       kMaximumAmountOfMixedParticipants);
744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        } else {
7464b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            if(wasMixed) {
747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                ParticipantFramePair* pair = new ParticipantFramePair;
748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                pair->audioFrame  = audioFrame;
7494b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                pair->participant = *participant;
7504b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                passiveWasMixedList.push_back(pair);
751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else if(mustAddToPassiveList) {
752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                RampIn(*audioFrame);
753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                ParticipantFramePair* pair = new ParticipantFramePair;
754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                pair->audioFrame  = audioFrame;
7554b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                pair->participant = *participant;
7564b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                passiveWasNotMixedList.push_back(pair);
757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            } else {
758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _audioFramePool->PushMemory(audioFrame);
759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
7624b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    assert(activeList.size() <= maxAudioFrameCounter);
763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // At this point it is known which participants should be mixed. Transfer
764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // this information to this functions output parameters.
7654b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (AudioFrameList::iterator iter = activeList.begin();
7664b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != activeList.end();
7674b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
7684b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        mixList->push_back(*iter);
769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
7704b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    activeList.clear();
771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Always mix a constant number of AudioFrames. If there aren't enough
772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // active participants mix passive ones. Starting with those that was mixed
773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // last iteration.
7744b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (ParticipantFramePairList::iterator iter = passiveWasMixedList.begin();
7754b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != passiveWasMixedList.end();
7764b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
7774b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(mixList->size() < maxAudioFrameCounter + mixListStartSize) {
7784b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            mixList->push_back((*iter)->audioFrame);
7794b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            (*mixParticipantList)[(*iter)->audioFrame->id_] =
7804b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                (*iter)->participant;
78152c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org            assert(mixParticipantList->size() <=
782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   kMaximumAmountOfMixedParticipants);
7834b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        } else {
7844b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            _audioFramePool->PushMemory((*iter)->audioFrame);
785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
7864b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        delete *iter;
787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // And finally the ones that have not been mixed for a while.
7894b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (ParticipantFramePairList::iterator iter =
7904b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org             passiveWasNotMixedList.begin();
7914b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != passiveWasNotMixedList.end();
7924b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
7934b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(mixList->size() <  maxAudioFrameCounter + mixListStartSize) {
7944b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org          mixList->push_back((*iter)->audioFrame);
7954b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            (*mixParticipantList)[(*iter)->audioFrame->id_] =
7964b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                (*iter)->participant;
79752c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org            assert(mixParticipantList->size() <=
798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   kMaximumAmountOfMixedParticipants);
7994b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        } else {
8004b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            _audioFramePool->PushMemory((*iter)->audioFrame);
801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
8024b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        delete *iter;
803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
8044b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    assert(maxAudioFrameCounter + mixListStartSize >= mixList->size());
8054b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    maxAudioFrameCounter += mixListStartSize - mixList->size();
806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioConferenceMixerImpl::GetAdditionalAudio(
8094b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList* additionalFramesList) {
810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "GetAdditionalAudio(additionalFramesList)");
8124b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    // The GetAudioFrame() callback may result in the participant being removed
8134b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    // from additionalParticipantList_. If that happens it will invalidate any
8144b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    // iterators. Create a copy of the participants list such that the list of
8154b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    // participants can be traversed safely.
8164b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    MixerParticipantList additionalParticipantList;
8174b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    additionalParticipantList.insert(additionalParticipantList.begin(),
8184b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                     _additionalParticipantList.begin(),
8194b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                     _additionalParticipantList.end());
8204b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org
8214b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (MixerParticipantList::iterator participant =
8224b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org             additionalParticipantList.begin();
8234b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         participant != additionalParticipantList.end();
8244b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++participant) {
825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        AudioFrame* audioFrame = NULL;
8264b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(_audioFramePool->PopMemory(audioFrame) == -1) {
827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "failed PopMemory() call");
829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            assert(false);
830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return;
831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        audioFrame->sample_rate_hz_ = _outputFrequency;
8334b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if((*participant)->GetAudioFrame(_id, *audioFrame) != 0) {
834b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "failed to GetAudioFrame() from participant");
836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _audioFramePool->PushMemory(audioFrame);
837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            continue;
838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
8394b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(audioFrame->samples_per_channel_ == 0) {
840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Empty frame. Don't use it.
841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _audioFramePool->PushMemory(audioFrame);
842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            continue;
843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
8444b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        additionalFramesList->push_back(audioFrame);
845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
847b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioConferenceMixerImpl::UpdateMixedStatus(
8494b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    std::map<int, MixerParticipant*>& mixedParticipantsMap) {
850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "UpdateMixedStatus(mixedParticipantsMap)");
85252c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org    assert(mixedParticipantsMap.size() <= kMaximumAmountOfMixedParticipants);
853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Loop through all participants. If they are in the mix map they
855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // were mixed.
8564b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (MixerParticipantList::iterator participant = _participantList.begin();
8574b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         participant != _participantList.end();
8584b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++participant) {
859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        bool isMixed = false;
86052c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org        for (std::map<int, MixerParticipant*>::iterator it =
86152c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                 mixedParticipantsMap.begin();
86252c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org             it != mixedParticipantsMap.end();
86352c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org             ++it) {
8644b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org          if (it->second == *participant) {
86552c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org            isMixed = true;
86652c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org            break;
86752c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org          }
868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
8694b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        (*participant)->_mixHistory->SetIsMixed(isMixed);
870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
8734b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgvoid AudioConferenceMixerImpl::ClearAudioFrameList(
8744b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList* audioFrameList) {
875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "ClearAudioFrameList(audioFrameList)");
8774b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (AudioFrameList::iterator iter = audioFrameList->begin();
8784b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != audioFrameList->end();
8794b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
8804b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        _audioFramePool->PushMemory(*iter);
881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
8824b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    audioFrameList->clear();
883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
885b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AudioConferenceMixerImpl::UpdateVADPositiveParticipants(
8864b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    AudioFrameList* mixList) {
887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "UpdateVADPositiveParticipants(mixList)");
889b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
8904b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (AudioFrameList::iterator iter = mixList->begin();
8914b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != mixList->end();
8924b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
8934b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        CalculateEnergy(**iter);
8944b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if((*iter)->vad_activity_ == AudioFrame::kVadActive) {
895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _scratchVadPositiveParticipants[
896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _scratchVadPositiveParticipantsAmount].participant =
8974b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                (*iter)->id_;
898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // TODO(andrew): to what should this be set?
899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _scratchVadPositiveParticipants[
900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _scratchVadPositiveParticipantsAmount].level = 0;
901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _scratchVadPositiveParticipantsAmount++;
902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioConferenceMixerImpl::IsParticipantInList(
907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MixerParticipant& participant,
9084b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    MixerParticipantList* participantList) const {
909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "IsParticipantInList(participant,participantList)");
9114b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (MixerParticipantList::const_iterator iter = participantList->begin();
9124b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != participantList->end();
9134b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
9144b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(&participant == *iter) {
915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return true;
916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return false;
919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioConferenceMixerImpl::AddParticipantToList(
922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MixerParticipant& participant,
9234b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    MixerParticipantList* participantList) {
924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "AddParticipantToList(participant, participantList)");
9264b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    participantList->push_back(&participant);
927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make sure that the mixed status is correct for new MixerParticipant.
928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    participant._mixHistory->ResetMixedStatus();
929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool AudioConferenceMixerImpl::RemoveParticipantFromList(
933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MixerParticipant& participant,
9344b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    MixerParticipantList* participantList) {
935b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "RemoveParticipantFromList(participant, participantList)");
9374b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (MixerParticipantList::iterator iter = participantList->begin();
9384b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != participantList->end();
9394b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
9404b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(*iter == &participant) {
9414b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org            participantList->erase(iter);
942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Participant is no longer mixed, reset to default.
943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            participant._mixHistory->ResetMixedStatus();
944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return true;
945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return false;
948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
95074f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::MixFromList(
951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioFrame& mixedAudio,
9524b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    const AudioFrameList* audioFrameList) {
953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "MixFromList(mixedAudio, audioFrameList)");
9554b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(audioFrameList->empty()) return 0;
956b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
9574b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    uint32_t position = 0;
958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
9599ae7d44896eeb88cb5dd4a7baf805607436ce7e0wu@webrtc.org    if (_numMixedParticipants == 1) {
96081f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org      mixedAudio.timestamp_ = audioFrameList->front()->timestamp_;
96181f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org      mixedAudio.elapsed_time_ms_ = audioFrameList->front()->elapsed_time_ms_;
96281f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org    } else {
96381f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org      // TODO(wu): Issue 3390.
96481f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org      // Audio frame timestamp is only supported in one channel case.
96581f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org      mixedAudio.timestamp_ = 0;
96681f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org      mixedAudio.elapsed_time_ms_ = -1;
96781f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org    }
96881f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org
9694b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (AudioFrameList::const_iterator iter = audioFrameList->begin();
9704b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != audioFrameList->end();
9714b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
9724b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org        if(position >= kMaximumAmountOfMixedParticipants) {
973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(
974b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                kTraceMemory,
975b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                kTraceAudioMixerServer,
976b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _id,
977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "Trying to mix more than max amount of mixed participants:%d!",
978b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                kMaximumAmountOfMixedParticipants);
979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Assert and avoid crash
980b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            assert(false);
981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            position = 0;
982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
983d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org        MixFrames(&mixedAudio, (*iter), use_limiter_);
984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
985b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        SetParticipantStatistics(&_scratchMixedParticipants[position],
9864b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org                                 **iter);
987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        position++;
989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// TODO(andrew): consolidate this function with MixFromList.
99574f9bbbf9efe39e1f7df99aa7d6cb02d57978a5cpbos@webrtc.orgint32_t AudioConferenceMixerImpl::MixAnonomouslyFromList(
996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AudioFrame& mixedAudio,
9974b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    const AudioFrameList* audioFrameList) {
998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
999b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "MixAnonomouslyFromList(mixedAudio, audioFrameList)");
1000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
10014b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(audioFrameList->empty()) return 0;
10024b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org
10034b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    for (AudioFrameList::const_iterator iter = audioFrameList->begin();
10044b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         iter != audioFrameList->end();
10054b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org         ++iter) {
1006d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org        MixFrames(&mixedAudio, *iter, use_limiter_);
1007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
1009b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
10114b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.orgbool AudioConferenceMixerImpl::LimitMixedAudio(AudioFrame& mixedAudio) {
1012d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    if (!use_limiter_) {
1013d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org      return true;
1014b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1015b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1016b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Smoothly limit the mixed frame.
1017b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const int error = _limiter->ProcessStream(&mixedAudio);
1018b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1019b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // And now we can safely restore the level. This procedure results in
1020b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // some loss of resolution, deemed acceptable.
1021b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
1022b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // It's possible to apply the gain in the AGC (with a target level of 0 dbFS
1023b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // and compression gain of 6 dB). However, in the transition frame when this
1024b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // is enabled (moving from one to two participants) it has the potential to
1025b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // create discontinuities in the mixed frame.
1026b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
1027b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Instead we double the frame (with addition since left-shifting a
1028b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // negative value is undefined).
1029b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    mixedAudio += mixedAudio;
1030b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
10314b5d36e064828ce9140b2b36c9210305effa01f9henrike@webrtc.org    if(error != _limiter->kNoError) {
1032b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
1033b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Error from AudioProcessing: %d", error);
1034b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        assert(false);
1035b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
1036b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1037b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
1038b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
10393b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org}  // namespace webrtc
1040