• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "webrtc/modules/audio_conference_mixer/interface/audio_conference_mixer_defines.h"
12 #include "webrtc/modules/audio_conference_mixer/source/audio_conference_mixer_impl.h"
13 #include "webrtc/modules/audio_conference_mixer/source/audio_frame_manipulator.h"
14 #include "webrtc/modules/audio_processing/include/audio_processing.h"
15 #include "webrtc/modules/utility/interface/audio_frame_operations.h"
16 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
17 #include "webrtc/system_wrappers/interface/trace.h"
18 
19 namespace webrtc {
20 namespace {
21 
22 struct ParticipantFramePair {
23   MixerParticipant* participant;
24   AudioFrame* audioFrame;
25 };
26 
27 typedef std::list<ParticipantFramePair*> ParticipantFramePairList;
28 
29 // Mix |frame| into |mixed_frame|, with saturation protection and upmixing.
30 // These effects are applied to |frame| itself prior to mixing. Assumes that
31 // |mixed_frame| always has at least as many channels as |frame|. Supports
32 // stereo at most.
33 //
34 // TODO(andrew): consider not modifying |frame| here.
MixFrames(AudioFrame * mixed_frame,AudioFrame * frame)35 void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame) {
36   assert(mixed_frame->num_channels_ >= frame->num_channels_);
37   // Divide by two to avoid saturation in the mixing.
38   *frame >>= 1;
39   if (mixed_frame->num_channels_ > frame->num_channels_) {
40     // We only support mono-to-stereo.
41     assert(mixed_frame->num_channels_ == 2 &&
42            frame->num_channels_ == 1);
43     AudioFrameOperations::MonoToStereo(frame);
44   }
45 
46   *mixed_frame += *frame;
47 }
48 
49 // Return the max number of channels from a |list| composed of AudioFrames.
MaxNumChannels(const AudioFrameList * list)50 int MaxNumChannels(const AudioFrameList* list) {
51   int max_num_channels = 1;
52   for (AudioFrameList::const_iterator iter = list->begin();
53        iter != list->end();
54        ++iter) {
55     max_num_channels = std::max(max_num_channels, (*iter)->num_channels_);
56   }
57   return max_num_channels;
58 }
59 
SetParticipantStatistics(ParticipantStatistics * stats,const AudioFrame & frame)60 void SetParticipantStatistics(ParticipantStatistics* stats,
61                               const AudioFrame& frame) {
62     stats->participant = frame.id_;
63     stats->level = 0;  // TODO(andrew): to what should this be set?
64 }
65 
66 }  // namespace
67 
MixerParticipant()68 MixerParticipant::MixerParticipant()
69     : _mixHistory(new MixHistory()) {
70 }
71 
~MixerParticipant()72 MixerParticipant::~MixerParticipant() {
73     delete _mixHistory;
74 }
75 
IsMixed(bool & mixed) const76 int32_t MixerParticipant::IsMixed(bool& mixed) const {
77     return _mixHistory->IsMixed(mixed);
78 }
79 
MixHistory()80 MixHistory::MixHistory()
81     : _isMixed(0) {
82 }
83 
~MixHistory()84 MixHistory::~MixHistory() {
85 }
86 
IsMixed(bool & mixed) const87 int32_t MixHistory::IsMixed(bool& mixed) const {
88     mixed = _isMixed;
89     return 0;
90 }
91 
WasMixed(bool & wasMixed) const92 int32_t MixHistory::WasMixed(bool& wasMixed) const {
93     // Was mixed is the same as is mixed depending on perspective. This function
94     // is for the perspective of AudioConferenceMixerImpl.
95     return IsMixed(wasMixed);
96 }
97 
SetIsMixed(const bool mixed)98 int32_t MixHistory::SetIsMixed(const bool mixed) {
99     _isMixed = mixed;
100     return 0;
101 }
102 
ResetMixedStatus()103 void MixHistory::ResetMixedStatus() {
104     _isMixed = false;
105 }
106 
Create(int id)107 AudioConferenceMixer* AudioConferenceMixer::Create(int id) {
108     AudioConferenceMixerImpl* mixer = new AudioConferenceMixerImpl(id);
109     if(!mixer->Init()) {
110         delete mixer;
111         return NULL;
112     }
113     return mixer;
114 }
115 
AudioConferenceMixerImpl(int id)116 AudioConferenceMixerImpl::AudioConferenceMixerImpl(int id)
117     : _scratchParticipantsToMixAmount(0),
118       _scratchMixedParticipants(),
119       _scratchVadPositiveParticipantsAmount(0),
120       _scratchVadPositiveParticipants(),
121       _id(id),
122       _minimumMixingFreq(kLowestPossible),
123       _mixReceiver(NULL),
124       _mixerStatusCallback(NULL),
125       _amountOf10MsBetweenCallbacks(1),
126       _amountOf10MsUntilNextCallback(0),
127       _mixerStatusCb(false),
128       _outputFrequency(kDefaultFrequency),
129       _sampleSize(0),
130       _audioFramePool(NULL),
131       _participantList(),
132       _additionalParticipantList(),
133       _numMixedParticipants(0),
134       _timeStamp(0),
135       _timeScheduler(kProcessPeriodicityInMs),
136       _mixedAudioLevel(),
137       _processCalls(0) {}
138 
Init()139 bool AudioConferenceMixerImpl::Init() {
140     _crit.reset(CriticalSectionWrapper::CreateCriticalSection());
141     if (_crit.get() == NULL)
142         return false;
143 
144     _cbCrit.reset(CriticalSectionWrapper::CreateCriticalSection());
145     if(_cbCrit.get() == NULL)
146         return false;
147 
148     Config config;
149     config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
150     _limiter.reset(AudioProcessing::Create(config));
151     if(!_limiter.get())
152         return false;
153 
154     MemoryPool<AudioFrame>::CreateMemoryPool(_audioFramePool,
155                                              DEFAULT_AUDIO_FRAME_POOLSIZE);
156     if(_audioFramePool == NULL)
157         return false;
158 
159     if(SetOutputFrequency(kDefaultFrequency) == -1)
160         return false;
161 
162     if(_limiter->gain_control()->set_mode(GainControl::kFixedDigital) !=
163         _limiter->kNoError)
164         return false;
165 
166     // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the
167     // divide-by-2 but -7 is used instead to give a bit of headroom since the
168     // AGC is not a hard limiter.
169     if(_limiter->gain_control()->set_target_level_dbfs(7) != _limiter->kNoError)
170         return false;
171 
172     if(_limiter->gain_control()->set_compression_gain_db(0)
173         != _limiter->kNoError)
174         return false;
175 
176     if(_limiter->gain_control()->enable_limiter(true) != _limiter->kNoError)
177         return false;
178 
179     if(_limiter->gain_control()->Enable(true) != _limiter->kNoError)
180         return false;
181 
182     return true;
183 }
184 
~AudioConferenceMixerImpl()185 AudioConferenceMixerImpl::~AudioConferenceMixerImpl() {
186     MemoryPool<AudioFrame>::DeleteMemoryPool(_audioFramePool);
187     assert(_audioFramePool == NULL);
188 }
189 
ChangeUniqueId(const int32_t id)190 int32_t AudioConferenceMixerImpl::ChangeUniqueId(const int32_t id) {
191     _id = id;
192     return 0;
193 }
194 
195 // Process should be called every kProcessPeriodicityInMs ms
TimeUntilNextProcess()196 int32_t AudioConferenceMixerImpl::TimeUntilNextProcess() {
197     int32_t timeUntilNextProcess = 0;
198     CriticalSectionScoped cs(_crit.get());
199     if(_timeScheduler.TimeToNextUpdate(timeUntilNextProcess) != 0) {
200         WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
201                      "failed in TimeToNextUpdate() call");
202         // Sanity check
203         assert(false);
204         return -1;
205     }
206     return timeUntilNextProcess;
207 }
208 
Process()209 int32_t AudioConferenceMixerImpl::Process() {
210     size_t remainingParticipantsAllowedToMix =
211         kMaximumAmountOfMixedParticipants;
212     {
213         CriticalSectionScoped cs(_crit.get());
214         assert(_processCalls == 0);
215         _processCalls++;
216 
217         // Let the scheduler know that we are running one iteration.
218         _timeScheduler.UpdateScheduler();
219     }
220 
221     AudioFrameList mixList;
222     AudioFrameList rampOutList;
223     AudioFrameList additionalFramesList;
224     std::map<int, MixerParticipant*> mixedParticipantsMap;
225     {
226         CriticalSectionScoped cs(_cbCrit.get());
227 
228         int32_t lowFreq = GetLowestMixingFrequency();
229         // SILK can run in 12 kHz and 24 kHz. These frequencies are not
230         // supported so use the closest higher frequency to not lose any
231         // information.
232         // TODO(henrike): this is probably more appropriate to do in
233         //                GetLowestMixingFrequency().
234         if (lowFreq == 12000) {
235             lowFreq = 16000;
236         } else if (lowFreq == 24000) {
237             lowFreq = 32000;
238         }
239         if(lowFreq <= 0) {
240             CriticalSectionScoped cs(_crit.get());
241             _processCalls--;
242             return 0;
243         } else {
244             switch(lowFreq) {
245             case 8000:
246                 if(OutputFrequency() != kNbInHz) {
247                     SetOutputFrequency(kNbInHz);
248                 }
249                 break;
250             case 16000:
251                 if(OutputFrequency() != kWbInHz) {
252                     SetOutputFrequency(kWbInHz);
253                 }
254                 break;
255             case 32000:
256                 if(OutputFrequency() != kSwbInHz) {
257                     SetOutputFrequency(kSwbInHz);
258                 }
259                 break;
260             case 48000:
261                 if(OutputFrequency() != kFbInHz) {
262                     SetOutputFrequency(kFbInHz);
263                 }
264                 break;
265             default:
266                 assert(false);
267 
268                 CriticalSectionScoped cs(_crit.get());
269                 _processCalls--;
270                 return -1;
271             }
272         }
273 
274         UpdateToMix(&mixList, &rampOutList, &mixedParticipantsMap,
275                     remainingParticipantsAllowedToMix);
276 
277         GetAdditionalAudio(&additionalFramesList);
278         UpdateMixedStatus(mixedParticipantsMap);
279         _scratchParticipantsToMixAmount = mixedParticipantsMap.size();
280     }
281 
282     // Get an AudioFrame for mixing from the memory pool.
283     AudioFrame* mixedAudio = NULL;
284     if(_audioFramePool->PopMemory(mixedAudio) == -1) {
285         WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
286                      "failed PopMemory() call");
287         assert(false);
288         return -1;
289     }
290 
291     bool timeForMixerCallback = false;
292     int retval = 0;
293     int32_t audioLevel = 0;
294     {
295         CriticalSectionScoped cs(_crit.get());
296 
297         // TODO(henrike): it might be better to decide the number of channels
298         //                with an API instead of dynamically.
299 
300         // Find the max channels over all mixing lists.
301         const int num_mixed_channels = std::max(MaxNumChannels(&mixList),
302             std::max(MaxNumChannels(&additionalFramesList),
303                      MaxNumChannels(&rampOutList)));
304 
305         mixedAudio->UpdateFrame(-1, _timeStamp, NULL, 0, _outputFrequency,
306                                 AudioFrame::kNormalSpeech,
307                                 AudioFrame::kVadPassive, num_mixed_channels);
308 
309         _timeStamp += _sampleSize;
310 
311         MixFromList(*mixedAudio, &mixList);
312         MixAnonomouslyFromList(*mixedAudio, &additionalFramesList);
313         MixAnonomouslyFromList(*mixedAudio, &rampOutList);
314 
315         if(mixedAudio->samples_per_channel_ == 0) {
316             // Nothing was mixed, set the audio samples to silence.
317             mixedAudio->samples_per_channel_ = _sampleSize;
318             mixedAudio->Mute();
319         } else {
320             // Only call the limiter if we have something to mix.
321             if(!LimitMixedAudio(*mixedAudio))
322                 retval = -1;
323         }
324 
325         _mixedAudioLevel.ComputeLevel(mixedAudio->data_,_sampleSize);
326         audioLevel = _mixedAudioLevel.GetLevel();
327 
328         if(_mixerStatusCb) {
329             _scratchVadPositiveParticipantsAmount = 0;
330             UpdateVADPositiveParticipants(&mixList);
331             if(_amountOf10MsUntilNextCallback-- == 0) {
332                 _amountOf10MsUntilNextCallback = _amountOf10MsBetweenCallbacks;
333                 timeForMixerCallback = true;
334             }
335         }
336     }
337 
338     {
339         CriticalSectionScoped cs(_cbCrit.get());
340         if(_mixReceiver != NULL) {
341             const AudioFrame** dummy = NULL;
342             _mixReceiver->NewMixedAudio(
343                 _id,
344                 *mixedAudio,
345                 dummy,
346                 0);
347         }
348 
349         if((_mixerStatusCallback != NULL) &&
350             timeForMixerCallback) {
351             _mixerStatusCallback->MixedParticipants(
352                 _id,
353                 _scratchMixedParticipants,
354                 static_cast<uint32_t>(_scratchParticipantsToMixAmount));
355 
356             _mixerStatusCallback->VADPositiveParticipants(
357                 _id,
358                 _scratchVadPositiveParticipants,
359                 _scratchVadPositiveParticipantsAmount);
360             _mixerStatusCallback->MixedAudioLevel(_id,audioLevel);
361         }
362     }
363 
364     // Reclaim all outstanding memory.
365     _audioFramePool->PushMemory(mixedAudio);
366     ClearAudioFrameList(&mixList);
367     ClearAudioFrameList(&rampOutList);
368     ClearAudioFrameList(&additionalFramesList);
369     {
370         CriticalSectionScoped cs(_crit.get());
371         _processCalls--;
372     }
373     return retval;
374 }
375 
RegisterMixedStreamCallback(AudioMixerOutputReceiver & mixReceiver)376 int32_t AudioConferenceMixerImpl::RegisterMixedStreamCallback(
377     AudioMixerOutputReceiver& mixReceiver) {
378     CriticalSectionScoped cs(_cbCrit.get());
379     if(_mixReceiver != NULL) {
380         return -1;
381     }
382     _mixReceiver = &mixReceiver;
383     return 0;
384 }
385 
UnRegisterMixedStreamCallback()386 int32_t AudioConferenceMixerImpl::UnRegisterMixedStreamCallback() {
387     CriticalSectionScoped cs(_cbCrit.get());
388     if(_mixReceiver == NULL) {
389         return -1;
390     }
391     _mixReceiver = NULL;
392     return 0;
393 }
394 
SetOutputFrequency(const Frequency frequency)395 int32_t AudioConferenceMixerImpl::SetOutputFrequency(
396     const Frequency frequency) {
397     CriticalSectionScoped cs(_crit.get());
398 
399     _outputFrequency = frequency;
400     _sampleSize = (_outputFrequency*kProcessPeriodicityInMs) / 1000;
401 
402     return 0;
403 }
404 
405 AudioConferenceMixer::Frequency
OutputFrequency() const406 AudioConferenceMixerImpl::OutputFrequency() const {
407     CriticalSectionScoped cs(_crit.get());
408     return _outputFrequency;
409 }
410 
RegisterMixerStatusCallback(AudioMixerStatusReceiver & mixerStatusCallback,const uint32_t amountOf10MsBetweenCallbacks)411 int32_t AudioConferenceMixerImpl::RegisterMixerStatusCallback(
412     AudioMixerStatusReceiver& mixerStatusCallback,
413     const uint32_t amountOf10MsBetweenCallbacks) {
414     if(amountOf10MsBetweenCallbacks == 0) {
415         WEBRTC_TRACE(
416             kTraceWarning,
417             kTraceAudioMixerServer,
418             _id,
419             "amountOf10MsBetweenCallbacks(%d) needs to be larger than 0");
420         return -1;
421     }
422     {
423         CriticalSectionScoped cs(_cbCrit.get());
424         if(_mixerStatusCallback != NULL) {
425             WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
426                          "Mixer status callback already registered");
427             return -1;
428         }
429         _mixerStatusCallback = &mixerStatusCallback;
430     }
431     {
432         CriticalSectionScoped cs(_crit.get());
433         _amountOf10MsBetweenCallbacks  = amountOf10MsBetweenCallbacks;
434         _amountOf10MsUntilNextCallback = 0;
435         _mixerStatusCb                 = true;
436     }
437     return 0;
438 }
439 
UnRegisterMixerStatusCallback()440 int32_t AudioConferenceMixerImpl::UnRegisterMixerStatusCallback() {
441     {
442         CriticalSectionScoped cs(_crit.get());
443         if(!_mixerStatusCb)
444         {
445             WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
446                          "Mixer status callback not registered");
447             return -1;
448         }
449         _mixerStatusCb = false;
450     }
451     {
452         CriticalSectionScoped cs(_cbCrit.get());
453         _mixerStatusCallback = NULL;
454     }
455     return 0;
456 }
457 
SetMixabilityStatus(MixerParticipant & participant,bool mixable)458 int32_t AudioConferenceMixerImpl::SetMixabilityStatus(
459     MixerParticipant& participant,
460     bool mixable) {
461     if (!mixable) {
462         // Anonymous participants are in a separate list. Make sure that the
463         // participant is in the _participantList if it is being mixed.
464         SetAnonymousMixabilityStatus(participant, false);
465     }
466     size_t numMixedParticipants;
467     {
468         CriticalSectionScoped cs(_cbCrit.get());
469         const bool isMixed =
470             IsParticipantInList(participant, &_participantList);
471         // API must be called with a new state.
472         if(!(mixable ^ isMixed)) {
473             WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
474                          "Mixable is aready %s",
475                          isMixed ? "ON" : "off");
476             return -1;
477         }
478         bool success = false;
479         if(mixable) {
480             success = AddParticipantToList(participant, &_participantList);
481         } else {
482             success = RemoveParticipantFromList(participant, &_participantList);
483         }
484         if(!success) {
485             WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
486                          "failed to %s participant",
487                          mixable ? "add" : "remove");
488             assert(false);
489             return -1;
490         }
491 
492         size_t numMixedNonAnonymous = _participantList.size();
493         if (numMixedNonAnonymous > kMaximumAmountOfMixedParticipants) {
494             numMixedNonAnonymous = kMaximumAmountOfMixedParticipants;
495         }
496         numMixedParticipants =
497             numMixedNonAnonymous + _additionalParticipantList.size();
498     }
499     // A MixerParticipant was added or removed. Make sure the scratch
500     // buffer is updated if necessary.
501     // Note: The scratch buffer may only be updated in Process().
502     CriticalSectionScoped cs(_crit.get());
503     _numMixedParticipants = numMixedParticipants;
504     return 0;
505 }
506 
MixabilityStatus(MixerParticipant & participant,bool & mixable)507 int32_t AudioConferenceMixerImpl::MixabilityStatus(
508     MixerParticipant& participant,
509     bool& mixable) {
510     CriticalSectionScoped cs(_cbCrit.get());
511     mixable = IsParticipantInList(participant, &_participantList);
512     return 0;
513 }
514 
SetAnonymousMixabilityStatus(MixerParticipant & participant,const bool anonymous)515 int32_t AudioConferenceMixerImpl::SetAnonymousMixabilityStatus(
516     MixerParticipant& participant, const bool anonymous) {
517     CriticalSectionScoped cs(_cbCrit.get());
518     if(IsParticipantInList(participant, &_additionalParticipantList)) {
519         if(anonymous) {
520             return 0;
521         }
522         if(!RemoveParticipantFromList(participant,
523                                       &_additionalParticipantList)) {
524             WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
525                          "unable to remove participant from anonymous list");
526             assert(false);
527             return -1;
528         }
529         return AddParticipantToList(participant, &_participantList) ? 0 : -1;
530     }
531     if(!anonymous) {
532         return 0;
533     }
534     const bool mixable = RemoveParticipantFromList(participant,
535                                                    &_participantList);
536     if(!mixable) {
537         WEBRTC_TRACE(
538             kTraceWarning,
539             kTraceAudioMixerServer,
540             _id,
541             "participant must be registered before turning it into anonymous");
542         // Setting anonymous status is only possible if MixerParticipant is
543         // already registered.
544         return -1;
545     }
546     return AddParticipantToList(participant, &_additionalParticipantList) ?
547         0 : -1;
548 }
549 
AnonymousMixabilityStatus(MixerParticipant & participant,bool & mixable)550 int32_t AudioConferenceMixerImpl::AnonymousMixabilityStatus(
551     MixerParticipant& participant, bool& mixable) {
552     CriticalSectionScoped cs(_cbCrit.get());
553     mixable = IsParticipantInList(participant,
554                                   &_additionalParticipantList);
555     return 0;
556 }
557 
SetMinimumMixingFrequency(Frequency freq)558 int32_t AudioConferenceMixerImpl::SetMinimumMixingFrequency(
559     Frequency freq) {
560     // Make sure that only allowed sampling frequencies are used. Use closest
561     // higher sampling frequency to avoid losing information.
562     if (static_cast<int>(freq) == 12000) {
563          freq = kWbInHz;
564     } else if (static_cast<int>(freq) == 24000) {
565         freq = kSwbInHz;
566     }
567 
568     if((freq == kNbInHz) || (freq == kWbInHz) || (freq == kSwbInHz) ||
569        (freq == kLowestPossible)) {
570         _minimumMixingFreq=freq;
571         return 0;
572     } else {
573         WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
574                      "SetMinimumMixingFrequency incorrect frequency: %i",freq);
575         assert(false);
576         return -1;
577     }
578 }
579 
580 // Check all AudioFrames that are to be mixed. The highest sampling frequency
581 // found is the lowest that can be used without losing information.
GetLowestMixingFrequency()582 int32_t AudioConferenceMixerImpl::GetLowestMixingFrequency() {
583     const int participantListFrequency =
584         GetLowestMixingFrequencyFromList(&_participantList);
585     const int anonymousListFrequency =
586         GetLowestMixingFrequencyFromList(&_additionalParticipantList);
587     const int highestFreq =
588         (participantListFrequency > anonymousListFrequency) ?
589             participantListFrequency : anonymousListFrequency;
590     // Check if the user specified a lowest mixing frequency.
591     if(_minimumMixingFreq != kLowestPossible) {
592         if(_minimumMixingFreq > highestFreq) {
593             return _minimumMixingFreq;
594         }
595     }
596     return highestFreq;
597 }
598 
GetLowestMixingFrequencyFromList(MixerParticipantList * mixList)599 int32_t AudioConferenceMixerImpl::GetLowestMixingFrequencyFromList(
600     MixerParticipantList* mixList) {
601     int32_t highestFreq = 8000;
602     for (MixerParticipantList::iterator iter = mixList->begin();
603          iter != mixList->end();
604          ++iter) {
605         const int32_t neededFrequency = (*iter)->NeededFrequency(_id);
606         if(neededFrequency > highestFreq) {
607             highestFreq = neededFrequency;
608         }
609     }
610     return highestFreq;
611 }
612 
UpdateToMix(AudioFrameList * mixList,AudioFrameList * rampOutList,std::map<int,MixerParticipant * > * mixParticipantList,size_t & maxAudioFrameCounter)613 void AudioConferenceMixerImpl::UpdateToMix(
614     AudioFrameList* mixList,
615     AudioFrameList* rampOutList,
616     std::map<int, MixerParticipant*>* mixParticipantList,
617     size_t& maxAudioFrameCounter) {
618     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
619                  "UpdateToMix(mixList,rampOutList,mixParticipantList,%d)",
620                  maxAudioFrameCounter);
621     const size_t mixListStartSize = mixList->size();
622     AudioFrameList activeList;
623     // Struct needed by the passive lists to keep track of which AudioFrame
624     // belongs to which MixerParticipant.
625     ParticipantFramePairList passiveWasNotMixedList;
626     ParticipantFramePairList passiveWasMixedList;
627     for (MixerParticipantList::iterator participant = _participantList.begin();
628          participant != _participantList.end();
629          ++participant) {
630         // Stop keeping track of passive participants if there are already
631         // enough participants available (they wont be mixed anyway).
632         bool mustAddToPassiveList = (maxAudioFrameCounter >
633                                     (activeList.size() +
634                                      passiveWasMixedList.size() +
635                                      passiveWasNotMixedList.size()));
636 
637         bool wasMixed = false;
638         (*participant)->_mixHistory->WasMixed(wasMixed);
639         AudioFrame* audioFrame = NULL;
640         if(_audioFramePool->PopMemory(audioFrame) == -1) {
641             WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
642                          "failed PopMemory() call");
643             assert(false);
644             return;
645         }
646         audioFrame->sample_rate_hz_ = _outputFrequency;
647 
648         if((*participant)->GetAudioFrame(_id,*audioFrame) != 0) {
649             WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
650                          "failed to GetAudioFrame() from participant");
651             _audioFramePool->PushMemory(audioFrame);
652             continue;
653         }
654         if (_participantList.size() != 1) {
655           // TODO(wu): Issue 3390, add support for multiple participants case.
656           audioFrame->ntp_time_ms_ = -1;
657         }
658 
659         // TODO(henrike): this assert triggers in some test cases where SRTP is
660         // used which prevents NetEQ from making a VAD. Temporarily disable this
661         // assert until the problem is fixed on a higher level.
662         // assert(audioFrame->vad_activity_ != AudioFrame::kVadUnknown);
663         if (audioFrame->vad_activity_ == AudioFrame::kVadUnknown) {
664             WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
665                          "invalid VAD state from participant");
666         }
667 
668         if(audioFrame->vad_activity_ == AudioFrame::kVadActive) {
669             if(!wasMixed) {
670                 RampIn(*audioFrame);
671             }
672 
673             if(activeList.size() >= maxAudioFrameCounter) {
674                 // There are already more active participants than should be
675                 // mixed. Only keep the ones with the highest energy.
676                 AudioFrameList::iterator replaceItem;
677                 CalculateEnergy(*audioFrame);
678                 uint32_t lowestEnergy = audioFrame->energy_;
679 
680                 bool found_replace_item = false;
681                 for (AudioFrameList::iterator iter = activeList.begin();
682                      iter != activeList.end();
683                      ++iter) {
684                     CalculateEnergy(**iter);
685                     if((*iter)->energy_ < lowestEnergy) {
686                         replaceItem = iter;
687                         lowestEnergy = (*iter)->energy_;
688                         found_replace_item = true;
689                     }
690                 }
691                 if(found_replace_item) {
692                     AudioFrame* replaceFrame = *replaceItem;
693 
694                     bool replaceWasMixed = false;
695                     std::map<int, MixerParticipant*>::iterator it =
696                         mixParticipantList->find(replaceFrame->id_);
697 
698                     // When a frame is pushed to |activeList| it is also pushed
699                     // to mixParticipantList with the frame's id. This means
700                     // that the Find call above should never fail.
701                     assert(it != mixParticipantList->end());
702                     it->second->_mixHistory->WasMixed(replaceWasMixed);
703 
704                     mixParticipantList->erase(replaceFrame->id_);
705                     activeList.erase(replaceItem);
706 
707                     activeList.push_front(audioFrame);
708                     (*mixParticipantList)[audioFrame->id_] = *participant;
709                     assert(mixParticipantList->size() <=
710                            kMaximumAmountOfMixedParticipants);
711 
712                     if (replaceWasMixed) {
713                       RampOut(*replaceFrame);
714                       rampOutList->push_back(replaceFrame);
715                       assert(rampOutList->size() <=
716                              kMaximumAmountOfMixedParticipants);
717                     } else {
718                       _audioFramePool->PushMemory(replaceFrame);
719                     }
720                 } else {
721                     if(wasMixed) {
722                         RampOut(*audioFrame);
723                         rampOutList->push_back(audioFrame);
724                         assert(rampOutList->size() <=
725                                kMaximumAmountOfMixedParticipants);
726                     } else {
727                         _audioFramePool->PushMemory(audioFrame);
728                     }
729                 }
730             } else {
731                 activeList.push_front(audioFrame);
732                 (*mixParticipantList)[audioFrame->id_] = *participant;
733                 assert(mixParticipantList->size() <=
734                        kMaximumAmountOfMixedParticipants);
735             }
736         } else {
737             if(wasMixed) {
738                 ParticipantFramePair* pair = new ParticipantFramePair;
739                 pair->audioFrame  = audioFrame;
740                 pair->participant = *participant;
741                 passiveWasMixedList.push_back(pair);
742             } else if(mustAddToPassiveList) {
743                 RampIn(*audioFrame);
744                 ParticipantFramePair* pair = new ParticipantFramePair;
745                 pair->audioFrame  = audioFrame;
746                 pair->participant = *participant;
747                 passiveWasNotMixedList.push_back(pair);
748             } else {
749                 _audioFramePool->PushMemory(audioFrame);
750             }
751         }
752     }
753     assert(activeList.size() <= maxAudioFrameCounter);
754     // At this point it is known which participants should be mixed. Transfer
755     // this information to this functions output parameters.
756     for (AudioFrameList::iterator iter = activeList.begin();
757          iter != activeList.end();
758          ++iter) {
759         mixList->push_back(*iter);
760     }
761     activeList.clear();
762     // Always mix a constant number of AudioFrames. If there aren't enough
763     // active participants mix passive ones. Starting with those that was mixed
764     // last iteration.
765     for (ParticipantFramePairList::iterator iter = passiveWasMixedList.begin();
766          iter != passiveWasMixedList.end();
767          ++iter) {
768         if(mixList->size() < maxAudioFrameCounter + mixListStartSize) {
769             mixList->push_back((*iter)->audioFrame);
770             (*mixParticipantList)[(*iter)->audioFrame->id_] =
771                 (*iter)->participant;
772             assert(mixParticipantList->size() <=
773                    kMaximumAmountOfMixedParticipants);
774         } else {
775             _audioFramePool->PushMemory((*iter)->audioFrame);
776         }
777         delete *iter;
778     }
779     // And finally the ones that have not been mixed for a while.
780     for (ParticipantFramePairList::iterator iter =
781              passiveWasNotMixedList.begin();
782          iter != passiveWasNotMixedList.end();
783          ++iter) {
784         if(mixList->size() <  maxAudioFrameCounter + mixListStartSize) {
785           mixList->push_back((*iter)->audioFrame);
786             (*mixParticipantList)[(*iter)->audioFrame->id_] =
787                 (*iter)->participant;
788             assert(mixParticipantList->size() <=
789                    kMaximumAmountOfMixedParticipants);
790         } else {
791             _audioFramePool->PushMemory((*iter)->audioFrame);
792         }
793         delete *iter;
794     }
795     assert(maxAudioFrameCounter + mixListStartSize >= mixList->size());
796     maxAudioFrameCounter += mixListStartSize - mixList->size();
797 }
798 
GetAdditionalAudio(AudioFrameList * additionalFramesList)799 void AudioConferenceMixerImpl::GetAdditionalAudio(
800     AudioFrameList* additionalFramesList) {
801     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
802                  "GetAdditionalAudio(additionalFramesList)");
803     // The GetAudioFrame() callback may result in the participant being removed
804     // from additionalParticipantList_. If that happens it will invalidate any
805     // iterators. Create a copy of the participants list such that the list of
806     // participants can be traversed safely.
807     MixerParticipantList additionalParticipantList;
808     additionalParticipantList.insert(additionalParticipantList.begin(),
809                                      _additionalParticipantList.begin(),
810                                      _additionalParticipantList.end());
811 
812     for (MixerParticipantList::iterator participant =
813              additionalParticipantList.begin();
814          participant != additionalParticipantList.end();
815          ++participant) {
816         AudioFrame* audioFrame = NULL;
817         if(_audioFramePool->PopMemory(audioFrame) == -1) {
818             WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id,
819                          "failed PopMemory() call");
820             assert(false);
821             return;
822         }
823         audioFrame->sample_rate_hz_ = _outputFrequency;
824         if((*participant)->GetAudioFrame(_id, *audioFrame) != 0) {
825             WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id,
826                          "failed to GetAudioFrame() from participant");
827             _audioFramePool->PushMemory(audioFrame);
828             continue;
829         }
830         if(audioFrame->samples_per_channel_ == 0) {
831             // Empty frame. Don't use it.
832             _audioFramePool->PushMemory(audioFrame);
833             continue;
834         }
835         additionalFramesList->push_back(audioFrame);
836     }
837 }
838 
UpdateMixedStatus(std::map<int,MixerParticipant * > & mixedParticipantsMap)839 void AudioConferenceMixerImpl::UpdateMixedStatus(
840     std::map<int, MixerParticipant*>& mixedParticipantsMap) {
841     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
842                  "UpdateMixedStatus(mixedParticipantsMap)");
843     assert(mixedParticipantsMap.size() <= kMaximumAmountOfMixedParticipants);
844 
845     // Loop through all participants. If they are in the mix map they
846     // were mixed.
847     for (MixerParticipantList::iterator participant = _participantList.begin();
848          participant != _participantList.end();
849          ++participant) {
850         bool isMixed = false;
851         for (std::map<int, MixerParticipant*>::iterator it =
852                  mixedParticipantsMap.begin();
853              it != mixedParticipantsMap.end();
854              ++it) {
855           if (it->second == *participant) {
856             isMixed = true;
857             break;
858           }
859         }
860         (*participant)->_mixHistory->SetIsMixed(isMixed);
861     }
862 }
863 
ClearAudioFrameList(AudioFrameList * audioFrameList)864 void AudioConferenceMixerImpl::ClearAudioFrameList(
865     AudioFrameList* audioFrameList) {
866     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
867                  "ClearAudioFrameList(audioFrameList)");
868     for (AudioFrameList::iterator iter = audioFrameList->begin();
869          iter != audioFrameList->end();
870          ++iter) {
871         _audioFramePool->PushMemory(*iter);
872     }
873     audioFrameList->clear();
874 }
875 
UpdateVADPositiveParticipants(AudioFrameList * mixList)876 void AudioConferenceMixerImpl::UpdateVADPositiveParticipants(
877     AudioFrameList* mixList) {
878     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
879                  "UpdateVADPositiveParticipants(mixList)");
880 
881     for (AudioFrameList::iterator iter = mixList->begin();
882          iter != mixList->end();
883          ++iter) {
884         CalculateEnergy(**iter);
885         if((*iter)->vad_activity_ == AudioFrame::kVadActive) {
886             _scratchVadPositiveParticipants[
887                 _scratchVadPositiveParticipantsAmount].participant =
888                 (*iter)->id_;
889             // TODO(andrew): to what should this be set?
890             _scratchVadPositiveParticipants[
891                 _scratchVadPositiveParticipantsAmount].level = 0;
892             _scratchVadPositiveParticipantsAmount++;
893         }
894     }
895 }
896 
IsParticipantInList(MixerParticipant & participant,MixerParticipantList * participantList) const897 bool AudioConferenceMixerImpl::IsParticipantInList(
898     MixerParticipant& participant,
899     MixerParticipantList* participantList) const {
900     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
901                  "IsParticipantInList(participant,participantList)");
902     for (MixerParticipantList::const_iterator iter = participantList->begin();
903          iter != participantList->end();
904          ++iter) {
905         if(&participant == *iter) {
906             return true;
907         }
908     }
909     return false;
910 }
911 
AddParticipantToList(MixerParticipant & participant,MixerParticipantList * participantList)912 bool AudioConferenceMixerImpl::AddParticipantToList(
913     MixerParticipant& participant,
914     MixerParticipantList* participantList) {
915     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
916                  "AddParticipantToList(participant, participantList)");
917     participantList->push_back(&participant);
918     // Make sure that the mixed status is correct for new MixerParticipant.
919     participant._mixHistory->ResetMixedStatus();
920     return true;
921 }
922 
RemoveParticipantFromList(MixerParticipant & participant,MixerParticipantList * participantList)923 bool AudioConferenceMixerImpl::RemoveParticipantFromList(
924     MixerParticipant& participant,
925     MixerParticipantList* participantList) {
926     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
927                  "RemoveParticipantFromList(participant, participantList)");
928     for (MixerParticipantList::iterator iter = participantList->begin();
929          iter != participantList->end();
930          ++iter) {
931         if(*iter == &participant) {
932             participantList->erase(iter);
933             // Participant is no longer mixed, reset to default.
934             participant._mixHistory->ResetMixedStatus();
935             return true;
936         }
937     }
938     return false;
939 }
940 
MixFromList(AudioFrame & mixedAudio,const AudioFrameList * audioFrameList)941 int32_t AudioConferenceMixerImpl::MixFromList(
942     AudioFrame& mixedAudio,
943     const AudioFrameList* audioFrameList) {
944     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
945                  "MixFromList(mixedAudio, audioFrameList)");
946     if(audioFrameList->empty()) return 0;
947 
948     uint32_t position = 0;
949     if(_numMixedParticipants == 1) {
950         // No mixing required here; skip the saturation protection.
951         AudioFrame* audioFrame = audioFrameList->front();
952         mixedAudio.CopyFrom(*audioFrame);
953         SetParticipantStatistics(&_scratchMixedParticipants[position],
954                                  *audioFrame);
955         return 0;
956     }
957 
958     if (audioFrameList->size() == 1) {
959       mixedAudio.timestamp_ = audioFrameList->front()->timestamp_;
960       mixedAudio.elapsed_time_ms_ = audioFrameList->front()->elapsed_time_ms_;
961     } else {
962       // TODO(wu): Issue 3390.
963       // Audio frame timestamp is only supported in one channel case.
964       mixedAudio.timestamp_ = 0;
965       mixedAudio.elapsed_time_ms_ = -1;
966     }
967 
968     for (AudioFrameList::const_iterator iter = audioFrameList->begin();
969          iter != audioFrameList->end();
970          ++iter) {
971         if(position >= kMaximumAmountOfMixedParticipants) {
972             WEBRTC_TRACE(
973                 kTraceMemory,
974                 kTraceAudioMixerServer,
975                 _id,
976                 "Trying to mix more than max amount of mixed participants:%d!",
977                 kMaximumAmountOfMixedParticipants);
978             // Assert and avoid crash
979             assert(false);
980             position = 0;
981         }
982         MixFrames(&mixedAudio, (*iter));
983 
984         SetParticipantStatistics(&_scratchMixedParticipants[position],
985                                  **iter);
986 
987         position++;
988     }
989 
990     return 0;
991 }
992 
993 // TODO(andrew): consolidate this function with MixFromList.
MixAnonomouslyFromList(AudioFrame & mixedAudio,const AudioFrameList * audioFrameList)994 int32_t AudioConferenceMixerImpl::MixAnonomouslyFromList(
995     AudioFrame& mixedAudio,
996     const AudioFrameList* audioFrameList) {
997     WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
998                  "MixAnonomouslyFromList(mixedAudio, audioFrameList)");
999 
1000     if(audioFrameList->empty()) return 0;
1001 
1002     if(_numMixedParticipants == 1) {
1003         // No mixing required here; skip the saturation protection.
1004         AudioFrame* audioFrame = audioFrameList->front();
1005         mixedAudio.CopyFrom(*audioFrame);
1006         return 0;
1007     }
1008 
1009     for (AudioFrameList::const_iterator iter = audioFrameList->begin();
1010          iter != audioFrameList->end();
1011          ++iter) {
1012         MixFrames(&mixedAudio, *iter);
1013     }
1014     return 0;
1015 }
1016 
LimitMixedAudio(AudioFrame & mixedAudio)1017 bool AudioConferenceMixerImpl::LimitMixedAudio(AudioFrame& mixedAudio) {
1018     if(_numMixedParticipants == 1) {
1019         return true;
1020     }
1021 
1022     // Smoothly limit the mixed frame.
1023     const int error = _limiter->ProcessStream(&mixedAudio);
1024 
1025     // And now we can safely restore the level. This procedure results in
1026     // some loss of resolution, deemed acceptable.
1027     //
1028     // It's possible to apply the gain in the AGC (with a target level of 0 dbFS
1029     // and compression gain of 6 dB). However, in the transition frame when this
1030     // is enabled (moving from one to two participants) it has the potential to
1031     // create discontinuities in the mixed frame.
1032     //
1033     // Instead we double the frame (with addition since left-shifting a
1034     // negative value is undefined).
1035     mixedAudio += mixedAudio;
1036 
1037     if(error != _limiter->kNoError) {
1038         WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
1039                      "Error from AudioProcessing: %d", error);
1040         assert(false);
1041         return false;
1042     }
1043     return true;
1044 }
1045 }  // namespace webrtc
1046