blob: 43265a1341e2e7e709511927d2b84c90c6a43256 [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
aleloi36542512016-10-07 05:28:32 -070017#include "webrtc/base/logging.h"
aleloi5bcc00e2016-08-15 03:01:31 -070018#include "webrtc/modules/audio_mixer/audio_frame_manipulator.h"
aleloi77ad3942016-07-04 06:33:02 -070019#include "webrtc/modules/utility/include/audio_frame_operations.h"
aleloi77ad3942016-07-04 06:33:02 -070020#include "webrtc/system_wrappers/include/trace.h"
21
22namespace webrtc {
23namespace {
24
aleloif3882572016-07-29 02:12:41 -070025class SourceFrame {
26 public:
aleloi36542512016-10-07 05:28:32 -070027 SourceFrame(AudioSourceWithMixStatus* audio_source,
28 AudioFrame* audio_frame,
29 bool muted)
30 : audio_source_(audio_source), audio_frame_(audio_frame), muted_(muted) {
aleloif3882572016-07-29 02:12:41 -070031 if (!muted_) {
aleloi36542512016-10-07 05:28:32 -070032 energy_ = AudioMixerCalculateEnergy(*audio_frame);
aleloif3882572016-07-29 02:12:41 -070033 }
34 }
aleloi77ad3942016-07-04 06:33:02 -070035
aleloi36542512016-10-07 05:28:32 -070036 SourceFrame(AudioSourceWithMixStatus* audio_source,
37 AudioFrame* audio_frame,
38 bool muted,
aleloi652ac892016-09-07 07:42:14 -070039 uint32_t energy)
aleloi36542512016-10-07 05:28:32 -070040 : audio_source_(audio_source),
41 audio_frame_(audio_frame),
42 muted_(muted),
43 energy_(energy) {}
aleloi652ac892016-09-07 07:42:14 -070044
aleloi36542512016-10-07 05:28:32 -070045 // a.ShouldMixBefore(b) is used to select mixer sources.
46 bool ShouldMixBefore(const SourceFrame& other) const {
aleloif3882572016-07-29 02:12:41 -070047 if (muted_ != other.muted_) {
48 return other.muted_;
49 }
50
aleloia4c21062016-09-08 01:25:46 -070051 const auto our_activity = audio_frame_->vad_activity_;
52 const auto other_activity = other.audio_frame_->vad_activity_;
aleloif3882572016-07-29 02:12:41 -070053
54 if (our_activity != other_activity) {
55 return our_activity == AudioFrame::kVadActive;
56 }
57
58 return energy_ > other.energy_;
59 }
60
aleloi36542512016-10-07 05:28:32 -070061 AudioSourceWithMixStatus* audio_source_ = nullptr;
62 AudioFrame* audio_frame_ = nullptr;
63 bool muted_ = true;
64 uint32_t energy_ = 0;
aleloif3882572016-07-29 02:12:41 -070065};
tereliusea4c1412016-07-29 01:36:14 -070066
aleloi44968092016-08-08 10:18:58 -070067// Remixes a frame between stereo and mono.
68void RemixFrame(AudioFrame* frame, size_t number_of_channels) {
69 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
70 if (frame->num_channels_ == 1 && number_of_channels == 2) {
71 AudioFrameOperations::MonoToStereo(frame);
72 } else if (frame->num_channels_ == 2 && number_of_channels == 1) {
73 AudioFrameOperations::StereoToMono(frame);
74 }
75}
76
aleloi652ac892016-09-07 07:42:14 -070077void Ramp(const std::vector<SourceFrame>& mixed_sources_and_frames) {
78 for (const auto& source_frame : mixed_sources_and_frames) {
79 // Ramp in previously unmixed.
aleloi36542512016-10-07 05:28:32 -070080 if (!source_frame.audio_source_->WasMixed()) {
aleloi652ac892016-09-07 07:42:14 -070081 NewMixerRampIn(source_frame.audio_frame_);
82 }
83
aleloidc7669a2016-10-04 04:06:20 -070084 const bool is_mixed = source_frame.audio_source_->IsMixed();
aleloi652ac892016-09-07 07:42:14 -070085 // Ramp out currently unmixed.
aleloi36542512016-10-07 05:28:32 -070086 if (source_frame.audio_source_->WasMixed() && !is_mixed) {
aleloi652ac892016-09-07 07:42:14 -070087 NewMixerRampOut(source_frame.audio_frame_);
88 }
aleloi77ad3942016-07-04 06:33:02 -070089 }
aleloi77ad3942016-07-04 06:33:02 -070090}
91
aleloidc7669a2016-10-04 04:06:20 -070092// Mix the AudioFrames stored in audioFrameList into mixed_audio.
93int32_t MixFromList(AudioFrame* mixed_audio,
94 const AudioFrameList& audio_frame_list,
95 int32_t id,
96 bool use_limiter) {
97 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id,
98 "MixFromList(mixed_audio, audio_frame_list)");
99 if (audio_frame_list.empty())
100 return 0;
aleloi77ad3942016-07-04 06:33:02 -0700101
aleloidc7669a2016-10-04 04:06:20 -0700102 if (audio_frame_list.size() == 1) {
103 mixed_audio->timestamp_ = audio_frame_list.front()->timestamp_;
104 mixed_audio->elapsed_time_ms_ = audio_frame_list.front()->elapsed_time_ms_;
105 } else {
106 // TODO(wu): Issue 3390.
107 // Audio frame timestamp is only supported in one channel case.
108 mixed_audio->timestamp_ = 0;
109 mixed_audio->elapsed_time_ms_ = -1;
110 }
aleloi77ad3942016-07-04 06:33:02 -0700111
aleloidc7669a2016-10-04 04:06:20 -0700112 for (const auto& frame : audio_frame_list) {
113 RTC_DCHECK_EQ(mixed_audio->sample_rate_hz_, frame->sample_rate_hz_);
114 RTC_DCHECK_EQ(
115 frame->samples_per_channel_,
116 static_cast<size_t>((mixed_audio->sample_rate_hz_ *
117 webrtc::AudioMixerImpl::kFrameDurationInMs) /
118 1000));
aleloi77ad3942016-07-04 06:33:02 -0700119
aleloidc7669a2016-10-04 04:06:20 -0700120 // Mix |f.frame| into |mixed_audio|, with saturation protection.
121 // These effect is applied to |f.frame| itself prior to mixing.
122 if (use_limiter) {
123 // Divide by two to avoid saturation in the mixing.
124 // This is only meaningful if the limiter will be used.
125 *frame >>= 1;
126 }
127 RTC_DCHECK_EQ(frame->num_channels_, mixed_audio->num_channels_);
128 *mixed_audio += *frame;
129 }
aleloi77ad3942016-07-04 06:33:02 -0700130 return 0;
131}
132
aleloi36542512016-10-07 05:28:32 -0700133MixerAudioSourceList::const_iterator FindSourceInList(
134 MixerAudioSource const* audio_source,
135 MixerAudioSourceList const* audio_source_list) {
136 return std::find_if(audio_source_list->begin(), audio_source_list->end(),
137 [audio_source](const AudioSourceWithMixStatus& p) {
138 return p.audio_source() == audio_source;
139 });
140}
141
142MixerAudioSourceList::iterator FindSourceInList(
143 MixerAudioSource const* audio_source,
144 MixerAudioSourceList* audio_source_list) {
145 return std::find_if(audio_source_list->begin(), audio_source_list->end(),
146 [audio_source](const AudioSourceWithMixStatus& p) {
147 return p.audio_source() == audio_source;
148 });
149}
150
aleloidc7669a2016-10-04 04:06:20 -0700151} // namespace
aleloi77ad3942016-07-04 06:33:02 -0700152
aleloi5d167d62016-08-24 02:20:54 -0700153std::unique_ptr<AudioMixer> AudioMixer::Create(int id) {
aleloi311525e2016-09-07 06:13:12 -0700154 return AudioMixerImpl::Create(id);
aleloi77ad3942016-07-04 06:33:02 -0700155}
156
aleloi311525e2016-09-07 06:13:12 -0700157AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter)
aleloi6382a192016-08-08 10:25:04 -0700158 : id_(id),
aleloi09f45102016-07-28 03:52:15 -0700159 audio_source_list_(),
160 additional_audio_source_list_(),
161 num_mixed_audio_sources_(0),
aleloi77ad3942016-07-04 06:33:02 -0700162 use_limiter_(true),
aleloi311525e2016-09-07 06:13:12 -0700163 time_stamp_(0),
164 limiter_(std::move(limiter)) {
165 SetOutputFrequency(kDefaultFrequency);
aleloi8b2233f2016-07-28 06:24:14 -0700166 thread_checker_.DetachFromThread();
aleloia0db81f2016-07-28 06:36:22 -0700167}
aleloi77ad3942016-07-04 06:33:02 -0700168
aleloi5d167d62016-08-24 02:20:54 -0700169AudioMixerImpl::~AudioMixerImpl() {}
aleloi70f866c2016-08-16 02:15:49 -0700170
aleloi36542512016-10-07 05:28:32 -0700171std::unique_ptr<AudioMixerImpl> AudioMixerImpl::Create(int id) {
aleloi77ad3942016-07-04 06:33:02 -0700172 Config config;
173 config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
aleloi311525e2016-09-07 06:13:12 -0700174 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config));
175 if (!limiter.get())
176 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700177
aleloi311525e2016-09-07 06:13:12 -0700178 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) !=
179 limiter->kNoError)
180 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700181
182 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the
183 // divide-by-2 but -7 is used instead to give a bit of headroom since the
184 // AGC is not a hard limiter.
aleloi311525e2016-09-07 06:13:12 -0700185 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError)
186 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700187
aleloi311525e2016-09-07 06:13:12 -0700188 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError)
189 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700190
aleloi311525e2016-09-07 06:13:12 -0700191 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError)
192 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700193
aleloi311525e2016-09-07 06:13:12 -0700194 if (limiter->gain_control()->Enable(true) != limiter->kNoError)
195 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700196
aleloi36542512016-10-07 05:28:32 -0700197 return std::unique_ptr<AudioMixerImpl>(
aleloi311525e2016-09-07 06:13:12 -0700198 new AudioMixerImpl(id, std::move(limiter)));
aleloi77ad3942016-07-04 06:33:02 -0700199}
200
aleloi5d167d62016-08-24 02:20:54 -0700201void AudioMixerImpl::Mix(int sample_rate,
202 size_t number_of_channels,
203 AudioFrame* audio_frame_for_mixing) {
aleloi44968092016-08-08 10:18:58 -0700204 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
aleloi311525e2016-09-07 06:13:12 -0700205 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi311525e2016-09-07 06:13:12 -0700206
207 if (sample_rate != kNbInHz && sample_rate != kWbInHz &&
208 sample_rate != kSwbInHz && sample_rate != kFbInHz) {
209 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
210 "Invalid frequency: %d", sample_rate);
211 RTC_NOTREACHED();
212 return;
213 }
214
215 if (OutputFrequency() != sample_rate) {
216 SetOutputFrequency(static_cast<Frequency>(sample_rate));
217 }
218
aleloi652ac892016-09-07 07:42:14 -0700219 AudioFrameList mix_list;
220 AudioFrameList anonymous_mix_list;
aleloidc7669a2016-10-04 04:06:20 -0700221 size_t num_mixed_audio_sources;
aleloi77ad3942016-07-04 06:33:02 -0700222 {
aleloi311525e2016-09-07 06:13:12 -0700223 rtc::CritScope lock(&crit_);
aleloi652ac892016-09-07 07:42:14 -0700224 mix_list = GetNonAnonymousAudio();
225 anonymous_mix_list = GetAnonymousAudio();
aleloidc7669a2016-10-04 04:06:20 -0700226 num_mixed_audio_sources = num_mixed_audio_sources_;
aleloi77ad3942016-07-04 06:33:02 -0700227 }
228
aleloi652ac892016-09-07 07:42:14 -0700229 mix_list.insert(mix_list.begin(), anonymous_mix_list.begin(),
230 anonymous_mix_list.end());
231
232 for (const auto& frame : mix_list) {
233 RemixFrame(frame, number_of_channels);
aleloi44968092016-08-08 10:18:58 -0700234 }
aleloi09f45102016-07-28 03:52:15 -0700235
236 audio_frame_for_mixing->UpdateFrame(
aleloia4c21062016-09-08 01:25:46 -0700237 -1, time_stamp_, NULL, 0, OutputFrequency(), AudioFrame::kNormalSpeech,
aleloi44968092016-08-08 10:18:58 -0700238 AudioFrame::kVadPassive, number_of_channels);
aleloi09f45102016-07-28 03:52:15 -0700239
aleloi6382a192016-08-08 10:25:04 -0700240 time_stamp_ += static_cast<uint32_t>(sample_size_);
aleloi09f45102016-07-28 03:52:15 -0700241
aleloi311525e2016-09-07 06:13:12 -0700242 use_limiter_ = num_mixed_audio_sources > 1;
aleloi09f45102016-07-28 03:52:15 -0700243
aleloi652ac892016-09-07 07:42:14 -0700244 // We only use the limiter if we're actually mixing multiple streams.
245 MixFromList(audio_frame_for_mixing, mix_list, id_, use_limiter_);
246
aleloi311525e2016-09-07 06:13:12 -0700247 if (audio_frame_for_mixing->samples_per_channel_ == 0) {
248 // Nothing was mixed, set the audio samples to silence.
249 audio_frame_for_mixing->samples_per_channel_ = sample_size_;
250 audio_frame_for_mixing->Mute();
251 } else {
252 // Only call the limiter if we have something to mix.
253 LimitMixedAudio(audio_frame_for_mixing);
aleloi77ad3942016-07-04 06:33:02 -0700254 }
aleloi616df1e2016-08-24 01:17:12 -0700255
256 // Pass the final result to the level indicator.
257 audio_level_.ComputeLevel(*audio_frame_for_mixing);
258
aleloi77ad3942016-07-04 06:33:02 -0700259 return;
260}
261
aleloi5d167d62016-08-24 02:20:54 -0700262int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) {
aleloi311525e2016-09-07 06:13:12 -0700263 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700264 output_frequency_ = frequency;
aleloidc7669a2016-10-04 04:06:20 -0700265 sample_size_ = (output_frequency_ * kFrameDurationInMs) / 1000;
aleloi77ad3942016-07-04 06:33:02 -0700266
267 return 0;
268}
269
aleloi5d167d62016-08-24 02:20:54 -0700270AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const {
aleloi311525e2016-09-07 06:13:12 -0700271 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700272 return output_frequency_;
aleloi77ad3942016-07-04 06:33:02 -0700273}
274
aleloi5d167d62016-08-24 02:20:54 -0700275int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source,
276 bool mixable) {
aleloi77ad3942016-07-04 06:33:02 -0700277 if (!mixable) {
aleloi09f45102016-07-28 03:52:15 -0700278 // Anonymous audio sources are in a separate list. Make sure that the
279 // audio source is in the _audioSourceList if it is being mixed.
280 SetAnonymousMixabilityStatus(audio_source, false);
aleloi77ad3942016-07-04 06:33:02 -0700281 }
aleloi77ad3942016-07-04 06:33:02 -0700282 {
aleloi311525e2016-09-07 06:13:12 -0700283 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700284 const bool is_mixed = FindSourceInList(audio_source, &audio_source_list_) !=
285 audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700286 // API must be called with a new state.
aleloia4c21062016-09-08 01:25:46 -0700287 if (!(mixable ^ is_mixed)) {
aleloi6382a192016-08-08 10:25:04 -0700288 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700289 "Mixable is aready %s", is_mixed ? "ON" : "off");
aleloi77ad3942016-07-04 06:33:02 -0700290 return -1;
291 }
292 bool success = false;
293 if (mixable) {
aleloi09f45102016-07-28 03:52:15 -0700294 success = AddAudioSourceToList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700295 } else {
aleloi09f45102016-07-28 03:52:15 -0700296 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700297 }
298 if (!success) {
aleloi6382a192016-08-08 10:25:04 -0700299 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700300 "failed to %s audio_source", mixable ? "add" : "remove");
301 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700302 return -1;
303 }
304
aleloia4c21062016-09-08 01:25:46 -0700305 size_t num_mixed_non_anonymous = audio_source_list_.size();
306 if (num_mixed_non_anonymous > kMaximumAmountOfMixedAudioSources) {
307 num_mixed_non_anonymous = kMaximumAmountOfMixedAudioSources;
aleloi77ad3942016-07-04 06:33:02 -0700308 }
aleloi311525e2016-09-07 06:13:12 -0700309 num_mixed_audio_sources_ =
aleloia4c21062016-09-08 01:25:46 -0700310 num_mixed_non_anonymous + additional_audio_source_list_.size();
aleloi77ad3942016-07-04 06:33:02 -0700311 }
aleloi77ad3942016-07-04 06:33:02 -0700312 return 0;
313}
314
aleloi5d167d62016-08-24 02:20:54 -0700315bool AudioMixerImpl::MixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700316 const MixerAudioSource& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700317 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700318 return FindSourceInList(&audio_source, &audio_source_list_) !=
319 audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700320}
321
aleloi5d167d62016-08-24 02:20:54 -0700322int32_t AudioMixerImpl::SetAnonymousMixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700323 MixerAudioSource* audio_source,
aleloi77ad3942016-07-04 06:33:02 -0700324 bool anonymous) {
aleloi311525e2016-09-07 06:13:12 -0700325 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700326 if (FindSourceInList(audio_source, &additional_audio_source_list_) !=
327 additional_audio_source_list_.end()) {
aleloi77ad3942016-07-04 06:33:02 -0700328 if (anonymous) {
329 return 0;
330 }
aleloi09f45102016-07-28 03:52:15 -0700331 if (!RemoveAudioSourceFromList(audio_source,
332 &additional_audio_source_list_)) {
aleloi6382a192016-08-08 10:25:04 -0700333 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700334 "unable to remove audio_source from anonymous list");
335 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700336 return -1;
337 }
aleloi09f45102016-07-28 03:52:15 -0700338 return AddAudioSourceToList(audio_source, &audio_source_list_) ? 0 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700339 }
340 if (!anonymous) {
341 return 0;
342 }
343 const bool mixable =
aleloi09f45102016-07-28 03:52:15 -0700344 RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700345 if (!mixable) {
346 WEBRTC_TRACE(
aleloi6382a192016-08-08 10:25:04 -0700347 kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700348 "audio_source must be registered before turning it into anonymous");
aleloi77ad3942016-07-04 06:33:02 -0700349 // Setting anonymous status is only possible if MixerAudioSource is
350 // already registered.
351 return -1;
352 }
aleloi09f45102016-07-28 03:52:15 -0700353 return AddAudioSourceToList(audio_source, &additional_audio_source_list_)
354 ? 0
355 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700356}
357
aleloi5d167d62016-08-24 02:20:54 -0700358bool AudioMixerImpl::AnonymousMixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700359 const MixerAudioSource& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700360 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700361 return FindSourceInList(&audio_source, &additional_audio_source_list_) !=
362 additional_audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700363}
364
aleloi36542512016-10-07 05:28:32 -0700365AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() {
aleloi311525e2016-09-07 06:13:12 -0700366 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi652ac892016-09-07 07:42:14 -0700367 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
368 "GetNonAnonymousAudio()");
aleloif3882572016-07-29 02:12:41 -0700369 AudioFrameList result;
aleloia4c21062016-09-08 01:25:46 -0700370 std::vector<SourceFrame> audio_source_mixing_data_list;
aleloi652ac892016-09-07 07:42:14 -0700371 std::vector<SourceFrame> ramp_list;
aleloi77ad3942016-07-04 06:33:02 -0700372
aleloif3882572016-07-29 02:12:41 -0700373 // Get audio source audio and put it in the struct vector.
aleloi36542512016-10-07 05:28:32 -0700374 for (auto& source_and_status : audio_source_list_) {
375 auto audio_frame_with_info =
376 source_and_status.audio_source()->GetAudioFrameWithMuted(
377 id_, static_cast<int>(OutputFrequency()));
aleloi77ad3942016-07-04 06:33:02 -0700378
aleloia4c21062016-09-08 01:25:46 -0700379 const auto audio_frame_info = audio_frame_with_info.audio_frame_info;
aleloif3882572016-07-29 02:12:41 -0700380 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame;
381
382 if (audio_frame_info == MixerAudioSource::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700383 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi36542512016-10-07 05:28:32 -0700384 "failed to GetAudioFrameWithMuted() from source");
tereliusea4c1412016-07-29 01:36:14 -0700385 continue;
386 }
aleloia4c21062016-09-08 01:25:46 -0700387 audio_source_mixing_data_list.emplace_back(
aleloi36542512016-10-07 05:28:32 -0700388 &source_and_status, audio_source_audio_frame,
389 audio_frame_info == MixerAudioSource::AudioFrameInfo::kMuted);
aleloif3882572016-07-29 02:12:41 -0700390 }
391
392 // Sort frames by sorting function.
aleloia4c21062016-09-08 01:25:46 -0700393 std::sort(audio_source_mixing_data_list.begin(),
394 audio_source_mixing_data_list.end(),
aleloi36542512016-10-07 05:28:32 -0700395 std::mem_fn(&SourceFrame::ShouldMixBefore));
aleloif3882572016-07-29 02:12:41 -0700396
aleloia4c21062016-09-08 01:25:46 -0700397 int max_audio_frame_counter = kMaximumAmountOfMixedAudioSources;
398
399 // Go through list in order and put unmuted frames in result list.
aleloi36542512016-10-07 05:28:32 -0700400 for (const auto& p : audio_source_mixing_data_list) {
aleloif3882572016-07-29 02:12:41 -0700401 // Filter muted.
402 if (p.muted_) {
aleloidc7669a2016-10-04 04:06:20 -0700403 p.audio_source_->SetIsMixed(false);
aleloif3882572016-07-29 02:12:41 -0700404 continue;
tereliusea4c1412016-07-29 01:36:14 -0700405 }
aleloi2942e242016-07-29 01:23:49 -0700406
aleloif3882572016-07-29 02:12:41 -0700407 // Add frame to result vector for mixing.
408 bool is_mixed = false;
aleloia4c21062016-09-08 01:25:46 -0700409 if (max_audio_frame_counter > 0) {
410 --max_audio_frame_counter;
aleloi652ac892016-09-07 07:42:14 -0700411 result.push_back(p.audio_frame_);
aleloi36542512016-10-07 05:28:32 -0700412 ramp_list.emplace_back(p.audio_source_, p.audio_frame_, false, -1);
aleloif3882572016-07-29 02:12:41 -0700413 is_mixed = true;
tereliusea4c1412016-07-29 01:36:14 -0700414 }
aleloidc7669a2016-10-04 04:06:20 -0700415 p.audio_source_->SetIsMixed(is_mixed);
tereliusea4c1412016-07-29 01:36:14 -0700416 }
aleloi652ac892016-09-07 07:42:14 -0700417 Ramp(ramp_list);
aleloif3882572016-07-29 02:12:41 -0700418 return result;
aleloi77ad3942016-07-04 06:33:02 -0700419}
420
aleloi36542512016-10-07 05:28:32 -0700421AudioFrameList AudioMixerImpl::GetAnonymousAudio() {
aleloi311525e2016-09-07 06:13:12 -0700422 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700423 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi652ac892016-09-07 07:42:14 -0700424 "GetAnonymousAudio()");
aleloi652ac892016-09-07 07:42:14 -0700425 std::vector<SourceFrame> ramp_list;
aleloi652ac892016-09-07 07:42:14 -0700426 AudioFrameList result;
aleloi36542512016-10-07 05:28:32 -0700427 for (auto& source_and_status : additional_audio_source_list_) {
aleloia4c21062016-09-08 01:25:46 -0700428 const auto audio_frame_with_info =
aleloi36542512016-10-07 05:28:32 -0700429 source_and_status.audio_source()->GetAudioFrameWithMuted(
430 id_, OutputFrequency());
aleloia4c21062016-09-08 01:25:46 -0700431 const auto ret = audio_frame_with_info.audio_frame_info;
aleloia0db81f2016-07-28 06:36:22 -0700432 AudioFrame* audio_frame = audio_frame_with_info.audio_frame;
aleloi77ad3942016-07-04 06:33:02 -0700433 if (ret == MixerAudioSource::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700434 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700435 "failed to GetAudioFrameWithMuted() from audio_source");
aleloi77ad3942016-07-04 06:33:02 -0700436 continue;
437 }
aleloi652ac892016-09-07 07:42:14 -0700438 if (ret != MixerAudioSource::AudioFrameInfo::kMuted) {
439 result.push_back(audio_frame);
aleloi36542512016-10-07 05:28:32 -0700440 ramp_list.emplace_back(&source_and_status, audio_frame, false, 0);
441 source_and_status.SetIsMixed(true);
aleloi77ad3942016-07-04 06:33:02 -0700442 }
aleloi77ad3942016-07-04 06:33:02 -0700443 }
aleloi652ac892016-09-07 07:42:14 -0700444 Ramp(ramp_list);
445 return result;
aleloi77ad3942016-07-04 06:33:02 -0700446}
447
aleloi5d167d62016-08-24 02:20:54 -0700448bool AudioMixerImpl::AddAudioSourceToList(
aleloi09f45102016-07-28 03:52:15 -0700449 MixerAudioSource* audio_source,
aleloia4c21062016-09-08 01:25:46 -0700450 MixerAudioSourceList* audio_source_list) const {
aleloi6382a192016-08-08 10:25:04 -0700451 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700452 "AddAudioSourceToList(audio_source, audio_source_list)");
aleloi36542512016-10-07 05:28:32 -0700453 audio_source_list->emplace_back(audio_source);
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,
aleloia4c21062016-09-08 01:25:46 -0700459 MixerAudioSourceList* audio_source_list) const {
aleloi6382a192016-08-08 10:25:04 -0700460 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700461 "RemoveAudioSourceFromList(audio_source, audio_source_list)");
aleloi36542512016-10-07 05:28:32 -0700462 const auto iter = FindSourceInList(audio_source, audio_source_list);
aleloia4c21062016-09-08 01:25:46 -0700463 if (iter != audio_source_list->end()) {
464 audio_source_list->erase(iter);
aleloi6382a192016-08-08 10:25:04 -0700465 return true;
466 } else {
467 return false;
aleloi77ad3942016-07-04 06:33:02 -0700468 }
aleloi77ad3942016-07-04 06:33:02 -0700469}
470
aleloia4c21062016-09-08 01:25:46 -0700471bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixed_audio) const {
aleloi311525e2016-09-07 06:13:12 -0700472 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi77ad3942016-07-04 06:33:02 -0700473 if (!use_limiter_) {
474 return true;
475 }
476
477 // Smoothly limit the mixed frame.
aleloia4c21062016-09-08 01:25:46 -0700478 const int error = limiter_->ProcessStream(mixed_audio);
aleloi77ad3942016-07-04 06:33:02 -0700479
480 // And now we can safely restore the level. This procedure results in
481 // some loss of resolution, deemed acceptable.
482 //
483 // It's possible to apply the gain in the AGC (with a target level of 0 dbFS
484 // and compression gain of 6 dB). However, in the transition frame when this
aleloi09f45102016-07-28 03:52:15 -0700485 // is enabled (moving from one to two audio sources) it has the potential to
aleloi77ad3942016-07-04 06:33:02 -0700486 // create discontinuities in the mixed frame.
487 //
488 // Instead we double the frame (with addition since left-shifting a
489 // negative value is undefined).
aleloia4c21062016-09-08 01:25:46 -0700490 *mixed_audio += *mixed_audio;
aleloi77ad3942016-07-04 06:33:02 -0700491
aleloi6382a192016-08-08 10:25:04 -0700492 if (error != limiter_->kNoError) {
493 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700494 "Error from AudioProcessing: %d", error);
aleloi09f45102016-07-28 03:52:15 -0700495 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700496 return false;
497 }
498 return true;
499}
aleloi616df1e2016-08-24 01:17:12 -0700500
aleloi5d167d62016-08-24 02:20:54 -0700501int AudioMixerImpl::GetOutputAudioLevel() {
aleloi311525e2016-09-07 06:13:12 -0700502 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700503 const int level = audio_level_.Level();
504 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
505 "GetAudioOutputLevel() => level=%d", level);
506 return level;
507}
508
aleloi5d167d62016-08-24 02:20:54 -0700509int AudioMixerImpl::GetOutputAudioLevelFullRange() {
aleloi311525e2016-09-07 06:13:12 -0700510 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700511 const int level = audio_level_.LevelFullRange();
512 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
513 "GetAudioOutputLevelFullRange() => level=%d", level);
514 return level;
515}
aleloi36542512016-10-07 05:28:32 -0700516
517bool AudioMixerImpl::GetAudioSourceMixabilityStatusForTest(
518 MixerAudioSource* audio_source) {
519 RTC_DCHECK_RUN_ON(&thread_checker_);
520 rtc::CritScope lock(&crit_);
521
522 const auto non_anonymous_iter =
523 FindSourceInList(audio_source, &audio_source_list_);
524 if (non_anonymous_iter != audio_source_list_.end()) {
525 return non_anonymous_iter->IsMixed();
526 }
527
528 const auto anonymous_iter =
529 FindSourceInList(audio_source, &additional_audio_source_list_);
530 if (anonymous_iter != audio_source_list_.end()) {
531 return anonymous_iter->IsMixed();
532 }
533
534 LOG(LS_ERROR) << "Audio source unknown";
535 return false;
536}
aleloi77ad3942016-07-04 06:33:02 -0700537} // namespace webrtc