 Chromium Code Reviews
 Chromium Code Reviews Issue 2221443002:
  Changed mixing api and removed resampler  (Closed) 
  Base URL: https://chromium.googlesource.com/external/webrtc.git@master
    
  
    Issue 2221443002:
  Changed mixing api and removed resampler  (Closed) 
  Base URL: https://chromium.googlesource.com/external/webrtc.git@master| 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 #include <functional> | 14 #include <functional> | 
| 15 | 15 | 
| 16 #include "webrtc/modules/audio_conference_mixer/source/audio_frame_manipulator.h " | 16 #include "webrtc/modules/audio_conference_mixer/source/audio_frame_manipulator.h " | 
| 17 #include "webrtc/modules/audio_mixer/include/audio_mixer_defines.h" | 17 #include "webrtc/modules/audio_mixer/include/audio_mixer_defines.h" | 
| 18 #include "webrtc/modules/audio_processing/include/audio_processing.h" | 18 #include "webrtc/modules/audio_processing/include/audio_processing.h" | 
| 19 #include "webrtc/modules/utility/include/audio_frame_operations.h" | 19 #include "webrtc/modules/utility/include/audio_frame_operations.h" | 
| 20 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 20 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 
| 21 #include "webrtc/system_wrappers/include/trace.h" | 21 #include "webrtc/system_wrappers/include/trace.h" | 
| 22 #include "webrtc/voice_engine/utility.h" | |
| 22 | 23 | 
| 23 namespace webrtc { | 24 namespace webrtc { | 
| 24 namespace { | 25 namespace { | 
| 25 | 26 | 
| 26 class SourceFrame { | 27 class SourceFrame { | 
| 27 public: | 28 public: | 
| 28 SourceFrame(MixerAudioSource* p, AudioFrame* a, bool m, bool was_mixed_before) | 29 SourceFrame(MixerAudioSource* p, AudioFrame* a, bool m, bool was_mixed_before) | 
| 29 : audio_source_(p), | 30 : audio_source_(p), | 
| 30 audio_frame_(a), | 31 audio_frame_(a), | 
| 31 muted_(m), | 32 muted_(m), | 
| (...skipping 19 matching lines...) Expand all Loading... | |
| 51 return energy_ > other.energy_; | 52 return energy_ > other.energy_; | 
| 52 } | 53 } | 
| 53 | 54 | 
| 54 MixerAudioSource* audio_source_; | 55 MixerAudioSource* audio_source_; | 
| 55 AudioFrame* audio_frame_; | 56 AudioFrame* audio_frame_; | 
| 56 bool muted_; | 57 bool muted_; | 
| 57 uint32_t energy_; | 58 uint32_t energy_; | 
| 58 bool was_mixed_before_; | 59 bool was_mixed_before_; | 
| 59 }; | 60 }; | 
| 60 | 61 | 
| 62 // Remixes a frame between stereo and mono. | |
| 
aleloi2
2016/08/06 10:13:50
I couldn't find any function that does this in Web
 | |
| 63 void RemixFrame(AudioFrame* frame, size_t number_of_channels) { | |
| 64 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); | |
| 65 if (frame->num_channels_ == 1 && number_of_channels == 2) { | |
| 66 AudioFrameOperations::MonoToStereo(frame); | |
| 67 } else if (frame->num_channels_ == 2 && number_of_channels == 1) { | |
| 68 AudioFrameOperations::StereoToMono(frame); | |
| 69 } | |
| 70 } | |
| 71 | |
| 61 // Mix |frame| into |mixed_frame|, with saturation protection and upmixing. | 72 // Mix |frame| into |mixed_frame|, with saturation protection and upmixing. | 
| 62 // These effects are applied to |frame| itself prior to mixing. Assumes that | 73 // These effects are applied to |frame| itself prior to mixing. Assumes that | 
| 63 // |mixed_frame| always has at least as many channels as |frame|. Supports | 74 // |mixed_frame| always has at least as many channels as |frame|. Supports | 
| 64 // stereo at most. | 75 // stereo at most. | 
| 65 // | 76 // | 
| 66 // TODO(andrew): consider not modifying |frame| here. | 77 // TODO(andrew): consider not modifying |frame| here. | 
| 67 void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) { | 78 void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) { | 
| 68 RTC_DCHECK_GE(mixed_frame->num_channels_, frame->num_channels_); | 79 RTC_DCHECK_GE(mixed_frame->num_channels_, frame->num_channels_); | 
| 69 if (use_limiter) { | 80 if (use_limiter) { | 
| 70 // Divide by two to avoid saturation in the mixing. | 81 // Divide by two to avoid saturation in the mixing. | 
| 71 // This is only meaningful if the limiter will be used. | 82 // This is only meaningful if the limiter will be used. | 
| 72 *frame >>= 1; | 83 *frame >>= 1; | 
| 73 } | 84 } | 
| 74 if (mixed_frame->num_channels_ > frame->num_channels_) { | 85 RTC_DCHECK_EQ(frame->num_channels_, mixed_frame->num_channels_); | 
| 75 // We only support mono-to-stereo. | |
| 76 RTC_DCHECK_EQ(mixed_frame->num_channels_, static_cast<size_t>(2)); | |
| 77 RTC_DCHECK_EQ(frame->num_channels_, static_cast<size_t>(1)); | |
| 78 AudioFrameOperations::MonoToStereo(frame); | |
| 79 } | |
| 80 | |
| 81 *mixed_frame += *frame; | 86 *mixed_frame += *frame; | 
| 82 } | 87 } | 
| 83 | 88 | 
| 84 // Return the max number of channels from a |list| composed of AudioFrames. | |
| 85 size_t MaxNumChannels(const AudioFrameList* list) { | |
| 86 size_t max_num_channels = 1; | |
| 87 for (AudioFrameList::const_iterator iter = list->begin(); iter != list->end(); | |
| 88 ++iter) { | |
| 89 max_num_channels = std::max(max_num_channels, (*iter).frame->num_channels_); | |
| 90 } | |
| 91 return max_num_channels; | |
| 92 } | |
| 93 | |
| 94 } // namespace | 89 } // namespace | 
| 95 | 90 | 
| 96 MixerAudioSource::MixerAudioSource() : _mixHistory(new NewMixHistory()) {} | 91 MixerAudioSource::MixerAudioSource() : _mixHistory(new NewMixHistory()) {} | 
| 97 | 92 | 
| 98 MixerAudioSource::~MixerAudioSource() { | 93 MixerAudioSource::~MixerAudioSource() { | 
| 99 delete _mixHistory; | 94 delete _mixHistory; | 
| 100 } | 95 } | 
| 101 | 96 | 
| 102 bool MixerAudioSource::IsMixed() const { | 97 bool MixerAudioSource::IsMixed() const { | 
| 103 return _mixHistory->IsMixed(); | 98 return _mixHistory->IsMixed(); | 
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 | 177 | 
| 183 if (_limiter->gain_control()->enable_limiter(true) != _limiter->kNoError) | 178 if (_limiter->gain_control()->enable_limiter(true) != _limiter->kNoError) | 
| 184 return false; | 179 return false; | 
| 185 | 180 | 
| 186 if (_limiter->gain_control()->Enable(true) != _limiter->kNoError) | 181 if (_limiter->gain_control()->Enable(true) != _limiter->kNoError) | 
| 187 return false; | 182 return false; | 
| 188 | 183 | 
| 189 return true; | 184 return true; | 
| 190 } | 185 } | 
| 191 | 186 | 
| 192 void NewAudioConferenceMixerImpl::Mix(AudioFrame* audio_frame_for_mixing) { | 187 void NewAudioConferenceMixerImpl::Mix(int sample_rate, | 
| 188 size_t number_of_channels, | |
| 189 AudioFrame* audio_frame_for_mixing) { | |
| 190 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); | |
| 193 size_t remainingAudioSourcesAllowedToMix = kMaximumAmountOfMixedAudioSources; | 191 size_t remainingAudioSourcesAllowedToMix = kMaximumAmountOfMixedAudioSources; | 
| 194 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 192 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 
| 195 AudioFrameList mixList; | 193 AudioFrameList mixList; | 
| 196 AudioFrameList additionalFramesList; | 194 AudioFrameList additionalFramesList; | 
| 197 std::map<int, MixerAudioSource*> mixedAudioSourcesMap; | 195 std::map<int, MixerAudioSource*> mixedAudioSourcesMap; | 
| 198 { | 196 { | 
| 199 CriticalSectionScoped cs(_cbCrit.get()); | 197 CriticalSectionScoped cs(_cbCrit.get()); | 
| 198 Frequency mixing_frequency; | |
| 200 | 199 | 
| 201 int32_t lowFreq = GetLowestMixingFrequency(); | 200 switch (sample_rate) { | 
| 202 // SILK can run in 12 kHz and 24 kHz. These frequencies are not | 201 case 8000: | 
| 203 // supported so use the closest higher frequency to not lose any | 202 mixing_frequency = kNbInHz; | 
| 204 // information. | 203 break; | 
| 205 // TODO(aleloi): this is probably more appropriate to do in | 204 case 16000: | 
| 206 // GetLowestMixingFrequency(). | 205 mixing_frequency = kWbInHz; | 
| 207 if (lowFreq == 12000) { | 206 break; | 
| 208 lowFreq = 16000; | 207 case 32000: | 
| 209 } else if (lowFreq == 24000) { | 208 mixing_frequency = kSwbInHz; | 
| 210 lowFreq = 32000; | 209 break; | 
| 210 case 48000: | |
| 211 mixing_frequency = kFbInHz; | |
| 212 break; | |
| 213 default: | |
| 214 RTC_NOTREACHED(); | |
| 211 } | 215 } | 
| 212 if (lowFreq <= 0) { | 216 | 
| 213 return; | 217 if (OutputFrequency() != mixing_frequency) { | 
| 214 } else { | 218 SetOutputFrequency(mixing_frequency); | 
| 215 switch (lowFreq) { | |
| 216 case 8000: | |
| 217 if (OutputFrequency() != kNbInHz) { | |
| 218 SetOutputFrequency(kNbInHz); | |
| 219 } | |
| 220 break; | |
| 221 case 16000: | |
| 222 if (OutputFrequency() != kWbInHz) { | |
| 223 SetOutputFrequency(kWbInHz); | |
| 224 } | |
| 225 break; | |
| 226 case 32000: | |
| 227 if (OutputFrequency() != kSwbInHz) { | |
| 228 SetOutputFrequency(kSwbInHz); | |
| 229 } | |
| 230 break; | |
| 231 case 48000: | |
| 232 if (OutputFrequency() != kFbInHz) { | |
| 233 SetOutputFrequency(kFbInHz); | |
| 234 } | |
| 235 break; | |
| 236 default: | |
| 237 RTC_NOTREACHED(); | |
| 238 return; | |
| 239 } | |
| 240 } | 219 } | 
| 241 | 220 | 
| 242 mixList = UpdateToMix(remainingAudioSourcesAllowedToMix); | 221 mixList = UpdateToMix(remainingAudioSourcesAllowedToMix); | 
| 243 remainingAudioSourcesAllowedToMix -= mixList.size(); | 222 remainingAudioSourcesAllowedToMix -= mixList.size(); | 
| 244 GetAdditionalAudio(&additionalFramesList); | 223 GetAdditionalAudio(&additionalFramesList); | 
| 245 } | 224 } | 
| 246 | 225 | 
| 247 // TODO(aleloi): it might be better to decide the number of channels | 226 for (FrameAndMuteInfo& frame_and_mute : mixList) { | 
| 
aleloi2
2016/08/06 10:13:50
Previously, all frames were up-mixed if a single o
 | |
| 248 // with an API instead of dynamically. | 227 RemixFrame(frame_and_mute.frame, number_of_channels); | 
| 249 | 228 } | 
| 250 // Find the max channels over all mixing lists. | 229 for (FrameAndMuteInfo& frame_and_mute : additionalFramesList) { | 
| 251 const size_t num_mixed_channels = | 230 RemixFrame(frame_and_mute.frame, number_of_channels); | 
| 252 std::max(MaxNumChannels(&mixList), MaxNumChannels(&additionalFramesList)); | 231 } | 
| 253 | 232 | 
| 254 audio_frame_for_mixing->UpdateFrame( | 233 audio_frame_for_mixing->UpdateFrame( | 
| 255 -1, _timeStamp, NULL, 0, _outputFrequency, AudioFrame::kNormalSpeech, | 234 -1, _timeStamp, NULL, 0, _outputFrequency, AudioFrame::kNormalSpeech, | 
| 256 AudioFrame::kVadPassive, num_mixed_channels); | 235 AudioFrame::kVadPassive, number_of_channels); | 
| 257 | 236 | 
| 258 _timeStamp += static_cast<uint32_t>(_sampleSize); | 237 _timeStamp += static_cast<uint32_t>(_sampleSize); | 
| 259 | 238 | 
| 260 use_limiter_ = num_mixed_audio_sources_ > 1 && | 239 use_limiter_ = num_mixed_audio_sources_ > 1 && | 
| 261 _outputFrequency <= AudioProcessing::kMaxNativeSampleRateHz; | 240 _outputFrequency <= AudioProcessing::kMaxNativeSampleRateHz; | 
| 262 | 241 | 
| 263 // We only use the limiter if it supports the output sample rate and | 242 // We only use the limiter if it supports the output sample rate and | 
| 264 // we're actually mixing multiple streams. | 243 // we're actually mixing multiple streams. | 
| 265 MixFromList(audio_frame_for_mixing, mixList, _id, use_limiter_); | 244 MixFromList(audio_frame_for_mixing, mixList, _id, use_limiter_); | 
| 266 | 245 | 
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 _minimumMixingFreq = freq; | 383 _minimumMixingFreq = freq; | 
| 405 return 0; | 384 return 0; | 
| 406 } else { | 385 } else { | 
| 407 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id, | 386 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id, | 
| 408 "SetMinimumMixingFrequency incorrect frequency: %i", freq); | 387 "SetMinimumMixingFrequency incorrect frequency: %i", freq); | 
| 409 RTC_NOTREACHED(); | 388 RTC_NOTREACHED(); | 
| 410 return -1; | 389 return -1; | 
| 411 } | 390 } | 
| 412 } | 391 } | 
| 413 | 392 | 
| 414 // Check all AudioFrames that are to be mixed. The highest sampling frequency | |
| 415 // found is the lowest that can be used without losing information. | |
| 416 int32_t NewAudioConferenceMixerImpl::GetLowestMixingFrequency() const { | |
| 417 const int audioSourceListFrequency = | |
| 418 GetLowestMixingFrequencyFromList(audio_source_list_); | |
| 419 const int anonymousListFrequency = | |
| 420 GetLowestMixingFrequencyFromList(additional_audio_source_list_); | |
| 421 const int highestFreq = (audioSourceListFrequency > anonymousListFrequency) | |
| 422 ? audioSourceListFrequency | |
| 423 : anonymousListFrequency; | |
| 424 // Check if the user specified a lowest mixing frequency. | |
| 425 if (_minimumMixingFreq != kLowestPossible) { | |
| 426 if (_minimumMixingFreq > highestFreq) { | |
| 427 return _minimumMixingFreq; | |
| 428 } | |
| 429 } | |
| 430 return highestFreq; | |
| 431 } | |
| 432 | |
| 433 int32_t NewAudioConferenceMixerImpl::GetLowestMixingFrequencyFromList( | |
| 434 const MixerAudioSourceList& mixList) const { | |
| 435 int32_t highestFreq = 8000; | |
| 436 for (MixerAudioSourceList::const_iterator iter = mixList.begin(); | |
| 437 iter != mixList.end(); ++iter) { | |
| 438 const int32_t neededFrequency = (*iter)->NeededFrequency(_id); | |
| 439 if (neededFrequency > highestFreq) { | |
| 440 highestFreq = neededFrequency; | |
| 441 } | |
| 442 } | |
| 443 return highestFreq; | |
| 444 } | |
| 445 | |
| 446 AudioFrameList NewAudioConferenceMixerImpl::UpdateToMix( | 393 AudioFrameList NewAudioConferenceMixerImpl::UpdateToMix( | 
| 447 size_t maxAudioFrameCounter) const { | 394 size_t maxAudioFrameCounter) const { | 
| 448 AudioFrameList result; | 395 AudioFrameList result; | 
| 449 std::vector<SourceFrame> audioSourceMixingDataList; | 396 std::vector<SourceFrame> audioSourceMixingDataList; | 
| 450 | 397 | 
| 451 // Get audio source audio and put it in the struct vector. | 398 // Get audio source audio and put it in the struct vector. | 
| 452 for (MixerAudioSource* audio_source : audio_source_list_) { | 399 for (MixerAudioSource* audio_source : audio_source_list_) { | 
| 453 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( | 400 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( | 
| 454 _id, static_cast<int>(_outputFrequency)); | 401 _id, static_cast<int>(_outputFrequency)); | 
| 455 | 402 | 
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 663 | 610 | 
| 664 if (error != _limiter->kNoError) { | 611 if (error != _limiter->kNoError) { | 
| 665 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id, | 612 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id, | 
| 666 "Error from AudioProcessing: %d", error); | 613 "Error from AudioProcessing: %d", error); | 
| 667 RTC_NOTREACHED(); | 614 RTC_NOTREACHED(); | 
| 668 return false; | 615 return false; | 
| 669 } | 616 } | 
| 670 return true; | 617 return true; | 
| 671 } | 618 } | 
| 672 } // namespace webrtc | 619 } // namespace webrtc | 
| OLD | NEW |