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