Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: webrtc/modules/audio_mixer/source/new_audio_conference_mixer_impl.cc

Issue 2221443002: Changed mixing api and removed resampler (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Described Mix args in comments. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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.
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 26 matching lines...) Expand all
130 NewAudioConferenceMixerImpl* mixer = new NewAudioConferenceMixerImpl(id); 125 NewAudioConferenceMixerImpl* mixer = new NewAudioConferenceMixerImpl(id);
131 if (!mixer->Init()) { 126 if (!mixer->Init()) {
132 delete mixer; 127 delete mixer;
133 return NULL; 128 return NULL;
134 } 129 }
135 return mixer; 130 return mixer;
136 } 131 }
137 132
138 NewAudioConferenceMixerImpl::NewAudioConferenceMixerImpl(int id) 133 NewAudioConferenceMixerImpl::NewAudioConferenceMixerImpl(int id)
139 : _id(id), 134 : _id(id),
140 _minimumMixingFreq(kLowestPossible),
141 _outputFrequency(kDefaultFrequency), 135 _outputFrequency(kDefaultFrequency),
142 _sampleSize(0), 136 _sampleSize(0),
143 audio_source_list_(), 137 audio_source_list_(),
144 additional_audio_source_list_(), 138 additional_audio_source_list_(),
145 num_mixed_audio_sources_(0), 139 num_mixed_audio_sources_(0),
146 use_limiter_(true), 140 use_limiter_(true),
147 _timeStamp(0) { 141 _timeStamp(0) {
148 thread_checker_.DetachFromThread(); 142 thread_checker_.DetachFromThread();
149 } 143 }
150 144
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 176
183 if (_limiter->gain_control()->enable_limiter(true) != _limiter->kNoError) 177 if (_limiter->gain_control()->enable_limiter(true) != _limiter->kNoError)
184 return false; 178 return false;
185 179
186 if (_limiter->gain_control()->Enable(true) != _limiter->kNoError) 180 if (_limiter->gain_control()->Enable(true) != _limiter->kNoError)
187 return false; 181 return false;
188 182
189 return true; 183 return true;
190 } 184 }
191 185
192 void NewAudioConferenceMixerImpl::Mix(AudioFrame* audio_frame_for_mixing) { 186 void NewAudioConferenceMixerImpl::Mix(int sample_rate,
187 size_t number_of_channels,
188 AudioFrame* audio_frame_for_mixing) {
189 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
193 size_t remainingAudioSourcesAllowedToMix = kMaximumAmountOfMixedAudioSources; 190 size_t remainingAudioSourcesAllowedToMix = kMaximumAmountOfMixedAudioSources;
194 RTC_DCHECK(thread_checker_.CalledOnValidThread()); 191 RTC_DCHECK(thread_checker_.CalledOnValidThread());
195 AudioFrameList mixList; 192 AudioFrameList mixList;
196 AudioFrameList additionalFramesList; 193 AudioFrameList additionalFramesList;
197 std::map<int, MixerAudioSource*> mixedAudioSourcesMap; 194 std::map<int, MixerAudioSource*> mixedAudioSourcesMap;
198 { 195 {
199 CriticalSectionScoped cs(_cbCrit.get()); 196 CriticalSectionScoped cs(_cbCrit.get());
197 Frequency mixing_frequency;
200 198
201 int32_t lowFreq = GetLowestMixingFrequency(); 199 switch (sample_rate) {
202 // SILK can run in 12 kHz and 24 kHz. These frequencies are not 200 case 8000:
203 // supported so use the closest higher frequency to not lose any 201 mixing_frequency = kNbInHz;
204 // information. 202 break;
205 // TODO(aleloi): this is probably more appropriate to do in 203 case 16000:
206 // GetLowestMixingFrequency(). 204 mixing_frequency = kWbInHz;
207 if (lowFreq == 12000) { 205 break;
208 lowFreq = 16000; 206 case 32000:
209 } else if (lowFreq == 24000) { 207 mixing_frequency = kSwbInHz;
210 lowFreq = 32000; 208 break;
209 case 48000:
210 mixing_frequency = kFbInHz;
211 break;
212 default:
213 RTC_NOTREACHED();
214 return;
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) {
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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 ? 0 362 ? 0
384 : -1; 363 : -1;
385 } 364 }
386 365
387 bool NewAudioConferenceMixerImpl::AnonymousMixabilityStatus( 366 bool NewAudioConferenceMixerImpl::AnonymousMixabilityStatus(
388 const MixerAudioSource& audio_source) const { 367 const MixerAudioSource& audio_source) const {
389 CriticalSectionScoped cs(_cbCrit.get()); 368 CriticalSectionScoped cs(_cbCrit.get());
390 return IsAudioSourceInList(audio_source, additional_audio_source_list_); 369 return IsAudioSourceInList(audio_source, additional_audio_source_list_);
391 } 370 }
392 371
393 int32_t NewAudioConferenceMixerImpl::SetMinimumMixingFrequency(Frequency freq) {
394 // Make sure that only allowed sampling frequencies are used. Use closest
395 // higher sampling frequency to avoid losing information.
396 if (static_cast<int>(freq) == 12000) {
397 freq = kWbInHz;
398 } else if (static_cast<int>(freq) == 24000) {
399 freq = kSwbInHz;
400 }
401
402 if ((freq == kNbInHz) || (freq == kWbInHz) || (freq == kSwbInHz) ||
403 (freq == kLowestPossible)) {
404 _minimumMixingFreq = freq;
405 return 0;
406 } else {
407 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
408 "SetMinimumMixingFrequency incorrect frequency: %i", freq);
409 RTC_NOTREACHED();
410 return -1;
411 }
412 }
413
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( 372 AudioFrameList NewAudioConferenceMixerImpl::UpdateToMix(
447 size_t maxAudioFrameCounter) const { 373 size_t maxAudioFrameCounter) const {
448 AudioFrameList result; 374 AudioFrameList result;
449 std::vector<SourceFrame> audioSourceMixingDataList; 375 std::vector<SourceFrame> audioSourceMixingDataList;
450 376
451 // Get audio source audio and put it in the struct vector. 377 // Get audio source audio and put it in the struct vector.
452 for (MixerAudioSource* audio_source : audio_source_list_) { 378 for (MixerAudioSource* audio_source : audio_source_list_) {
453 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( 379 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted(
454 _id, static_cast<int>(_outputFrequency)); 380 _id, static_cast<int>(_outputFrequency));
455 381
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 589
664 if (error != _limiter->kNoError) { 590 if (error != _limiter->kNoError) {
665 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id, 591 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id,
666 "Error from AudioProcessing: %d", error); 592 "Error from AudioProcessing: %d", error);
667 RTC_NOTREACHED(); 593 RTC_NOTREACHED();
668 return false; 594 return false;
669 } 595 }
670 return true; 596 return true;
671 } 597 }
672 } // namespace webrtc 598 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698