blob: 789d63b9f1df605afc4fa69790624103138b0c68 [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
aleloi4b8bfb82016-10-12 02:14:59 -070025struct SourceFrame {
26 SourceFrame(AudioMixerImpl::SourceStatus* source_status,
aleloi36542512016-10-07 05:28:32 -070027 AudioFrame* audio_frame,
28 bool muted)
aleloi4b8bfb82016-10-12 02:14:59 -070029 : source_status(source_status), audio_frame(audio_frame), muted(muted) {
30 RTC_DCHECK(source_status);
31 RTC_DCHECK(audio_frame);
32 if (!muted) {
33 energy = AudioMixerCalculateEnergy(*audio_frame);
aleloif3882572016-07-29 02:12:41 -070034 }
35 }
aleloi77ad3942016-07-04 06:33:02 -070036
aleloi4b8bfb82016-10-12 02:14:59 -070037 SourceFrame(AudioMixerImpl::SourceStatus* source_status,
aleloi36542512016-10-07 05:28:32 -070038 AudioFrame* audio_frame,
39 bool muted,
aleloi652ac892016-09-07 07:42:14 -070040 uint32_t energy)
aleloi4b8bfb82016-10-12 02:14:59 -070041 : source_status(source_status),
42 audio_frame(audio_frame),
43 muted(muted),
44 energy(energy) {
45 RTC_DCHECK(source_status);
46 RTC_DCHECK(audio_frame);
aleloif3882572016-07-29 02:12:41 -070047 }
48
aleloi4b8bfb82016-10-12 02:14:59 -070049 AudioMixerImpl::SourceStatus* source_status = nullptr;
50 AudioFrame* audio_frame = nullptr;
51 bool muted = true;
52 uint32_t energy = 0;
aleloif3882572016-07-29 02:12:41 -070053};
tereliusea4c1412016-07-29 01:36:14 -070054
aleloi4b8bfb82016-10-12 02:14:59 -070055// ShouldMixBefore(a, b) is used to select mixer sources.
56bool ShouldMixBefore(const SourceFrame& a, const SourceFrame& b) {
57 if (a.muted != b.muted) {
58 return b.muted;
59 }
aleloi44968092016-08-08 10:18:58 -070060
aleloi4b8bfb82016-10-12 02:14:59 -070061 const auto a_activity = a.audio_frame->vad_activity_;
62 const auto b_activity = b.audio_frame->vad_activity_;
63
64 if (a_activity != b_activity) {
65 return a_activity == AudioFrame::kVadActive;
66 }
67
68 return a.energy > b.energy;
69}
70
71void RampAndUpdateGain(
72 const std::vector<SourceFrame>& mixed_sources_and_frames) {
aleloi652ac892016-09-07 07:42:14 -070073 for (const auto& source_frame : mixed_sources_and_frames) {
aleloi4b8bfb82016-10-12 02:14:59 -070074 float target_gain = source_frame.source_status->is_mixed ? 1.0f : 0.0f;
75 Ramp(source_frame.source_status->gain, target_gain,
76 source_frame.audio_frame);
77 source_frame.source_status->gain = target_gain;
aleloi77ad3942016-07-04 06:33:02 -070078 }
aleloi77ad3942016-07-04 06:33:02 -070079}
80
aleloidc7669a2016-10-04 04:06:20 -070081// Mix the AudioFrames stored in audioFrameList into mixed_audio.
82int32_t MixFromList(AudioFrame* mixed_audio,
83 const AudioFrameList& audio_frame_list,
84 int32_t id,
85 bool use_limiter) {
86 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id,
87 "MixFromList(mixed_audio, audio_frame_list)");
88 if (audio_frame_list.empty())
89 return 0;
aleloi77ad3942016-07-04 06:33:02 -070090
aleloidc7669a2016-10-04 04:06:20 -070091 if (audio_frame_list.size() == 1) {
92 mixed_audio->timestamp_ = audio_frame_list.front()->timestamp_;
93 mixed_audio->elapsed_time_ms_ = audio_frame_list.front()->elapsed_time_ms_;
94 } else {
95 // TODO(wu): Issue 3390.
96 // Audio frame timestamp is only supported in one channel case.
97 mixed_audio->timestamp_ = 0;
98 mixed_audio->elapsed_time_ms_ = -1;
99 }
aleloi77ad3942016-07-04 06:33:02 -0700100
aleloidc7669a2016-10-04 04:06:20 -0700101 for (const auto& frame : audio_frame_list) {
102 RTC_DCHECK_EQ(mixed_audio->sample_rate_hz_, frame->sample_rate_hz_);
103 RTC_DCHECK_EQ(
104 frame->samples_per_channel_,
105 static_cast<size_t>((mixed_audio->sample_rate_hz_ *
106 webrtc::AudioMixerImpl::kFrameDurationInMs) /
107 1000));
aleloi77ad3942016-07-04 06:33:02 -0700108
aleloidc7669a2016-10-04 04:06:20 -0700109 // Mix |f.frame| into |mixed_audio|, with saturation protection.
110 // These effect is applied to |f.frame| itself prior to mixing.
111 if (use_limiter) {
112 // Divide by two to avoid saturation in the mixing.
113 // This is only meaningful if the limiter will be used.
114 *frame >>= 1;
115 }
116 RTC_DCHECK_EQ(frame->num_channels_, mixed_audio->num_channels_);
117 *mixed_audio += *frame;
118 }
aleloi77ad3942016-07-04 06:33:02 -0700119 return 0;
120}
121
aleloi4b8bfb82016-10-12 02:14:59 -0700122AudioMixerImpl::SourceStatusList::const_iterator FindSourceInList(
aleloie8914152016-10-11 06:18:31 -0700123 AudioMixerImpl::Source const* audio_source,
aleloi4b8bfb82016-10-12 02:14:59 -0700124 AudioMixerImpl::SourceStatusList const* audio_source_list) {
aleloi36542512016-10-07 05:28:32 -0700125 return std::find_if(audio_source_list->begin(), audio_source_list->end(),
aleloi4b8bfb82016-10-12 02:14:59 -0700126 [audio_source](const AudioMixerImpl::SourceStatus& p) {
127 return p.audio_source == audio_source;
aleloi36542512016-10-07 05:28:32 -0700128 });
129}
130
aleloi4b8bfb82016-10-12 02:14:59 -0700131AudioMixerImpl::SourceStatusList::iterator FindSourceInList(
aleloie8914152016-10-11 06:18:31 -0700132 AudioMixerImpl::Source const* audio_source,
aleloi4b8bfb82016-10-12 02:14:59 -0700133 AudioMixerImpl::SourceStatusList* audio_source_list) {
aleloi36542512016-10-07 05:28:32 -0700134 return std::find_if(audio_source_list->begin(), audio_source_list->end(),
aleloi4b8bfb82016-10-12 02:14:59 -0700135 [audio_source](const AudioMixerImpl::SourceStatus& p) {
136 return p.audio_source == audio_source;
aleloi36542512016-10-07 05:28:32 -0700137 });
138}
139
aleloidc7669a2016-10-04 04:06:20 -0700140} // namespace
aleloi77ad3942016-07-04 06:33:02 -0700141
aleloi5d167d62016-08-24 02:20:54 -0700142std::unique_ptr<AudioMixer> AudioMixer::Create(int id) {
aleloi311525e2016-09-07 06:13:12 -0700143 return AudioMixerImpl::Create(id);
aleloi77ad3942016-07-04 06:33:02 -0700144}
145
aleloi311525e2016-09-07 06:13:12 -0700146AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter)
aleloi6382a192016-08-08 10:25:04 -0700147 : id_(id),
aleloi09f45102016-07-28 03:52:15 -0700148 audio_source_list_(),
149 additional_audio_source_list_(),
150 num_mixed_audio_sources_(0),
aleloi77ad3942016-07-04 06:33:02 -0700151 use_limiter_(true),
aleloi311525e2016-09-07 06:13:12 -0700152 time_stamp_(0),
153 limiter_(std::move(limiter)) {
154 SetOutputFrequency(kDefaultFrequency);
aleloi8b2233f2016-07-28 06:24:14 -0700155 thread_checker_.DetachFromThread();
aleloia0db81f2016-07-28 06:36:22 -0700156}
aleloi77ad3942016-07-04 06:33:02 -0700157
aleloi5d167d62016-08-24 02:20:54 -0700158AudioMixerImpl::~AudioMixerImpl() {}
aleloi70f866c2016-08-16 02:15:49 -0700159
aleloi36542512016-10-07 05:28:32 -0700160std::unique_ptr<AudioMixerImpl> AudioMixerImpl::Create(int id) {
aleloi77ad3942016-07-04 06:33:02 -0700161 Config config;
162 config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
aleloi311525e2016-09-07 06:13:12 -0700163 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config));
164 if (!limiter.get())
165 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700166
aleloi311525e2016-09-07 06:13:12 -0700167 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) !=
168 limiter->kNoError)
169 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700170
171 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the
172 // divide-by-2 but -7 is used instead to give a bit of headroom since the
173 // AGC is not a hard limiter.
aleloi311525e2016-09-07 06:13:12 -0700174 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError)
175 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700176
aleloi311525e2016-09-07 06:13:12 -0700177 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError)
178 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700179
aleloi311525e2016-09-07 06:13:12 -0700180 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError)
181 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700182
aleloi311525e2016-09-07 06:13:12 -0700183 if (limiter->gain_control()->Enable(true) != limiter->kNoError)
184 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700185
aleloi36542512016-10-07 05:28:32 -0700186 return std::unique_ptr<AudioMixerImpl>(
aleloi311525e2016-09-07 06:13:12 -0700187 new AudioMixerImpl(id, std::move(limiter)));
aleloi77ad3942016-07-04 06:33:02 -0700188}
189
aleloi5d167d62016-08-24 02:20:54 -0700190void AudioMixerImpl::Mix(int sample_rate,
191 size_t number_of_channels,
192 AudioFrame* audio_frame_for_mixing) {
aleloi44968092016-08-08 10:18:58 -0700193 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
aleloi311525e2016-09-07 06:13:12 -0700194 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi311525e2016-09-07 06:13:12 -0700195
196 if (sample_rate != kNbInHz && sample_rate != kWbInHz &&
197 sample_rate != kSwbInHz && sample_rate != kFbInHz) {
198 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
199 "Invalid frequency: %d", sample_rate);
200 RTC_NOTREACHED();
201 return;
202 }
203
204 if (OutputFrequency() != sample_rate) {
205 SetOutputFrequency(static_cast<Frequency>(sample_rate));
206 }
207
aleloi652ac892016-09-07 07:42:14 -0700208 AudioFrameList mix_list;
209 AudioFrameList anonymous_mix_list;
aleloidc7669a2016-10-04 04:06:20 -0700210 size_t num_mixed_audio_sources;
aleloi77ad3942016-07-04 06:33:02 -0700211 {
aleloi311525e2016-09-07 06:13:12 -0700212 rtc::CritScope lock(&crit_);
aleloi652ac892016-09-07 07:42:14 -0700213 mix_list = GetNonAnonymousAudio();
214 anonymous_mix_list = GetAnonymousAudio();
aleloidc7669a2016-10-04 04:06:20 -0700215 num_mixed_audio_sources = num_mixed_audio_sources_;
aleloi77ad3942016-07-04 06:33:02 -0700216 }
217
aleloi652ac892016-09-07 07:42:14 -0700218 mix_list.insert(mix_list.begin(), anonymous_mix_list.begin(),
219 anonymous_mix_list.end());
220
221 for (const auto& frame : mix_list) {
aleloie8914152016-10-11 06:18:31 -0700222 RemixFrame(number_of_channels, frame);
aleloi44968092016-08-08 10:18:58 -0700223 }
aleloi09f45102016-07-28 03:52:15 -0700224
225 audio_frame_for_mixing->UpdateFrame(
aleloia4c21062016-09-08 01:25:46 -0700226 -1, time_stamp_, NULL, 0, OutputFrequency(), AudioFrame::kNormalSpeech,
aleloi44968092016-08-08 10:18:58 -0700227 AudioFrame::kVadPassive, number_of_channels);
aleloi09f45102016-07-28 03:52:15 -0700228
aleloi6382a192016-08-08 10:25:04 -0700229 time_stamp_ += static_cast<uint32_t>(sample_size_);
aleloi09f45102016-07-28 03:52:15 -0700230
aleloi311525e2016-09-07 06:13:12 -0700231 use_limiter_ = num_mixed_audio_sources > 1;
aleloi09f45102016-07-28 03:52:15 -0700232
aleloi652ac892016-09-07 07:42:14 -0700233 // We only use the limiter if we're actually mixing multiple streams.
234 MixFromList(audio_frame_for_mixing, mix_list, id_, use_limiter_);
235
aleloi311525e2016-09-07 06:13:12 -0700236 if (audio_frame_for_mixing->samples_per_channel_ == 0) {
237 // Nothing was mixed, set the audio samples to silence.
238 audio_frame_for_mixing->samples_per_channel_ = sample_size_;
239 audio_frame_for_mixing->Mute();
240 } else {
241 // Only call the limiter if we have something to mix.
242 LimitMixedAudio(audio_frame_for_mixing);
aleloi77ad3942016-07-04 06:33:02 -0700243 }
aleloi616df1e2016-08-24 01:17:12 -0700244
245 // Pass the final result to the level indicator.
246 audio_level_.ComputeLevel(*audio_frame_for_mixing);
247
aleloi77ad3942016-07-04 06:33:02 -0700248 return;
249}
250
aleloi5d167d62016-08-24 02:20:54 -0700251int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) {
aleloi311525e2016-09-07 06:13:12 -0700252 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700253 output_frequency_ = frequency;
aleloidc7669a2016-10-04 04:06:20 -0700254 sample_size_ = (output_frequency_ * kFrameDurationInMs) / 1000;
aleloi77ad3942016-07-04 06:33:02 -0700255
256 return 0;
257}
258
aleloi5d167d62016-08-24 02:20:54 -0700259AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const {
aleloi311525e2016-09-07 06:13:12 -0700260 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700261 return output_frequency_;
aleloi77ad3942016-07-04 06:33:02 -0700262}
263
aleloie8914152016-10-11 06:18:31 -0700264int32_t AudioMixerImpl::SetMixabilityStatus(Source* audio_source,
aleloi5d167d62016-08-24 02:20:54 -0700265 bool mixable) {
aleloi77ad3942016-07-04 06:33:02 -0700266 if (!mixable) {
aleloi09f45102016-07-28 03:52:15 -0700267 // Anonymous audio sources are in a separate list. Make sure that the
268 // audio source is in the _audioSourceList if it is being mixed.
269 SetAnonymousMixabilityStatus(audio_source, false);
aleloi77ad3942016-07-04 06:33:02 -0700270 }
aleloi77ad3942016-07-04 06:33:02 -0700271 {
aleloi311525e2016-09-07 06:13:12 -0700272 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700273 const bool is_mixed = FindSourceInList(audio_source, &audio_source_list_) !=
274 audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700275 // API must be called with a new state.
aleloia4c21062016-09-08 01:25:46 -0700276 if (!(mixable ^ is_mixed)) {
aleloi6382a192016-08-08 10:25:04 -0700277 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700278 "Mixable is aready %s", is_mixed ? "ON" : "off");
aleloi77ad3942016-07-04 06:33:02 -0700279 return -1;
280 }
281 bool success = false;
282 if (mixable) {
aleloi09f45102016-07-28 03:52:15 -0700283 success = AddAudioSourceToList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700284 } else {
aleloi09f45102016-07-28 03:52:15 -0700285 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700286 }
287 if (!success) {
aleloi6382a192016-08-08 10:25:04 -0700288 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700289 "failed to %s audio_source", mixable ? "add" : "remove");
290 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700291 return -1;
292 }
293
aleloia4c21062016-09-08 01:25:46 -0700294 size_t num_mixed_non_anonymous = audio_source_list_.size();
295 if (num_mixed_non_anonymous > kMaximumAmountOfMixedAudioSources) {
296 num_mixed_non_anonymous = kMaximumAmountOfMixedAudioSources;
aleloi77ad3942016-07-04 06:33:02 -0700297 }
aleloi311525e2016-09-07 06:13:12 -0700298 num_mixed_audio_sources_ =
aleloia4c21062016-09-08 01:25:46 -0700299 num_mixed_non_anonymous + additional_audio_source_list_.size();
aleloi77ad3942016-07-04 06:33:02 -0700300 }
aleloi77ad3942016-07-04 06:33:02 -0700301 return 0;
302}
303
aleloie8914152016-10-11 06:18:31 -0700304bool AudioMixerImpl::MixabilityStatus(const Source& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700305 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700306 return FindSourceInList(&audio_source, &audio_source_list_) !=
307 audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700308}
309
aleloie8914152016-10-11 06:18:31 -0700310int32_t AudioMixerImpl::SetAnonymousMixabilityStatus(Source* audio_source,
311 bool anonymous) {
aleloi311525e2016-09-07 06:13:12 -0700312 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700313 if (FindSourceInList(audio_source, &additional_audio_source_list_) !=
314 additional_audio_source_list_.end()) {
aleloi77ad3942016-07-04 06:33:02 -0700315 if (anonymous) {
316 return 0;
317 }
aleloi09f45102016-07-28 03:52:15 -0700318 if (!RemoveAudioSourceFromList(audio_source,
319 &additional_audio_source_list_)) {
aleloi6382a192016-08-08 10:25:04 -0700320 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700321 "unable to remove audio_source from anonymous list");
322 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700323 return -1;
324 }
aleloi09f45102016-07-28 03:52:15 -0700325 return AddAudioSourceToList(audio_source, &audio_source_list_) ? 0 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700326 }
327 if (!anonymous) {
328 return 0;
329 }
330 const bool mixable =
aleloi09f45102016-07-28 03:52:15 -0700331 RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700332 if (!mixable) {
333 WEBRTC_TRACE(
aleloi6382a192016-08-08 10:25:04 -0700334 kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700335 "audio_source must be registered before turning it into anonymous");
aleloi77ad3942016-07-04 06:33:02 -0700336 // Setting anonymous status is only possible if MixerAudioSource is
337 // already registered.
338 return -1;
339 }
aleloi09f45102016-07-28 03:52:15 -0700340 return AddAudioSourceToList(audio_source, &additional_audio_source_list_)
341 ? 0
342 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700343}
344
aleloi5d167d62016-08-24 02:20:54 -0700345bool AudioMixerImpl::AnonymousMixabilityStatus(
aleloie8914152016-10-11 06:18:31 -0700346 const Source& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700347 rtc::CritScope lock(&crit_);
aleloi36542512016-10-07 05:28:32 -0700348 return FindSourceInList(&audio_source, &additional_audio_source_list_) !=
349 additional_audio_source_list_.end();
aleloi77ad3942016-07-04 06:33:02 -0700350}
351
aleloi36542512016-10-07 05:28:32 -0700352AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() {
aleloi311525e2016-09-07 06:13:12 -0700353 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi652ac892016-09-07 07:42:14 -0700354 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
355 "GetNonAnonymousAudio()");
aleloif3882572016-07-29 02:12:41 -0700356 AudioFrameList result;
aleloia4c21062016-09-08 01:25:46 -0700357 std::vector<SourceFrame> audio_source_mixing_data_list;
aleloi652ac892016-09-07 07:42:14 -0700358 std::vector<SourceFrame> ramp_list;
aleloi77ad3942016-07-04 06:33:02 -0700359
aleloif3882572016-07-29 02:12:41 -0700360 // Get audio source audio and put it in the struct vector.
aleloi36542512016-10-07 05:28:32 -0700361 for (auto& source_and_status : audio_source_list_) {
362 auto audio_frame_with_info =
aleloi4b8bfb82016-10-12 02:14:59 -0700363 source_and_status.audio_source->GetAudioFrameWithInfo(
aleloi36542512016-10-07 05:28:32 -0700364 id_, static_cast<int>(OutputFrequency()));
aleloi77ad3942016-07-04 06:33:02 -0700365
aleloia4c21062016-09-08 01:25:46 -0700366 const auto audio_frame_info = audio_frame_with_info.audio_frame_info;
aleloif3882572016-07-29 02:12:41 -0700367 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame;
368
aleloie8914152016-10-11 06:18:31 -0700369 if (audio_frame_info == Source::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700370 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi36542512016-10-07 05:28:32 -0700371 "failed to GetAudioFrameWithMuted() from source");
tereliusea4c1412016-07-29 01:36:14 -0700372 continue;
373 }
aleloia4c21062016-09-08 01:25:46 -0700374 audio_source_mixing_data_list.emplace_back(
aleloi36542512016-10-07 05:28:32 -0700375 &source_and_status, audio_source_audio_frame,
aleloie8914152016-10-11 06:18:31 -0700376 audio_frame_info == Source::AudioFrameInfo::kMuted);
aleloif3882572016-07-29 02:12:41 -0700377 }
378
379 // Sort frames by sorting function.
aleloia4c21062016-09-08 01:25:46 -0700380 std::sort(audio_source_mixing_data_list.begin(),
aleloi4b8bfb82016-10-12 02:14:59 -0700381 audio_source_mixing_data_list.end(), ShouldMixBefore);
aleloif3882572016-07-29 02:12:41 -0700382
aleloia4c21062016-09-08 01:25:46 -0700383 int max_audio_frame_counter = kMaximumAmountOfMixedAudioSources;
384
385 // Go through list in order and put unmuted frames in result list.
aleloi36542512016-10-07 05:28:32 -0700386 for (const auto& p : audio_source_mixing_data_list) {
aleloif3882572016-07-29 02:12:41 -0700387 // Filter muted.
aleloi4b8bfb82016-10-12 02:14:59 -0700388 if (p.muted) {
389 p.source_status->is_mixed = false;
aleloif3882572016-07-29 02:12:41 -0700390 continue;
tereliusea4c1412016-07-29 01:36:14 -0700391 }
aleloi2942e242016-07-29 01:23:49 -0700392
aleloif3882572016-07-29 02:12:41 -0700393 // Add frame to result vector for mixing.
394 bool is_mixed = false;
aleloia4c21062016-09-08 01:25:46 -0700395 if (max_audio_frame_counter > 0) {
396 --max_audio_frame_counter;
aleloi4b8bfb82016-10-12 02:14:59 -0700397 result.push_back(p.audio_frame);
398 ramp_list.emplace_back(p.source_status, p.audio_frame, false, -1);
aleloif3882572016-07-29 02:12:41 -0700399 is_mixed = true;
tereliusea4c1412016-07-29 01:36:14 -0700400 }
aleloi4b8bfb82016-10-12 02:14:59 -0700401 p.source_status->is_mixed = is_mixed;
tereliusea4c1412016-07-29 01:36:14 -0700402 }
aleloi4b8bfb82016-10-12 02:14:59 -0700403 RampAndUpdateGain(ramp_list);
aleloif3882572016-07-29 02:12:41 -0700404 return result;
aleloi77ad3942016-07-04 06:33:02 -0700405}
406
aleloi36542512016-10-07 05:28:32 -0700407AudioFrameList AudioMixerImpl::GetAnonymousAudio() {
aleloi311525e2016-09-07 06:13:12 -0700408 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700409 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi652ac892016-09-07 07:42:14 -0700410 "GetAnonymousAudio()");
aleloi652ac892016-09-07 07:42:14 -0700411 std::vector<SourceFrame> ramp_list;
aleloi652ac892016-09-07 07:42:14 -0700412 AudioFrameList result;
aleloi36542512016-10-07 05:28:32 -0700413 for (auto& source_and_status : additional_audio_source_list_) {
aleloia4c21062016-09-08 01:25:46 -0700414 const auto audio_frame_with_info =
aleloi4b8bfb82016-10-12 02:14:59 -0700415 source_and_status.audio_source->GetAudioFrameWithInfo(
aleloi36542512016-10-07 05:28:32 -0700416 id_, OutputFrequency());
aleloia4c21062016-09-08 01:25:46 -0700417 const auto ret = audio_frame_with_info.audio_frame_info;
aleloia0db81f2016-07-28 06:36:22 -0700418 AudioFrame* audio_frame = audio_frame_with_info.audio_frame;
aleloie8914152016-10-11 06:18:31 -0700419 if (ret == Source::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700420 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700421 "failed to GetAudioFrameWithMuted() from audio_source");
aleloi77ad3942016-07-04 06:33:02 -0700422 continue;
423 }
aleloie8914152016-10-11 06:18:31 -0700424 if (ret != Source::AudioFrameInfo::kMuted) {
aleloi652ac892016-09-07 07:42:14 -0700425 result.push_back(audio_frame);
aleloi36542512016-10-07 05:28:32 -0700426 ramp_list.emplace_back(&source_and_status, audio_frame, false, 0);
aleloi4b8bfb82016-10-12 02:14:59 -0700427 source_and_status.is_mixed = true;
aleloi77ad3942016-07-04 06:33:02 -0700428 }
aleloi77ad3942016-07-04 06:33:02 -0700429 }
aleloi4b8bfb82016-10-12 02:14:59 -0700430 RampAndUpdateGain(ramp_list);
aleloi652ac892016-09-07 07:42:14 -0700431 return result;
aleloi77ad3942016-07-04 06:33:02 -0700432}
433
aleloi5d167d62016-08-24 02:20:54 -0700434bool AudioMixerImpl::AddAudioSourceToList(
aleloie8914152016-10-11 06:18:31 -0700435 Source* audio_source,
aleloi4b8bfb82016-10-12 02:14:59 -0700436 SourceStatusList* audio_source_list) const {
aleloi6382a192016-08-08 10:25:04 -0700437 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700438 "AddAudioSourceToList(audio_source, audio_source_list)");
aleloi4b8bfb82016-10-12 02:14:59 -0700439 audio_source_list->emplace_back(audio_source, false, 0);
aleloi77ad3942016-07-04 06:33:02 -0700440 return true;
441}
442
aleloi5d167d62016-08-24 02:20:54 -0700443bool AudioMixerImpl::RemoveAudioSourceFromList(
aleloie8914152016-10-11 06:18:31 -0700444 Source* audio_source,
aleloi4b8bfb82016-10-12 02:14:59 -0700445 SourceStatusList* audio_source_list) const {
aleloi6382a192016-08-08 10:25:04 -0700446 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloia4c21062016-09-08 01:25:46 -0700447 "RemoveAudioSourceFromList(audio_source, audio_source_list)");
aleloi36542512016-10-07 05:28:32 -0700448 const auto iter = FindSourceInList(audio_source, audio_source_list);
aleloia4c21062016-09-08 01:25:46 -0700449 if (iter != audio_source_list->end()) {
450 audio_source_list->erase(iter);
aleloi6382a192016-08-08 10:25:04 -0700451 return true;
452 } else {
453 return false;
aleloi77ad3942016-07-04 06:33:02 -0700454 }
aleloi77ad3942016-07-04 06:33:02 -0700455}
456
aleloia4c21062016-09-08 01:25:46 -0700457bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixed_audio) const {
aleloi311525e2016-09-07 06:13:12 -0700458 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi77ad3942016-07-04 06:33:02 -0700459 if (!use_limiter_) {
460 return true;
461 }
462
463 // Smoothly limit the mixed frame.
aleloia4c21062016-09-08 01:25:46 -0700464 const int error = limiter_->ProcessStream(mixed_audio);
aleloi77ad3942016-07-04 06:33:02 -0700465
466 // And now we can safely restore the level. This procedure results in
467 // some loss of resolution, deemed acceptable.
468 //
469 // It's possible to apply the gain in the AGC (with a target level of 0 dbFS
470 // and compression gain of 6 dB). However, in the transition frame when this
aleloi09f45102016-07-28 03:52:15 -0700471 // is enabled (moving from one to two audio sources) it has the potential to
aleloi77ad3942016-07-04 06:33:02 -0700472 // create discontinuities in the mixed frame.
473 //
474 // Instead we double the frame (with addition since left-shifting a
475 // negative value is undefined).
aleloia4c21062016-09-08 01:25:46 -0700476 *mixed_audio += *mixed_audio;
aleloi77ad3942016-07-04 06:33:02 -0700477
aleloi6382a192016-08-08 10:25:04 -0700478 if (error != limiter_->kNoError) {
479 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700480 "Error from AudioProcessing: %d", error);
aleloi09f45102016-07-28 03:52:15 -0700481 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700482 return false;
483 }
484 return true;
485}
aleloi616df1e2016-08-24 01:17:12 -0700486
aleloi5d167d62016-08-24 02:20:54 -0700487int AudioMixerImpl::GetOutputAudioLevel() {
aleloi311525e2016-09-07 06:13:12 -0700488 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700489 const int level = audio_level_.Level();
490 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
491 "GetAudioOutputLevel() => level=%d", level);
492 return level;
493}
494
aleloi5d167d62016-08-24 02:20:54 -0700495int AudioMixerImpl::GetOutputAudioLevelFullRange() {
aleloi311525e2016-09-07 06:13:12 -0700496 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700497 const int level = audio_level_.LevelFullRange();
498 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
499 "GetAudioOutputLevelFullRange() => level=%d", level);
500 return level;
501}
aleloi36542512016-10-07 05:28:32 -0700502
503bool AudioMixerImpl::GetAudioSourceMixabilityStatusForTest(
aleloie8914152016-10-11 06:18:31 -0700504 AudioMixerImpl::Source* audio_source) {
aleloi36542512016-10-07 05:28:32 -0700505 RTC_DCHECK_RUN_ON(&thread_checker_);
506 rtc::CritScope lock(&crit_);
507
508 const auto non_anonymous_iter =
509 FindSourceInList(audio_source, &audio_source_list_);
510 if (non_anonymous_iter != audio_source_list_.end()) {
aleloi4b8bfb82016-10-12 02:14:59 -0700511 return non_anonymous_iter->is_mixed;
aleloi36542512016-10-07 05:28:32 -0700512 }
513
514 const auto anonymous_iter =
515 FindSourceInList(audio_source, &additional_audio_source_list_);
516 if (anonymous_iter != audio_source_list_.end()) {
aleloi4b8bfb82016-10-12 02:14:59 -0700517 return anonymous_iter->is_mixed;
aleloi36542512016-10-07 05:28:32 -0700518 }
519
520 LOG(LS_ERROR) << "Audio source unknown";
521 return false;
522}
aleloi77ad3942016-07-04 06:33:02 -0700523} // namespace webrtc