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