blob: ee78eef2a13a9767b0d47651834c24a7eb0a9660 [file] [log] [blame]
aleloi77ad3942016-07-04 06:33:02 -07001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
aleloi5d167d62016-08-24 02:20:54 -070011#include "webrtc/modules/audio_mixer/audio_mixer_impl.h"
aleloi77ad3942016-07-04 06:33:02 -070012
13#include <algorithm>
aleloif3882572016-07-29 02:12:41 -070014#include <functional>
aleloi311525e2016-09-07 06:13:12 -070015#include <utility>
aleloi77ad3942016-07-04 06:33:02 -070016
aleloi311525e2016-09-07 06:13:12 -070017#include "webrtc/base/thread_annotations.h"
aleloi5bcc00e2016-08-15 03:01:31 -070018#include "webrtc/modules/audio_mixer/audio_frame_manipulator.h"
19#include "webrtc/modules/audio_mixer/audio_mixer_defines.h"
aleloi77ad3942016-07-04 06:33:02 -070020#include "webrtc/modules/audio_processing/include/audio_processing.h"
21#include "webrtc/modules/utility/include/audio_frame_operations.h"
22#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
23#include "webrtc/system_wrappers/include/trace.h"
24
25namespace webrtc {
26namespace {
27
aleloif3882572016-07-29 02:12:41 -070028class SourceFrame {
29 public:
30 SourceFrame(MixerAudioSource* p, AudioFrame* a, bool m, bool was_mixed_before)
31 : audio_source_(p),
32 audio_frame_(a),
33 muted_(m),
34 was_mixed_before_(was_mixed_before) {
35 if (!muted_) {
aleloi5bcc00e2016-08-15 03:01:31 -070036 energy_ = NewMixerCalculateEnergy(*a);
aleloif3882572016-07-29 02:12:41 -070037 }
38 }
aleloi77ad3942016-07-04 06:33:02 -070039
aleloi652ac892016-09-07 07:42:14 -070040 SourceFrame(MixerAudioSource* p,
41 AudioFrame* a,
42 bool m,
43 bool was_mixed_before,
44 uint32_t energy)
45 : audio_source_(p),
46 audio_frame_(a),
47 muted_(m),
48 energy_(energy),
49 was_mixed_before_(was_mixed_before) {}
50
aleloif3882572016-07-29 02:12:41 -070051 // a.shouldMixBefore(b) is used to select mixer participants.
52 bool shouldMixBefore(const SourceFrame& other) const {
53 if (muted_ != other.muted_) {
54 return other.muted_;
55 }
56
57 auto our_activity = audio_frame_->vad_activity_;
58 auto other_activity = other.audio_frame_->vad_activity_;
59
60 if (our_activity != other_activity) {
61 return our_activity == AudioFrame::kVadActive;
62 }
63
64 return energy_ > other.energy_;
65 }
66
67 MixerAudioSource* audio_source_;
68 AudioFrame* audio_frame_;
69 bool muted_;
70 uint32_t energy_;
71 bool was_mixed_before_;
72};
tereliusea4c1412016-07-29 01:36:14 -070073
aleloi44968092016-08-08 10:18:58 -070074// Remixes a frame between stereo and mono.
75void RemixFrame(AudioFrame* frame, size_t number_of_channels) {
76 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
77 if (frame->num_channels_ == 1 && number_of_channels == 2) {
78 AudioFrameOperations::MonoToStereo(frame);
79 } else if (frame->num_channels_ == 2 && number_of_channels == 1) {
80 AudioFrameOperations::StereoToMono(frame);
81 }
82}
83
aleloi652ac892016-09-07 07:42:14 -070084void Ramp(const std::vector<SourceFrame>& mixed_sources_and_frames) {
85 for (const auto& source_frame : mixed_sources_and_frames) {
86 // Ramp in previously unmixed.
87 if (!source_frame.was_mixed_before_) {
88 NewMixerRampIn(source_frame.audio_frame_);
89 }
90
91 const bool is_mixed = source_frame.audio_source_->_mixHistory->IsMixed();
92 // Ramp out currently unmixed.
93 if (source_frame.was_mixed_before_ && !is_mixed) {
94 NewMixerRampOut(source_frame.audio_frame_);
95 }
aleloi77ad3942016-07-04 06:33:02 -070096 }
aleloi77ad3942016-07-04 06:33:02 -070097}
98
aleloi77ad3942016-07-04 06:33:02 -070099} // namespace
100
101MixerAudioSource::MixerAudioSource() : _mixHistory(new NewMixHistory()) {}
102
103MixerAudioSource::~MixerAudioSource() {
104 delete _mixHistory;
105}
106
107bool MixerAudioSource::IsMixed() const {
108 return _mixHistory->IsMixed();
109}
110
aleloi6382a192016-08-08 10:25:04 -0700111NewMixHistory::NewMixHistory() : is_mixed_(0) {}
aleloi77ad3942016-07-04 06:33:02 -0700112
113NewMixHistory::~NewMixHistory() {}
114
115bool NewMixHistory::IsMixed() const {
aleloi6382a192016-08-08 10:25:04 -0700116 return is_mixed_;
aleloi77ad3942016-07-04 06:33:02 -0700117}
118
119bool NewMixHistory::WasMixed() const {
120 // Was mixed is the same as is mixed depending on perspective. This function
121 // is for the perspective of NewAudioConferenceMixerImpl.
122 return IsMixed();
123}
124
125int32_t NewMixHistory::SetIsMixed(const bool mixed) {
aleloi6382a192016-08-08 10:25:04 -0700126 is_mixed_ = mixed;
aleloi77ad3942016-07-04 06:33:02 -0700127 return 0;
128}
129
130void NewMixHistory::ResetMixedStatus() {
aleloi6382a192016-08-08 10:25:04 -0700131 is_mixed_ = false;
aleloi77ad3942016-07-04 06:33:02 -0700132}
133
aleloi5d167d62016-08-24 02:20:54 -0700134std::unique_ptr<AudioMixer> AudioMixer::Create(int id) {
aleloi311525e2016-09-07 06:13:12 -0700135 return AudioMixerImpl::Create(id);
aleloi77ad3942016-07-04 06:33:02 -0700136}
137
aleloi311525e2016-09-07 06:13:12 -0700138AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter)
aleloi6382a192016-08-08 10:25:04 -0700139 : id_(id),
aleloi09f45102016-07-28 03:52:15 -0700140 audio_source_list_(),
141 additional_audio_source_list_(),
142 num_mixed_audio_sources_(0),
aleloi77ad3942016-07-04 06:33:02 -0700143 use_limiter_(true),
aleloi311525e2016-09-07 06:13:12 -0700144 time_stamp_(0),
145 limiter_(std::move(limiter)) {
146 SetOutputFrequency(kDefaultFrequency);
aleloi8b2233f2016-07-28 06:24:14 -0700147 thread_checker_.DetachFromThread();
aleloia0db81f2016-07-28 06:36:22 -0700148}
aleloi77ad3942016-07-04 06:33:02 -0700149
aleloi5d167d62016-08-24 02:20:54 -0700150AudioMixerImpl::~AudioMixerImpl() {}
aleloi70f866c2016-08-16 02:15:49 -0700151
aleloi311525e2016-09-07 06:13:12 -0700152std::unique_ptr<AudioMixer> AudioMixerImpl::Create(int id) {
aleloi77ad3942016-07-04 06:33:02 -0700153 Config config;
154 config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
aleloi311525e2016-09-07 06:13:12 -0700155 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config));
156 if (!limiter.get())
157 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700158
aleloi311525e2016-09-07 06:13:12 -0700159 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) !=
160 limiter->kNoError)
161 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700162
163 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the
164 // divide-by-2 but -7 is used instead to give a bit of headroom since the
165 // AGC is not a hard limiter.
aleloi311525e2016-09-07 06:13:12 -0700166 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError)
167 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700168
aleloi311525e2016-09-07 06:13:12 -0700169 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError)
170 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700171
aleloi311525e2016-09-07 06:13:12 -0700172 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError)
173 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700174
aleloi311525e2016-09-07 06:13:12 -0700175 if (limiter->gain_control()->Enable(true) != limiter->kNoError)
176 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700177
aleloi311525e2016-09-07 06:13:12 -0700178 return std::unique_ptr<AudioMixer>(
179 new AudioMixerImpl(id, std::move(limiter)));
aleloi77ad3942016-07-04 06:33:02 -0700180}
181
aleloi5d167d62016-08-24 02:20:54 -0700182void AudioMixerImpl::Mix(int sample_rate,
183 size_t number_of_channels,
184 AudioFrame* audio_frame_for_mixing) {
aleloi44968092016-08-08 10:18:58 -0700185 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
aleloi311525e2016-09-07 06:13:12 -0700186 RTC_DCHECK_RUN_ON(&thread_checker_);
187 std::map<int, MixerAudioSource*> mixedAudioSourcesMap;
188
189 if (sample_rate != kNbInHz && sample_rate != kWbInHz &&
190 sample_rate != kSwbInHz && sample_rate != kFbInHz) {
191 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
192 "Invalid frequency: %d", sample_rate);
193 RTC_NOTREACHED();
194 return;
195 }
196
197 if (OutputFrequency() != sample_rate) {
198 SetOutputFrequency(static_cast<Frequency>(sample_rate));
199 }
200
aleloi652ac892016-09-07 07:42:14 -0700201 AudioFrameList mix_list;
202 AudioFrameList anonymous_mix_list;
aleloi311525e2016-09-07 06:13:12 -0700203 int num_mixed_audio_sources;
aleloi77ad3942016-07-04 06:33:02 -0700204 {
aleloi311525e2016-09-07 06:13:12 -0700205 rtc::CritScope lock(&crit_);
aleloi652ac892016-09-07 07:42:14 -0700206 mix_list = GetNonAnonymousAudio();
207 anonymous_mix_list = GetAnonymousAudio();
aleloi311525e2016-09-07 06:13:12 -0700208 num_mixed_audio_sources = static_cast<int>(num_mixed_audio_sources_);
aleloi77ad3942016-07-04 06:33:02 -0700209 }
210
aleloi652ac892016-09-07 07:42:14 -0700211 mix_list.insert(mix_list.begin(), anonymous_mix_list.begin(),
212 anonymous_mix_list.end());
213
214 for (const auto& frame : mix_list) {
215 RemixFrame(frame, number_of_channels);
aleloi44968092016-08-08 10:18:58 -0700216 }
aleloi09f45102016-07-28 03:52:15 -0700217
218 audio_frame_for_mixing->UpdateFrame(
aleloi6382a192016-08-08 10:25:04 -0700219 -1, time_stamp_, NULL, 0, output_frequency_, AudioFrame::kNormalSpeech,
aleloi44968092016-08-08 10:18:58 -0700220 AudioFrame::kVadPassive, number_of_channels);
aleloi09f45102016-07-28 03:52:15 -0700221
aleloi6382a192016-08-08 10:25:04 -0700222 time_stamp_ += static_cast<uint32_t>(sample_size_);
aleloi09f45102016-07-28 03:52:15 -0700223
aleloi311525e2016-09-07 06:13:12 -0700224 use_limiter_ = num_mixed_audio_sources > 1;
aleloi09f45102016-07-28 03:52:15 -0700225
aleloi652ac892016-09-07 07:42:14 -0700226 // We only use the limiter if we're actually mixing multiple streams.
227 MixFromList(audio_frame_for_mixing, mix_list, id_, use_limiter_);
228
aleloi311525e2016-09-07 06:13:12 -0700229 if (audio_frame_for_mixing->samples_per_channel_ == 0) {
230 // Nothing was mixed, set the audio samples to silence.
231 audio_frame_for_mixing->samples_per_channel_ = sample_size_;
232 audio_frame_for_mixing->Mute();
233 } else {
234 // Only call the limiter if we have something to mix.
235 LimitMixedAudio(audio_frame_for_mixing);
aleloi77ad3942016-07-04 06:33:02 -0700236 }
aleloi616df1e2016-08-24 01:17:12 -0700237
238 // Pass the final result to the level indicator.
239 audio_level_.ComputeLevel(*audio_frame_for_mixing);
240
aleloi77ad3942016-07-04 06:33:02 -0700241 return;
242}
243
aleloi5d167d62016-08-24 02:20:54 -0700244int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) {
aleloi311525e2016-09-07 06:13:12 -0700245 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700246 output_frequency_ = frequency;
247 sample_size_ =
aleloi5d167d62016-08-24 02:20:54 -0700248 static_cast<size_t>((output_frequency_ * kFrameDurationInMs) / 1000);
aleloi77ad3942016-07-04 06:33:02 -0700249
250 return 0;
251}
252
aleloi5d167d62016-08-24 02:20:54 -0700253AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const {
aleloi311525e2016-09-07 06:13:12 -0700254 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700255 return output_frequency_;
aleloi77ad3942016-07-04 06:33:02 -0700256}
257
aleloi5d167d62016-08-24 02:20:54 -0700258int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source,
259 bool mixable) {
aleloi77ad3942016-07-04 06:33:02 -0700260 if (!mixable) {
aleloi09f45102016-07-28 03:52:15 -0700261 // Anonymous audio sources are in a separate list. Make sure that the
262 // audio source is in the _audioSourceList if it is being mixed.
263 SetAnonymousMixabilityStatus(audio_source, false);
aleloi77ad3942016-07-04 06:33:02 -0700264 }
aleloi77ad3942016-07-04 06:33:02 -0700265 {
aleloi311525e2016-09-07 06:13:12 -0700266 rtc::CritScope lock(&crit_);
aleloi09f45102016-07-28 03:52:15 -0700267 const bool isMixed = IsAudioSourceInList(*audio_source, audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700268 // API must be called with a new state.
269 if (!(mixable ^ isMixed)) {
aleloi6382a192016-08-08 10:25:04 -0700270 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700271 "Mixable is aready %s", isMixed ? "ON" : "off");
272 return -1;
273 }
274 bool success = false;
275 if (mixable) {
aleloi09f45102016-07-28 03:52:15 -0700276 success = AddAudioSourceToList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700277 } else {
aleloi09f45102016-07-28 03:52:15 -0700278 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700279 }
280 if (!success) {
aleloi6382a192016-08-08 10:25:04 -0700281 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700282 "failed to %s audio_source", mixable ? "add" : "remove");
283 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700284 return -1;
285 }
286
aleloi09f45102016-07-28 03:52:15 -0700287 size_t numMixedNonAnonymous = audio_source_list_.size();
288 if (numMixedNonAnonymous > kMaximumAmountOfMixedAudioSources) {
289 numMixedNonAnonymous = kMaximumAmountOfMixedAudioSources;
aleloi77ad3942016-07-04 06:33:02 -0700290 }
aleloi311525e2016-09-07 06:13:12 -0700291 num_mixed_audio_sources_ =
aleloi09f45102016-07-28 03:52:15 -0700292 numMixedNonAnonymous + additional_audio_source_list_.size();
aleloi77ad3942016-07-04 06:33:02 -0700293 }
aleloi77ad3942016-07-04 06:33:02 -0700294 return 0;
295}
296
aleloi5d167d62016-08-24 02:20:54 -0700297bool AudioMixerImpl::MixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700298 const MixerAudioSource& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700299 rtc::CritScope lock(&crit_);
aleloi09f45102016-07-28 03:52:15 -0700300 return IsAudioSourceInList(audio_source, audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700301}
302
aleloi5d167d62016-08-24 02:20:54 -0700303int32_t AudioMixerImpl::SetAnonymousMixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700304 MixerAudioSource* audio_source,
aleloi77ad3942016-07-04 06:33:02 -0700305 bool anonymous) {
aleloi311525e2016-09-07 06:13:12 -0700306 rtc::CritScope lock(&crit_);
aleloi09f45102016-07-28 03:52:15 -0700307 if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) {
aleloi77ad3942016-07-04 06:33:02 -0700308 if (anonymous) {
309 return 0;
310 }
aleloi09f45102016-07-28 03:52:15 -0700311 if (!RemoveAudioSourceFromList(audio_source,
312 &additional_audio_source_list_)) {
aleloi6382a192016-08-08 10:25:04 -0700313 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700314 "unable to remove audio_source from anonymous list");
315 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700316 return -1;
317 }
aleloi09f45102016-07-28 03:52:15 -0700318 return AddAudioSourceToList(audio_source, &audio_source_list_) ? 0 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700319 }
320 if (!anonymous) {
321 return 0;
322 }
323 const bool mixable =
aleloi09f45102016-07-28 03:52:15 -0700324 RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700325 if (!mixable) {
326 WEBRTC_TRACE(
aleloi6382a192016-08-08 10:25:04 -0700327 kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700328 "audio_source must be registered before turning it into anonymous");
aleloi77ad3942016-07-04 06:33:02 -0700329 // Setting anonymous status is only possible if MixerAudioSource is
330 // already registered.
331 return -1;
332 }
aleloi09f45102016-07-28 03:52:15 -0700333 return AddAudioSourceToList(audio_source, &additional_audio_source_list_)
334 ? 0
335 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700336}
337
aleloi5d167d62016-08-24 02:20:54 -0700338bool AudioMixerImpl::AnonymousMixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700339 const MixerAudioSource& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700340 rtc::CritScope lock(&crit_);
aleloi09f45102016-07-28 03:52:15 -0700341 return IsAudioSourceInList(audio_source, additional_audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700342}
343
aleloi652ac892016-09-07 07:42:14 -0700344AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() const {
aleloi311525e2016-09-07 06:13:12 -0700345 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi652ac892016-09-07 07:42:14 -0700346 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
347 "GetNonAnonymousAudio()");
aleloif3882572016-07-29 02:12:41 -0700348 AudioFrameList result;
349 std::vector<SourceFrame> audioSourceMixingDataList;
aleloi652ac892016-09-07 07:42:14 -0700350 std::vector<SourceFrame> ramp_list;
aleloi77ad3942016-07-04 06:33:02 -0700351
aleloif3882572016-07-29 02:12:41 -0700352 // Get audio source audio and put it in the struct vector.
353 for (MixerAudioSource* audio_source : audio_source_list_) {
354 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted(
aleloi6382a192016-08-08 10:25:04 -0700355 id_, static_cast<int>(output_frequency_));
aleloi77ad3942016-07-04 06:33:02 -0700356
aleloif3882572016-07-29 02:12:41 -0700357 auto audio_frame_info = audio_frame_with_info.audio_frame_info;
358 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame;
359
360 if (audio_frame_info == MixerAudioSource::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700361 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloif3882572016-07-29 02:12:41 -0700362 "failed to GetAudioFrameWithMuted() from participant");
tereliusea4c1412016-07-29 01:36:14 -0700363 continue;
364 }
aleloif3882572016-07-29 02:12:41 -0700365 audioSourceMixingDataList.emplace_back(
366 audio_source, audio_source_audio_frame,
367 audio_frame_info == MixerAudioSource::AudioFrameInfo::kMuted,
368 audio_source->_mixHistory->WasMixed());
369 }
370
371 // Sort frames by sorting function.
372 std::sort(audioSourceMixingDataList.begin(), audioSourceMixingDataList.end(),
373 std::mem_fn(&SourceFrame::shouldMixBefore));
374
aleloi652ac892016-09-07 07:42:14 -0700375 int maxAudioFrameCounter = kMaximumAmountOfMixedAudioSources;
aleloif3882572016-07-29 02:12:41 -0700376 // Go through list in order and put things in mixList.
377 for (SourceFrame& p : audioSourceMixingDataList) {
378 // Filter muted.
379 if (p.muted_) {
380 p.audio_source_->_mixHistory->SetIsMixed(false);
381 continue;
tereliusea4c1412016-07-29 01:36:14 -0700382 }
aleloi2942e242016-07-29 01:23:49 -0700383
aleloif3882572016-07-29 02:12:41 -0700384 // Add frame to result vector for mixing.
385 bool is_mixed = false;
386 if (maxAudioFrameCounter > 0) {
387 --maxAudioFrameCounter;
aleloi652ac892016-09-07 07:42:14 -0700388 result.push_back(p.audio_frame_);
389 ramp_list.emplace_back(p.audio_source_, p.audio_frame_, false,
390 p.was_mixed_before_, -1);
aleloif3882572016-07-29 02:12:41 -0700391 is_mixed = true;
tereliusea4c1412016-07-29 01:36:14 -0700392 }
aleloif3882572016-07-29 02:12:41 -0700393 p.audio_source_->_mixHistory->SetIsMixed(is_mixed);
tereliusea4c1412016-07-29 01:36:14 -0700394 }
aleloi652ac892016-09-07 07:42:14 -0700395 Ramp(ramp_list);
aleloif3882572016-07-29 02:12:41 -0700396 return result;
aleloi77ad3942016-07-04 06:33:02 -0700397}
398
aleloi652ac892016-09-07 07:42:14 -0700399AudioFrameList AudioMixerImpl::GetAnonymousAudio() const {
aleloi311525e2016-09-07 06:13:12 -0700400 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700401 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi652ac892016-09-07 07:42:14 -0700402 "GetAnonymousAudio()");
aleloi09f45102016-07-28 03:52:15 -0700403 // The GetAudioFrameWithMuted() callback may result in the audio source being
aleloia0db81f2016-07-28 06:36:22 -0700404 // removed from additionalAudioFramesList_. If that happens it will
aleloi09f45102016-07-28 03:52:15 -0700405 // invalidate any iterators. Create a copy of the audio sources list such
aleloia0db81f2016-07-28 06:36:22 -0700406 // that the list of participants can be traversed safely.
aleloi652ac892016-09-07 07:42:14 -0700407 std::vector<SourceFrame> ramp_list;
aleloi09f45102016-07-28 03:52:15 -0700408 MixerAudioSourceList additionalAudioSourceList;
aleloi652ac892016-09-07 07:42:14 -0700409 AudioFrameList result;
aleloi09f45102016-07-28 03:52:15 -0700410 additionalAudioSourceList.insert(additionalAudioSourceList.begin(),
411 additional_audio_source_list_.begin(),
412 additional_audio_source_list_.end());
aleloi77ad3942016-07-04 06:33:02 -0700413
aleloi09f45102016-07-28 03:52:15 -0700414 for (MixerAudioSourceList::const_iterator audio_source =
415 additionalAudioSourceList.begin();
416 audio_source != additionalAudioSourceList.end(); ++audio_source) {
aleloia0db81f2016-07-28 06:36:22 -0700417 auto audio_frame_with_info =
aleloi6382a192016-08-08 10:25:04 -0700418 (*audio_source)->GetAudioFrameWithMuted(id_, output_frequency_);
aleloia0db81f2016-07-28 06:36:22 -0700419 auto ret = audio_frame_with_info.audio_frame_info;
420 AudioFrame* audio_frame = audio_frame_with_info.audio_frame;
aleloi77ad3942016-07-04 06:33:02 -0700421 if (ret == MixerAudioSource::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700422 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700423 "failed to GetAudioFrameWithMuted() from audio_source");
aleloi77ad3942016-07-04 06:33:02 -0700424 continue;
425 }
aleloi652ac892016-09-07 07:42:14 -0700426 if (ret != MixerAudioSource::AudioFrameInfo::kMuted) {
427 result.push_back(audio_frame);
428 ramp_list.emplace_back(*audio_source, audio_frame, false,
429 (*audio_source)->_mixHistory->IsMixed(), -1);
430 (*audio_source)->_mixHistory->SetIsMixed(true);
aleloi77ad3942016-07-04 06:33:02 -0700431 }
aleloi77ad3942016-07-04 06:33:02 -0700432 }
aleloi652ac892016-09-07 07:42:14 -0700433 Ramp(ramp_list);
434 return result;
aleloi77ad3942016-07-04 06:33:02 -0700435}
436
aleloi5d167d62016-08-24 02:20:54 -0700437bool AudioMixerImpl::IsAudioSourceInList(
aleloi09f45102016-07-28 03:52:15 -0700438 const MixerAudioSource& audio_source,
439 const MixerAudioSourceList& audioSourceList) const {
aleloi6382a192016-08-08 10:25:04 -0700440 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700441 "IsAudioSourceInList(audio_source,audioSourceList)");
aleloi6382a192016-08-08 10:25:04 -0700442 return std::find(audioSourceList.begin(), audioSourceList.end(),
443 &audio_source) != audioSourceList.end();
aleloi77ad3942016-07-04 06:33:02 -0700444}
445
aleloi5d167d62016-08-24 02:20:54 -0700446bool AudioMixerImpl::AddAudioSourceToList(
aleloi09f45102016-07-28 03:52:15 -0700447 MixerAudioSource* audio_source,
448 MixerAudioSourceList* audioSourceList) const {
aleloi6382a192016-08-08 10:25:04 -0700449 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700450 "AddAudioSourceToList(audio_source, audioSourceList)");
451 audioSourceList->push_back(audio_source);
aleloi77ad3942016-07-04 06:33:02 -0700452 // Make sure that the mixed status is correct for new MixerAudioSource.
aleloi09f45102016-07-28 03:52:15 -0700453 audio_source->_mixHistory->ResetMixedStatus();
aleloi77ad3942016-07-04 06:33:02 -0700454 return true;
455}
456
aleloi5d167d62016-08-24 02:20:54 -0700457bool AudioMixerImpl::RemoveAudioSourceFromList(
aleloi09f45102016-07-28 03:52:15 -0700458 MixerAudioSource* audio_source,
459 MixerAudioSourceList* audioSourceList) const {
aleloi6382a192016-08-08 10:25:04 -0700460 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700461 "RemoveAudioSourceFromList(audio_source, audioSourceList)");
aleloi6382a192016-08-08 10:25:04 -0700462 auto iter =
463 std::find(audioSourceList->begin(), audioSourceList->end(), audio_source);
464 if (iter != audioSourceList->end()) {
465 audioSourceList->erase(iter);
466 // AudioSource is no longer mixed, reset to default.
467 audio_source->_mixHistory->ResetMixedStatus();
468 return true;
469 } else {
470 return false;
aleloi77ad3942016-07-04 06:33:02 -0700471 }
aleloi77ad3942016-07-04 06:33:02 -0700472}
473
aleloi5d167d62016-08-24 02:20:54 -0700474int32_t AudioMixerImpl::MixFromList(AudioFrame* mixedAudio,
475 const AudioFrameList& audioFrameList,
476 int32_t id,
477 bool use_limiter) {
aleloi09f45102016-07-28 03:52:15 -0700478 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id,
aleloi77ad3942016-07-04 06:33:02 -0700479 "MixFromList(mixedAudio, audioFrameList)");
480 if (audioFrameList.empty())
481 return 0;
482
483 uint32_t position = 0;
484
aleloi09f45102016-07-28 03:52:15 -0700485 if (audioFrameList.size() == 1) {
aleloi652ac892016-09-07 07:42:14 -0700486 mixedAudio->timestamp_ = audioFrameList.front()->timestamp_;
487 mixedAudio->elapsed_time_ms_ = audioFrameList.front()->elapsed_time_ms_;
aleloi77ad3942016-07-04 06:33:02 -0700488 } else {
489 // TODO(wu): Issue 3390.
490 // Audio frame timestamp is only supported in one channel case.
491 mixedAudio->timestamp_ = 0;
492 mixedAudio->elapsed_time_ms_ = -1;
493 }
494
aleloi652ac892016-09-07 07:42:14 -0700495 for (const auto& frame : audioFrameList) {
496 RTC_DCHECK_EQ(mixedAudio->sample_rate_hz_, frame->sample_rate_hz_);
497 RTC_DCHECK_EQ(
498 frame->samples_per_channel_,
499 static_cast<size_t>((mixedAudio->sample_rate_hz_ * kFrameDurationInMs) /
500 1000));
aleloi77ad3942016-07-04 06:33:02 -0700501
aleloi652ac892016-09-07 07:42:14 -0700502 // Mix |f.frame| into |mixedAudio|, with saturation protection.
503 // These effect is applied to |f.frame| itself prior to mixing.
504 if (use_limiter) {
505 // Divide by two to avoid saturation in the mixing.
506 // This is only meaningful if the limiter will be used.
507 *frame >>= 1;
508 }
509 RTC_DCHECK_EQ(frame->num_channels_, mixedAudio->num_channels_);
510 *mixedAudio += *frame;
aleloi77ad3942016-07-04 06:33:02 -0700511 position++;
512 }
aleloi77ad3942016-07-04 06:33:02 -0700513 return 0;
514}
515
aleloi5d167d62016-08-24 02:20:54 -0700516bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixedAudio) const {
aleloi311525e2016-09-07 06:13:12 -0700517 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi77ad3942016-07-04 06:33:02 -0700518 if (!use_limiter_) {
519 return true;
520 }
521
522 // Smoothly limit the mixed frame.
aleloi6382a192016-08-08 10:25:04 -0700523 const int error = limiter_->ProcessStream(mixedAudio);
aleloi77ad3942016-07-04 06:33:02 -0700524
525 // And now we can safely restore the level. This procedure results in
526 // some loss of resolution, deemed acceptable.
527 //
528 // It's possible to apply the gain in the AGC (with a target level of 0 dbFS
529 // and compression gain of 6 dB). However, in the transition frame when this
aleloi09f45102016-07-28 03:52:15 -0700530 // is enabled (moving from one to two audio sources) it has the potential to
aleloi77ad3942016-07-04 06:33:02 -0700531 // create discontinuities in the mixed frame.
532 //
533 // Instead we double the frame (with addition since left-shifting a
534 // negative value is undefined).
535 *mixedAudio += *mixedAudio;
536
aleloi6382a192016-08-08 10:25:04 -0700537 if (error != limiter_->kNoError) {
538 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700539 "Error from AudioProcessing: %d", error);
aleloi09f45102016-07-28 03:52:15 -0700540 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700541 return false;
542 }
543 return true;
544}
aleloi616df1e2016-08-24 01:17:12 -0700545
aleloi5d167d62016-08-24 02:20:54 -0700546int AudioMixerImpl::GetOutputAudioLevel() {
aleloi311525e2016-09-07 06:13:12 -0700547 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700548 const int level = audio_level_.Level();
549 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
550 "GetAudioOutputLevel() => level=%d", level);
551 return level;
552}
553
aleloi5d167d62016-08-24 02:20:54 -0700554int AudioMixerImpl::GetOutputAudioLevelFullRange() {
aleloi311525e2016-09-07 06:13:12 -0700555 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700556 const int level = audio_level_.LevelFullRange();
557 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
558 "GetAudioOutputLevelFullRange() => level=%d", level);
559 return level;
560}
aleloi77ad3942016-07-04 06:33:02 -0700561} // namespace webrtc