blob: dd084af37156662c9c6c00b8a057e998ba539568 [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
aleloi652ac892016-09-07 07:42:14 -070068void Ramp(const std::vector<SourceFrame>& mixed_sources_and_frames) {
69 for (const auto& source_frame : mixed_sources_and_frames) {
70 // Ramp in previously unmixed.
aleloi36542512016-10-07 05:28:32 -070071 if (!source_frame.audio_source_->WasMixed()) {
aleloi652ac892016-09-07 07:42:14 -070072 NewMixerRampIn(source_frame.audio_frame_);
73 }
74
aleloidc7669a2016-10-04 04:06:20 -070075 const bool is_mixed = source_frame.audio_source_->IsMixed();
aleloi652ac892016-09-07 07:42:14 -070076 // Ramp out currently unmixed.
aleloi36542512016-10-07 05:28:32 -070077 if (source_frame.audio_source_->WasMixed() && !is_mixed) {
aleloi652ac892016-09-07 07:42:14 -070078 NewMixerRampOut(source_frame.audio_frame_);
79 }
aleloi77ad3942016-07-04 06:33:02 -070080 }
aleloi77ad3942016-07-04 06:33:02 -070081}
82
aleloidc7669a2016-10-04 04:06:20 -070083// Mix the AudioFrames stored in audioFrameList into mixed_audio.
84int32_t MixFromList(AudioFrame* mixed_audio,
85 const AudioFrameList& audio_frame_list,
86 int32_t id,
87 bool use_limiter) {
88 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id,
89 "MixFromList(mixed_audio, audio_frame_list)");
90 if (audio_frame_list.empty())
91 return 0;
aleloi77ad3942016-07-04 06:33:02 -070092
aleloidc7669a2016-10-04 04:06:20 -070093 if (audio_frame_list.size() == 1) {
94 mixed_audio->timestamp_ = audio_frame_list.front()->timestamp_;
95 mixed_audio->elapsed_time_ms_ = audio_frame_list.front()->elapsed_time_ms_;
96 } else {
97 // TODO(wu): Issue 3390.
98 // Audio frame timestamp is only supported in one channel case.
99 mixed_audio->timestamp_ = 0;
100 mixed_audio->elapsed_time_ms_ = -1;
101 }
aleloi77ad3942016-07-04 06:33:02 -0700102
aleloidc7669a2016-10-04 04:06:20 -0700103 for (const auto& frame : audio_frame_list) {
104 RTC_DCHECK_EQ(mixed_audio->sample_rate_hz_, frame->sample_rate_hz_);
105 RTC_DCHECK_EQ(
106 frame->samples_per_channel_,
107 static_cast<size_t>((mixed_audio->sample_rate_hz_ *
108 webrtc::AudioMixerImpl::kFrameDurationInMs) /
109 1000));
aleloi77ad3942016-07-04 06:33:02 -0700110
aleloidc7669a2016-10-04 04:06:20 -0700111 // Mix |f.frame| into |mixed_audio|, with saturation protection.
112 // These effect is applied to |f.frame| itself prior to mixing.
113 if (use_limiter) {
114 // Divide by two to avoid saturation in the mixing.
115 // This is only meaningful if the limiter will be used.
116 *frame >>= 1;
117 }
118 RTC_DCHECK_EQ(frame->num_channels_, mixed_audio->num_channels_);
119 *mixed_audio += *frame;
120 }
aleloi77ad3942016-07-04 06:33:02 -0700121 return 0;
122}
123
aleloi36542512016-10-07 05:28:32 -0700124MixerAudioSourceList::const_iterator FindSourceInList(
aleloie8914152016-10-11 06:18:31 -0700125 AudioMixerImpl::Source const* audio_source,
aleloi36542512016-10-07 05:28:32 -0700126 MixerAudioSourceList const* audio_source_list) {
127 return std::find_if(audio_source_list->begin(), audio_source_list->end(),
128 [audio_source](const AudioSourceWithMixStatus& p) {
129 return p.audio_source() == audio_source;
130 });
131}
132
133MixerAudioSourceList::iterator FindSourceInList(
aleloie8914152016-10-11 06:18:31 -0700134 AudioMixerImpl::Source const* audio_source,
aleloi36542512016-10-07 05:28:32 -0700135 MixerAudioSourceList* 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
aleloidc7669a2016-10-04 04:06:20 -0700142} // namespace
aleloi77ad3942016-07-04 06:33:02 -0700143
aleloi5d167d62016-08-24 02:20:54 -0700144std::unique_ptr<AudioMixer> AudioMixer::Create(int id) {
aleloi311525e2016-09-07 06:13:12 -0700145 return AudioMixerImpl::Create(id);
aleloi77ad3942016-07-04 06:33:02 -0700146}
147
aleloi311525e2016-09-07 06:13:12 -0700148AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter)
aleloi6382a192016-08-08 10:25:04 -0700149 : id_(id),
aleloi09f45102016-07-28 03:52:15 -0700150 audio_source_list_(),
151 additional_audio_source_list_(),
152 num_mixed_audio_sources_(0),
aleloi77ad3942016-07-04 06:33:02 -0700153 use_limiter_(true),
aleloi311525e2016-09-07 06:13:12 -0700154 time_stamp_(0),
155 limiter_(std::move(limiter)) {
156 SetOutputFrequency(kDefaultFrequency);
aleloi8b2233f2016-07-28 06:24:14 -0700157 thread_checker_.DetachFromThread();
aleloia0db81f2016-07-28 06:36:22 -0700158}
aleloi77ad3942016-07-04 06:33:02 -0700159
aleloi5d167d62016-08-24 02:20:54 -0700160AudioMixerImpl::~AudioMixerImpl() {}
aleloi70f866c2016-08-16 02:15:49 -0700161
aleloi36542512016-10-07 05:28:32 -0700162std::unique_ptr<AudioMixerImpl> AudioMixerImpl::Create(int id) {
aleloi77ad3942016-07-04 06:33:02 -0700163 Config config;
164 config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
aleloi311525e2016-09-07 06:13:12 -0700165 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config));
166 if (!limiter.get())
167 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700168
aleloi311525e2016-09-07 06:13:12 -0700169 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) !=
170 limiter->kNoError)
171 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700172
173 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the
174 // divide-by-2 but -7 is used instead to give a bit of headroom since the
175 // AGC is not a hard limiter.
aleloi311525e2016-09-07 06:13:12 -0700176 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError)
177 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700178
aleloi311525e2016-09-07 06:13:12 -0700179 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError)
180 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700181
aleloi311525e2016-09-07 06:13:12 -0700182 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError)
183 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700184
aleloi311525e2016-09-07 06:13:12 -0700185 if (limiter->gain_control()->Enable(true) != limiter->kNoError)
186 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700187
aleloi36542512016-10-07 05:28:32 -0700188 return std::unique_ptr<AudioMixerImpl>(
aleloi311525e2016-09-07 06:13:12 -0700189 new AudioMixerImpl(id, std::move(limiter)));
aleloi77ad3942016-07-04 06:33:02 -0700190}
191
aleloi5d167d62016-08-24 02:20:54 -0700192void AudioMixerImpl::Mix(int sample_rate,
193 size_t number_of_channels,
194 AudioFrame* audio_frame_for_mixing) {
aleloi44968092016-08-08 10:18:58 -0700195 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
aleloi311525e2016-09-07 06:13:12 -0700196 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi311525e2016-09-07 06:13:12 -0700197
198 if (sample_rate != kNbInHz && sample_rate != kWbInHz &&
199 sample_rate != kSwbInHz && sample_rate != kFbInHz) {
200 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
201 "Invalid frequency: %d", sample_rate);
202 RTC_NOTREACHED();
203 return;
204 }
205
206 if (OutputFrequency() != sample_rate) {
207 SetOutputFrequency(static_cast<Frequency>(sample_rate));
208 }
209
aleloi652ac892016-09-07 07:42:14 -0700210 AudioFrameList mix_list;
211 AudioFrameList anonymous_mix_list;
aleloidc7669a2016-10-04 04:06:20 -0700212 size_t num_mixed_audio_sources;
aleloi77ad3942016-07-04 06:33:02 -0700213 {
aleloi311525e2016-09-07 06:13:12 -0700214 rtc::CritScope lock(&crit_);
aleloi652ac892016-09-07 07:42:14 -0700215 mix_list = GetNonAnonymousAudio();
216 anonymous_mix_list = GetAnonymousAudio();
aleloidc7669a2016-10-04 04:06:20 -0700217 num_mixed_audio_sources = num_mixed_audio_sources_;
aleloi77ad3942016-07-04 06:33:02 -0700218 }
219
aleloi652ac892016-09-07 07:42:14 -0700220 mix_list.insert(mix_list.begin(), anonymous_mix_list.begin(),
221 anonymous_mix_list.end());
222
223 for (const auto& frame : mix_list) {
aleloie8914152016-10-11 06:18:31 -0700224 RemixFrame(number_of_channels, frame);
aleloi44968092016-08-08 10:18:58 -0700225 }
aleloi09f45102016-07-28 03:52:15 -0700226
227 audio_frame_for_mixing->UpdateFrame(
aleloia4c21062016-09-08 01:25:46 -0700228 -1, time_stamp_, NULL, 0, OutputFrequency(), AudioFrame::kNormalSpeech,
aleloi44968092016-08-08 10:18:58 -0700229 AudioFrame::kVadPassive, number_of_channels);
aleloi09f45102016-07-28 03:52:15 -0700230
aleloi6382a192016-08-08 10:25:04 -0700231 time_stamp_ += static_cast<uint32_t>(sample_size_);
aleloi09f45102016-07-28 03:52:15 -0700232
aleloi311525e2016-09-07 06:13:12 -0700233 use_limiter_ = num_mixed_audio_sources > 1;
aleloi09f45102016-07-28 03:52:15 -0700234
aleloi652ac892016-09-07 07:42:14 -0700235 // We only use the limiter if we're actually mixing multiple streams.
236 MixFromList(audio_frame_for_mixing, mix_list, id_, use_limiter_);
237
aleloi311525e2016-09-07 06:13:12 -0700238 if (audio_frame_for_mixing->samples_per_channel_ == 0) {
239 // Nothing was mixed, set the audio samples to silence.
240 audio_frame_for_mixing->samples_per_channel_ = sample_size_;
241 audio_frame_for_mixing->Mute();
242 } else {
243 // Only call the limiter if we have something to mix.
244 LimitMixedAudio(audio_frame_for_mixing);
aleloi77ad3942016-07-04 06:33:02 -0700245 }
aleloi616df1e2016-08-24 01:17:12 -0700246
247 // Pass the final result to the level indicator.
248 audio_level_.ComputeLevel(*audio_frame_for_mixing);
249
aleloi77ad3942016-07-04 06:33:02 -0700250 return;
251}
252
aleloi5d167d62016-08-24 02:20:54 -0700253int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) {
aleloi311525e2016-09-07 06:13:12 -0700254 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700255 output_frequency_ = frequency;
aleloidc7669a2016-10-04 04:06:20 -0700256 sample_size_ = (output_frequency_ * kFrameDurationInMs) / 1000;
aleloi77ad3942016-07-04 06:33:02 -0700257
258 return 0;
259}
260
aleloi5d167d62016-08-24 02:20:54 -0700261AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const {
aleloi311525e2016-09-07 06:13:12 -0700262 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700263 return output_frequency_;
aleloi77ad3942016-07-04 06:33:02 -0700264}
265
aleloie8914152016-10-11 06:18:31 -0700266int32_t AudioMixerImpl::SetMixabilityStatus(Source* audio_source,
aleloi5d167d62016-08-24 02:20:54 -0700267 bool mixable) {
aleloi77ad3942016-07-04 06:33:02 -0700268 if (!mixable) {
aleloi09f45102016-07-28 03:52:15 -0700269 // Anonymous audio sources are in a separate list. Make sure that the
270 // audio source is in the _audioSourceList if it is being mixed.
271 SetAnonymousMixabilityStatus(audio_source, false);
aleloi77ad3942016-07-04 06:33:02 -0700272 }
aleloi77ad3942016-07-04 06:33:02 -0700273 {
aleloi311525e2016-09-07 06:13:12 -0700274 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700275 const bool is_mixed = FindSourceInList(audio_source, &audio_source_list_) !=
276 audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700277 // API must be called with a new state.
aleloia4c21062016-09-08 01:25:46 -0700278 if (!(mixable ^ is_mixed)) {
aleloi6382a192016-08-08 10:25:04 -0700279 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700280 "Mixable is aready %s", is_mixed ? "ON" : "off");
aleloi77ad3942016-07-04 06:33:02 -0700281 return -1;
282 }
283 bool success = false;
284 if (mixable) {
aleloi09f45102016-07-28 03:52:15 -0700285 success = AddAudioSourceToList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700286 } else {
aleloi09f45102016-07-28 03:52:15 -0700287 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700288 }
289 if (!success) {
aleloi6382a192016-08-08 10:25:04 -0700290 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700291 "failed to %s audio_source", mixable ? "add" : "remove");
292 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700293 return -1;
294 }
295
aleloia4c21062016-09-08 01:25:46 -0700296 size_t num_mixed_non_anonymous = audio_source_list_.size();
297 if (num_mixed_non_anonymous > kMaximumAmountOfMixedAudioSources) {
298 num_mixed_non_anonymous = kMaximumAmountOfMixedAudioSources;
aleloi77ad3942016-07-04 06:33:02 -0700299 }
aleloi311525e2016-09-07 06:13:12 -0700300 num_mixed_audio_sources_ =
aleloia4c21062016-09-08 01:25:46 -0700301 num_mixed_non_anonymous + additional_audio_source_list_.size();
aleloi77ad3942016-07-04 06:33:02 -0700302 }
aleloi77ad3942016-07-04 06:33:02 -0700303 return 0;
304}
305
aleloie8914152016-10-11 06:18:31 -0700306bool AudioMixerImpl::MixabilityStatus(const Source& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700307 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700308 return FindSourceInList(&audio_source, &audio_source_list_) !=
309 audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700310}
311
aleloie8914152016-10-11 06:18:31 -0700312int32_t AudioMixerImpl::SetAnonymousMixabilityStatus(Source* audio_source,
313 bool anonymous) {
aleloi311525e2016-09-07 06:13:12 -0700314 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700315 if (FindSourceInList(audio_source, &additional_audio_source_list_) !=
316 additional_audio_source_list_.end()) {
aleloi77ad3942016-07-04 06:33:02 -0700317 if (anonymous) {
318 return 0;
319 }
aleloi09f45102016-07-28 03:52:15 -0700320 if (!RemoveAudioSourceFromList(audio_source,
321 &additional_audio_source_list_)) {
aleloi6382a192016-08-08 10:25:04 -0700322 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700323 "unable to remove audio_source from anonymous list");
324 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700325 return -1;
326 }
aleloi09f45102016-07-28 03:52:15 -0700327 return AddAudioSourceToList(audio_source, &audio_source_list_) ? 0 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700328 }
329 if (!anonymous) {
330 return 0;
331 }
332 const bool mixable =
aleloi09f45102016-07-28 03:52:15 -0700333 RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700334 if (!mixable) {
335 WEBRTC_TRACE(
aleloi6382a192016-08-08 10:25:04 -0700336 kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700337 "audio_source must be registered before turning it into anonymous");
aleloi77ad3942016-07-04 06:33:02 -0700338 // Setting anonymous status is only possible if MixerAudioSource is
339 // already registered.
340 return -1;
341 }
aleloi09f45102016-07-28 03:52:15 -0700342 return AddAudioSourceToList(audio_source, &additional_audio_source_list_)
343 ? 0
344 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700345}
346
aleloi5d167d62016-08-24 02:20:54 -0700347bool AudioMixerImpl::AnonymousMixabilityStatus(
aleloie8914152016-10-11 06:18:31 -0700348 const Source& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700349 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700350 return FindSourceInList(&audio_source, &additional_audio_source_list_) !=
351 additional_audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700352}
353
aleloi36542512016-10-07 05:28:32 -0700354AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() {
aleloi311525e2016-09-07 06:13:12 -0700355 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi652ac892016-09-07 07:42:14 -0700356 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
357 "GetNonAnonymousAudio()");
aleloif3882572016-07-29 02:12:41 -0700358 AudioFrameList result;
aleloia4c21062016-09-08 01:25:46 -0700359 std::vector<SourceFrame> audio_source_mixing_data_list;
aleloi652ac892016-09-07 07:42:14 -0700360 std::vector<SourceFrame> ramp_list;
aleloi77ad3942016-07-04 06:33:02 -0700361
aleloif3882572016-07-29 02:12:41 -0700362 // Get audio source audio and put it in the struct vector.
aleloi36542512016-10-07 05:28:32 -0700363 for (auto& source_and_status : audio_source_list_) {
364 auto audio_frame_with_info =
aleloie8914152016-10-11 06:18:31 -0700365 source_and_status.audio_source()->GetAudioFrameWithInfo(
aleloi36542512016-10-07 05:28:32 -0700366 id_, static_cast<int>(OutputFrequency()));
aleloi77ad3942016-07-04 06:33:02 -0700367
aleloia4c21062016-09-08 01:25:46 -0700368 const auto audio_frame_info = audio_frame_with_info.audio_frame_info;
aleloif3882572016-07-29 02:12:41 -0700369 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame;
370
aleloie8914152016-10-11 06:18:31 -0700371 if (audio_frame_info == Source::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700372 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi36542512016-10-07 05:28:32 -0700373 "failed to GetAudioFrameWithMuted() from source");
tereliusea4c1412016-07-29 01:36:14 -0700374 continue;
375 }
aleloia4c21062016-09-08 01:25:46 -0700376 audio_source_mixing_data_list.emplace_back(
aleloi36542512016-10-07 05:28:32 -0700377 &source_and_status, audio_source_audio_frame,
aleloie8914152016-10-11 06:18:31 -0700378 audio_frame_info == Source::AudioFrameInfo::kMuted);
aleloif3882572016-07-29 02:12:41 -0700379 }
380
381 // Sort frames by sorting function.
aleloia4c21062016-09-08 01:25:46 -0700382 std::sort(audio_source_mixing_data_list.begin(),
383 audio_source_mixing_data_list.end(),
aleloi36542512016-10-07 05:28:32 -0700384 std::mem_fn(&SourceFrame::ShouldMixBefore));
aleloif3882572016-07-29 02:12:41 -0700385
aleloia4c21062016-09-08 01:25:46 -0700386 int max_audio_frame_counter = kMaximumAmountOfMixedAudioSources;
387
388 // Go through list in order and put unmuted frames in result list.
aleloi36542512016-10-07 05:28:32 -0700389 for (const auto& p : audio_source_mixing_data_list) {
aleloif3882572016-07-29 02:12:41 -0700390 // Filter muted.
391 if (p.muted_) {
aleloidc7669a2016-10-04 04:06:20 -0700392 p.audio_source_->SetIsMixed(false);
aleloif3882572016-07-29 02:12:41 -0700393 continue;
tereliusea4c1412016-07-29 01:36:14 -0700394 }
aleloi2942e242016-07-29 01:23:49 -0700395
aleloif3882572016-07-29 02:12:41 -0700396 // Add frame to result vector for mixing.
397 bool is_mixed = false;
aleloia4c21062016-09-08 01:25:46 -0700398 if (max_audio_frame_counter > 0) {
399 --max_audio_frame_counter;
aleloi652ac892016-09-07 07:42:14 -0700400 result.push_back(p.audio_frame_);
aleloi36542512016-10-07 05:28:32 -0700401 ramp_list.emplace_back(p.audio_source_, p.audio_frame_, false, -1);
aleloif3882572016-07-29 02:12:41 -0700402 is_mixed = true;
tereliusea4c1412016-07-29 01:36:14 -0700403 }
aleloidc7669a2016-10-04 04:06:20 -0700404 p.audio_source_->SetIsMixed(is_mixed);
tereliusea4c1412016-07-29 01:36:14 -0700405 }
aleloi652ac892016-09-07 07:42:14 -0700406 Ramp(ramp_list);
aleloif3882572016-07-29 02:12:41 -0700407 return result;
aleloi77ad3942016-07-04 06:33:02 -0700408}
409
aleloi36542512016-10-07 05:28:32 -0700410AudioFrameList AudioMixerImpl::GetAnonymousAudio() {
aleloi311525e2016-09-07 06:13:12 -0700411 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700412 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi652ac892016-09-07 07:42:14 -0700413 "GetAnonymousAudio()");
aleloi652ac892016-09-07 07:42:14 -0700414 std::vector<SourceFrame> ramp_list;
aleloi652ac892016-09-07 07:42:14 -0700415 AudioFrameList result;
aleloi36542512016-10-07 05:28:32 -0700416 for (auto& source_and_status : additional_audio_source_list_) {
aleloia4c21062016-09-08 01:25:46 -0700417 const auto audio_frame_with_info =
aleloie8914152016-10-11 06:18:31 -0700418 source_and_status.audio_source()->GetAudioFrameWithInfo(
aleloi36542512016-10-07 05:28:32 -0700419 id_, OutputFrequency());
aleloia4c21062016-09-08 01:25:46 -0700420 const auto ret = audio_frame_with_info.audio_frame_info;
aleloia0db81f2016-07-28 06:36:22 -0700421 AudioFrame* audio_frame = audio_frame_with_info.audio_frame;
aleloie8914152016-10-11 06:18:31 -0700422 if (ret == Source::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700423 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700424 "failed to GetAudioFrameWithMuted() from audio_source");
aleloi77ad3942016-07-04 06:33:02 -0700425 continue;
426 }
aleloie8914152016-10-11 06:18:31 -0700427 if (ret != Source::AudioFrameInfo::kMuted) {
aleloi652ac892016-09-07 07:42:14 -0700428 result.push_back(audio_frame);
aleloi36542512016-10-07 05:28:32 -0700429 ramp_list.emplace_back(&source_and_status, audio_frame, false, 0);
430 source_and_status.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::AddAudioSourceToList(
aleloie8914152016-10-11 06:18:31 -0700438 Source* audio_source,
aleloia4c21062016-09-08 01:25:46 -0700439 MixerAudioSourceList* audio_source_list) const {
aleloi6382a192016-08-08 10:25:04 -0700440 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700441 "AddAudioSourceToList(audio_source, audio_source_list)");
aleloi36542512016-10-07 05:28:32 -0700442 audio_source_list->emplace_back(audio_source);
aleloi77ad3942016-07-04 06:33:02 -0700443 return true;
444}
445
aleloi5d167d62016-08-24 02:20:54 -0700446bool AudioMixerImpl::RemoveAudioSourceFromList(
aleloie8914152016-10-11 06:18:31 -0700447 Source* audio_source,
aleloia4c21062016-09-08 01:25:46 -0700448 MixerAudioSourceList* audio_source_list) const {
aleloi6382a192016-08-08 10:25:04 -0700449 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700450 "RemoveAudioSourceFromList(audio_source, audio_source_list)");
aleloi36542512016-10-07 05:28:32 -0700451 const auto iter = FindSourceInList(audio_source, audio_source_list);
aleloia4c21062016-09-08 01:25:46 -0700452 if (iter != audio_source_list->end()) {
453 audio_source_list->erase(iter);
aleloi6382a192016-08-08 10:25:04 -0700454 return true;
455 } else {
456 return false;
aleloi77ad3942016-07-04 06:33:02 -0700457 }
aleloi77ad3942016-07-04 06:33:02 -0700458}
459
aleloia4c21062016-09-08 01:25:46 -0700460bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixed_audio) const {
aleloi311525e2016-09-07 06:13:12 -0700461 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi77ad3942016-07-04 06:33:02 -0700462 if (!use_limiter_) {
463 return true;
464 }
465
466 // Smoothly limit the mixed frame.
aleloia4c21062016-09-08 01:25:46 -0700467 const int error = limiter_->ProcessStream(mixed_audio);
aleloi77ad3942016-07-04 06:33:02 -0700468
469 // And now we can safely restore the level. This procedure results in
470 // some loss of resolution, deemed acceptable.
471 //
472 // It's possible to apply the gain in the AGC (with a target level of 0 dbFS
473 // and compression gain of 6 dB). However, in the transition frame when this
aleloi09f45102016-07-28 03:52:15 -0700474 // is enabled (moving from one to two audio sources) it has the potential to
aleloi77ad3942016-07-04 06:33:02 -0700475 // create discontinuities in the mixed frame.
476 //
477 // Instead we double the frame (with addition since left-shifting a
478 // negative value is undefined).
aleloia4c21062016-09-08 01:25:46 -0700479 *mixed_audio += *mixed_audio;
aleloi77ad3942016-07-04 06:33:02 -0700480
aleloi6382a192016-08-08 10:25:04 -0700481 if (error != limiter_->kNoError) {
482 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700483 "Error from AudioProcessing: %d", error);
aleloi09f45102016-07-28 03:52:15 -0700484 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700485 return false;
486 }
487 return true;
488}
aleloi616df1e2016-08-24 01:17:12 -0700489
aleloi5d167d62016-08-24 02:20:54 -0700490int AudioMixerImpl::GetOutputAudioLevel() {
aleloi311525e2016-09-07 06:13:12 -0700491 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700492 const int level = audio_level_.Level();
493 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
494 "GetAudioOutputLevel() => level=%d", level);
495 return level;
496}
497
aleloi5d167d62016-08-24 02:20:54 -0700498int AudioMixerImpl::GetOutputAudioLevelFullRange() {
aleloi311525e2016-09-07 06:13:12 -0700499 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700500 const int level = audio_level_.LevelFullRange();
501 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
502 "GetAudioOutputLevelFullRange() => level=%d", level);
503 return level;
504}
aleloi36542512016-10-07 05:28:32 -0700505
506bool AudioMixerImpl::GetAudioSourceMixabilityStatusForTest(
aleloie8914152016-10-11 06:18:31 -0700507 AudioMixerImpl::Source* audio_source) {
aleloi36542512016-10-07 05:28:32 -0700508 RTC_DCHECK_RUN_ON(&thread_checker_);
509 rtc::CritScope lock(&crit_);
510
511 const auto non_anonymous_iter =
512 FindSourceInList(audio_source, &audio_source_list_);
513 if (non_anonymous_iter != audio_source_list_.end()) {
514 return non_anonymous_iter->IsMixed();
515 }
516
517 const auto anonymous_iter =
518 FindSourceInList(audio_source, &additional_audio_source_list_);
519 if (anonymous_iter != audio_source_list_.end()) {
520 return anonymous_iter->IsMixed();
521 }
522
523 LOG(LS_ERROR) << "Audio source unknown";
524 return false;
525}
aleloi77ad3942016-07-04 06:33:02 -0700526} // namespace webrtc