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