blob: 93b78bd4c34947ec91a514097384e4644e0a6402 [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
aleloif3882572016-07-29 02:12:41 -070040 // a.shouldMixBefore(b) is used to select mixer participants.
41 bool shouldMixBefore(const SourceFrame& other) const {
42 if (muted_ != other.muted_) {
43 return other.muted_;
44 }
45
46 auto our_activity = audio_frame_->vad_activity_;
47 auto other_activity = other.audio_frame_->vad_activity_;
48
49 if (our_activity != other_activity) {
50 return our_activity == AudioFrame::kVadActive;
51 }
52
53 return energy_ > other.energy_;
54 }
55
56 MixerAudioSource* audio_source_;
57 AudioFrame* audio_frame_;
58 bool muted_;
59 uint32_t energy_;
60 bool was_mixed_before_;
61};
tereliusea4c1412016-07-29 01:36:14 -070062
aleloi44968092016-08-08 10:18:58 -070063// Remixes a frame between stereo and mono.
64void RemixFrame(AudioFrame* frame, size_t number_of_channels) {
65 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
66 if (frame->num_channels_ == 1 && number_of_channels == 2) {
67 AudioFrameOperations::MonoToStereo(frame);
68 } else if (frame->num_channels_ == 2 && number_of_channels == 1) {
69 AudioFrameOperations::StereoToMono(frame);
70 }
71}
72
aleloi77ad3942016-07-04 06:33:02 -070073// Mix |frame| into |mixed_frame|, with saturation protection and upmixing.
74// These effects are applied to |frame| itself prior to mixing. Assumes that
75// |mixed_frame| always has at least as many channels as |frame|. Supports
76// stereo at most.
77//
aleloi77ad3942016-07-04 06:33:02 -070078void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) {
aleloi09f45102016-07-28 03:52:15 -070079 RTC_DCHECK_GE(mixed_frame->num_channels_, frame->num_channels_);
aleloi77ad3942016-07-04 06:33:02 -070080 if (use_limiter) {
81 // Divide by two to avoid saturation in the mixing.
82 // This is only meaningful if the limiter will be used.
83 *frame >>= 1;
84 }
aleloi44968092016-08-08 10:18:58 -070085 RTC_DCHECK_EQ(frame->num_channels_, mixed_frame->num_channels_);
aleloi77ad3942016-07-04 06:33:02 -070086 *mixed_frame += *frame;
87}
88
aleloi77ad3942016-07-04 06:33:02 -070089} // namespace
90
91MixerAudioSource::MixerAudioSource() : _mixHistory(new NewMixHistory()) {}
92
93MixerAudioSource::~MixerAudioSource() {
94 delete _mixHistory;
95}
96
97bool MixerAudioSource::IsMixed() const {
98 return _mixHistory->IsMixed();
99}
100
aleloi6382a192016-08-08 10:25:04 -0700101NewMixHistory::NewMixHistory() : is_mixed_(0) {}
aleloi77ad3942016-07-04 06:33:02 -0700102
103NewMixHistory::~NewMixHistory() {}
104
105bool NewMixHistory::IsMixed() const {
aleloi6382a192016-08-08 10:25:04 -0700106 return is_mixed_;
aleloi77ad3942016-07-04 06:33:02 -0700107}
108
109bool NewMixHistory::WasMixed() const {
110 // Was mixed is the same as is mixed depending on perspective. This function
111 // is for the perspective of NewAudioConferenceMixerImpl.
112 return IsMixed();
113}
114
115int32_t NewMixHistory::SetIsMixed(const bool mixed) {
aleloi6382a192016-08-08 10:25:04 -0700116 is_mixed_ = mixed;
aleloi77ad3942016-07-04 06:33:02 -0700117 return 0;
118}
119
120void NewMixHistory::ResetMixedStatus() {
aleloi6382a192016-08-08 10:25:04 -0700121 is_mixed_ = false;
aleloi77ad3942016-07-04 06:33:02 -0700122}
123
aleloi5d167d62016-08-24 02:20:54 -0700124std::unique_ptr<AudioMixer> AudioMixer::Create(int id) {
aleloi311525e2016-09-07 06:13:12 -0700125 return AudioMixerImpl::Create(id);
aleloi77ad3942016-07-04 06:33:02 -0700126}
127
aleloi311525e2016-09-07 06:13:12 -0700128AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter)
aleloi6382a192016-08-08 10:25:04 -0700129 : id_(id),
aleloi09f45102016-07-28 03:52:15 -0700130 audio_source_list_(),
131 additional_audio_source_list_(),
132 num_mixed_audio_sources_(0),
aleloi77ad3942016-07-04 06:33:02 -0700133 use_limiter_(true),
aleloi311525e2016-09-07 06:13:12 -0700134 time_stamp_(0),
135 limiter_(std::move(limiter)) {
136 SetOutputFrequency(kDefaultFrequency);
aleloi8b2233f2016-07-28 06:24:14 -0700137 thread_checker_.DetachFromThread();
aleloia0db81f2016-07-28 06:36:22 -0700138}
aleloi77ad3942016-07-04 06:33:02 -0700139
aleloi5d167d62016-08-24 02:20:54 -0700140AudioMixerImpl::~AudioMixerImpl() {}
aleloi70f866c2016-08-16 02:15:49 -0700141
aleloi311525e2016-09-07 06:13:12 -0700142std::unique_ptr<AudioMixer> AudioMixerImpl::Create(int id) {
aleloi77ad3942016-07-04 06:33:02 -0700143 Config config;
144 config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
aleloi311525e2016-09-07 06:13:12 -0700145 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config));
146 if (!limiter.get())
147 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700148
aleloi311525e2016-09-07 06:13:12 -0700149 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) !=
150 limiter->kNoError)
151 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700152
153 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the
154 // divide-by-2 but -7 is used instead to give a bit of headroom since the
155 // AGC is not a hard limiter.
aleloi311525e2016-09-07 06:13:12 -0700156 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError)
157 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700158
aleloi311525e2016-09-07 06:13:12 -0700159 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError)
160 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700161
aleloi311525e2016-09-07 06:13:12 -0700162 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError)
163 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700164
aleloi311525e2016-09-07 06:13:12 -0700165 if (limiter->gain_control()->Enable(true) != limiter->kNoError)
166 return nullptr;
aleloi77ad3942016-07-04 06:33:02 -0700167
aleloi311525e2016-09-07 06:13:12 -0700168 return std::unique_ptr<AudioMixer>(
169 new AudioMixerImpl(id, std::move(limiter)));
aleloi77ad3942016-07-04 06:33:02 -0700170}
171
aleloi5d167d62016-08-24 02:20:54 -0700172void AudioMixerImpl::Mix(int sample_rate,
173 size_t number_of_channels,
174 AudioFrame* audio_frame_for_mixing) {
aleloi44968092016-08-08 10:18:58 -0700175 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2);
aleloi311525e2016-09-07 06:13:12 -0700176 RTC_DCHECK_RUN_ON(&thread_checker_);
177 std::map<int, MixerAudioSource*> mixedAudioSourcesMap;
178
179 if (sample_rate != kNbInHz && sample_rate != kWbInHz &&
180 sample_rate != kSwbInHz && sample_rate != kFbInHz) {
181 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
182 "Invalid frequency: %d", sample_rate);
183 RTC_NOTREACHED();
184 return;
185 }
186
187 if (OutputFrequency() != sample_rate) {
188 SetOutputFrequency(static_cast<Frequency>(sample_rate));
189 }
190
aleloi77ad3942016-07-04 06:33:02 -0700191 AudioFrameList mixList;
aleloi77ad3942016-07-04 06:33:02 -0700192 AudioFrameList additionalFramesList;
aleloi311525e2016-09-07 06:13:12 -0700193 int num_mixed_audio_sources;
aleloi77ad3942016-07-04 06:33:02 -0700194 {
aleloi311525e2016-09-07 06:13:12 -0700195 rtc::CritScope lock(&crit_);
aleloi30be5d72016-08-24 01:38:44 -0700196 mixList = UpdateToMix(kMaximumAmountOfMixedAudioSources);
aleloi77ad3942016-07-04 06:33:02 -0700197 GetAdditionalAudio(&additionalFramesList);
aleloi311525e2016-09-07 06:13:12 -0700198 num_mixed_audio_sources = static_cast<int>(num_mixed_audio_sources_);
aleloi77ad3942016-07-04 06:33:02 -0700199 }
200
aleloi44968092016-08-08 10:18:58 -0700201 for (FrameAndMuteInfo& frame_and_mute : mixList) {
202 RemixFrame(frame_and_mute.frame, number_of_channels);
203 }
204 for (FrameAndMuteInfo& frame_and_mute : additionalFramesList) {
205 RemixFrame(frame_and_mute.frame, number_of_channels);
206 }
aleloi09f45102016-07-28 03:52:15 -0700207
208 audio_frame_for_mixing->UpdateFrame(
aleloi6382a192016-08-08 10:25:04 -0700209 -1, time_stamp_, NULL, 0, output_frequency_, AudioFrame::kNormalSpeech,
aleloi44968092016-08-08 10:18:58 -0700210 AudioFrame::kVadPassive, number_of_channels);
aleloi09f45102016-07-28 03:52:15 -0700211
aleloi6382a192016-08-08 10:25:04 -0700212 time_stamp_ += static_cast<uint32_t>(sample_size_);
aleloi09f45102016-07-28 03:52:15 -0700213
aleloi311525e2016-09-07 06:13:12 -0700214 use_limiter_ = num_mixed_audio_sources > 1;
aleloi09f45102016-07-28 03:52:15 -0700215
216 // We only use the limiter if it supports the output sample rate and
217 // we're actually mixing multiple streams.
aleloi6382a192016-08-08 10:25:04 -0700218 MixFromList(audio_frame_for_mixing, mixList, id_, use_limiter_);
aleloi311525e2016-09-07 06:13:12 -0700219 MixAnonomouslyFromList(audio_frame_for_mixing, additionalFramesList);
220 if (audio_frame_for_mixing->samples_per_channel_ == 0) {
221 // Nothing was mixed, set the audio samples to silence.
222 audio_frame_for_mixing->samples_per_channel_ = sample_size_;
223 audio_frame_for_mixing->Mute();
224 } else {
225 // Only call the limiter if we have something to mix.
226 LimitMixedAudio(audio_frame_for_mixing);
aleloi77ad3942016-07-04 06:33:02 -0700227 }
aleloi616df1e2016-08-24 01:17:12 -0700228
229 // Pass the final result to the level indicator.
230 audio_level_.ComputeLevel(*audio_frame_for_mixing);
231
aleloi77ad3942016-07-04 06:33:02 -0700232 return;
233}
234
aleloi5d167d62016-08-24 02:20:54 -0700235int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) {
aleloi311525e2016-09-07 06:13:12 -0700236 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700237 output_frequency_ = frequency;
238 sample_size_ =
aleloi5d167d62016-08-24 02:20:54 -0700239 static_cast<size_t>((output_frequency_ * kFrameDurationInMs) / 1000);
aleloi77ad3942016-07-04 06:33:02 -0700240
241 return 0;
242}
243
aleloi5d167d62016-08-24 02:20:54 -0700244AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const {
aleloi311525e2016-09-07 06:13:12 -0700245 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700246 return output_frequency_;
aleloi77ad3942016-07-04 06:33:02 -0700247}
248
aleloi5d167d62016-08-24 02:20:54 -0700249int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source,
250 bool mixable) {
aleloi77ad3942016-07-04 06:33:02 -0700251 if (!mixable) {
aleloi09f45102016-07-28 03:52:15 -0700252 // Anonymous audio sources are in a separate list. Make sure that the
253 // audio source is in the _audioSourceList if it is being mixed.
254 SetAnonymousMixabilityStatus(audio_source, false);
aleloi77ad3942016-07-04 06:33:02 -0700255 }
aleloi77ad3942016-07-04 06:33:02 -0700256 {
aleloi311525e2016-09-07 06:13:12 -0700257 rtc::CritScope lock(&crit_);
aleloi09f45102016-07-28 03:52:15 -0700258 const bool isMixed = IsAudioSourceInList(*audio_source, audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700259 // API must be called with a new state.
260 if (!(mixable ^ isMixed)) {
aleloi6382a192016-08-08 10:25:04 -0700261 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700262 "Mixable is aready %s", isMixed ? "ON" : "off");
263 return -1;
264 }
265 bool success = false;
266 if (mixable) {
aleloi09f45102016-07-28 03:52:15 -0700267 success = AddAudioSourceToList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700268 } else {
aleloi09f45102016-07-28 03:52:15 -0700269 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700270 }
271 if (!success) {
aleloi6382a192016-08-08 10:25:04 -0700272 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700273 "failed to %s audio_source", mixable ? "add" : "remove");
274 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700275 return -1;
276 }
277
aleloi09f45102016-07-28 03:52:15 -0700278 size_t numMixedNonAnonymous = audio_source_list_.size();
279 if (numMixedNonAnonymous > kMaximumAmountOfMixedAudioSources) {
280 numMixedNonAnonymous = kMaximumAmountOfMixedAudioSources;
aleloi77ad3942016-07-04 06:33:02 -0700281 }
aleloi311525e2016-09-07 06:13:12 -0700282 num_mixed_audio_sources_ =
aleloi09f45102016-07-28 03:52:15 -0700283 numMixedNonAnonymous + additional_audio_source_list_.size();
aleloi77ad3942016-07-04 06:33:02 -0700284 }
aleloi77ad3942016-07-04 06:33:02 -0700285 return 0;
286}
287
aleloi5d167d62016-08-24 02:20:54 -0700288bool AudioMixerImpl::MixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700289 const MixerAudioSource& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700290 rtc::CritScope lock(&crit_);
aleloi09f45102016-07-28 03:52:15 -0700291 return IsAudioSourceInList(audio_source, audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700292}
293
aleloi5d167d62016-08-24 02:20:54 -0700294int32_t AudioMixerImpl::SetAnonymousMixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700295 MixerAudioSource* audio_source,
aleloi77ad3942016-07-04 06:33:02 -0700296 bool anonymous) {
aleloi311525e2016-09-07 06:13:12 -0700297 rtc::CritScope lock(&crit_);
aleloi09f45102016-07-28 03:52:15 -0700298 if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) {
aleloi77ad3942016-07-04 06:33:02 -0700299 if (anonymous) {
300 return 0;
301 }
aleloi09f45102016-07-28 03:52:15 -0700302 if (!RemoveAudioSourceFromList(audio_source,
303 &additional_audio_source_list_)) {
aleloi6382a192016-08-08 10:25:04 -0700304 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700305 "unable to remove audio_source from anonymous list");
306 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700307 return -1;
308 }
aleloi09f45102016-07-28 03:52:15 -0700309 return AddAudioSourceToList(audio_source, &audio_source_list_) ? 0 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700310 }
311 if (!anonymous) {
312 return 0;
313 }
314 const bool mixable =
aleloi09f45102016-07-28 03:52:15 -0700315 RemoveAudioSourceFromList(audio_source, &audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700316 if (!mixable) {
317 WEBRTC_TRACE(
aleloi6382a192016-08-08 10:25:04 -0700318 kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700319 "audio_source must be registered before turning it into anonymous");
aleloi77ad3942016-07-04 06:33:02 -0700320 // Setting anonymous status is only possible if MixerAudioSource is
321 // already registered.
322 return -1;
323 }
aleloi09f45102016-07-28 03:52:15 -0700324 return AddAudioSourceToList(audio_source, &additional_audio_source_list_)
325 ? 0
326 : -1;
aleloi77ad3942016-07-04 06:33:02 -0700327}
328
aleloi5d167d62016-08-24 02:20:54 -0700329bool AudioMixerImpl::AnonymousMixabilityStatus(
aleloi09f45102016-07-28 03:52:15 -0700330 const MixerAudioSource& audio_source) const {
aleloi311525e2016-09-07 06:13:12 -0700331 rtc::CritScope lock(&crit_);
aleloi09f45102016-07-28 03:52:15 -0700332 return IsAudioSourceInList(audio_source, additional_audio_source_list_);
aleloi77ad3942016-07-04 06:33:02 -0700333}
334
aleloi5d167d62016-08-24 02:20:54 -0700335AudioFrameList AudioMixerImpl::UpdateToMix(size_t maxAudioFrameCounter) const {
aleloi311525e2016-09-07 06:13:12 -0700336 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloif3882572016-07-29 02:12:41 -0700337 AudioFrameList result;
338 std::vector<SourceFrame> audioSourceMixingDataList;
aleloi77ad3942016-07-04 06:33:02 -0700339
aleloif3882572016-07-29 02:12:41 -0700340 // Get audio source audio and put it in the struct vector.
341 for (MixerAudioSource* audio_source : audio_source_list_) {
342 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted(
aleloi6382a192016-08-08 10:25:04 -0700343 id_, static_cast<int>(output_frequency_));
aleloi77ad3942016-07-04 06:33:02 -0700344
aleloif3882572016-07-29 02:12:41 -0700345 auto audio_frame_info = audio_frame_with_info.audio_frame_info;
346 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame;
347
348 if (audio_frame_info == MixerAudioSource::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700349 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloif3882572016-07-29 02:12:41 -0700350 "failed to GetAudioFrameWithMuted() from participant");
tereliusea4c1412016-07-29 01:36:14 -0700351 continue;
352 }
aleloif3882572016-07-29 02:12:41 -0700353 audioSourceMixingDataList.emplace_back(
354 audio_source, audio_source_audio_frame,
355 audio_frame_info == MixerAudioSource::AudioFrameInfo::kMuted,
356 audio_source->_mixHistory->WasMixed());
357 }
358
359 // Sort frames by sorting function.
360 std::sort(audioSourceMixingDataList.begin(), audioSourceMixingDataList.end(),
361 std::mem_fn(&SourceFrame::shouldMixBefore));
362
363 // Go through list in order and put things in mixList.
364 for (SourceFrame& p : audioSourceMixingDataList) {
365 // Filter muted.
366 if (p.muted_) {
367 p.audio_source_->_mixHistory->SetIsMixed(false);
368 continue;
tereliusea4c1412016-07-29 01:36:14 -0700369 }
aleloi2942e242016-07-29 01:23:49 -0700370
aleloif3882572016-07-29 02:12:41 -0700371 // Add frame to result vector for mixing.
372 bool is_mixed = false;
373 if (maxAudioFrameCounter > 0) {
374 --maxAudioFrameCounter;
375 if (!p.was_mixed_before_) {
aleloi5bcc00e2016-08-15 03:01:31 -0700376 NewMixerRampIn(p.audio_frame_);
aleloi77ad3942016-07-04 06:33:02 -0700377 }
aleloif3882572016-07-29 02:12:41 -0700378 result.emplace_back(p.audio_frame_, false);
379 is_mixed = true;
tereliusea4c1412016-07-29 01:36:14 -0700380 }
aleloif3882572016-07-29 02:12:41 -0700381
382 // Ramp out unmuted.
383 if (p.was_mixed_before_ && !is_mixed) {
aleloi5bcc00e2016-08-15 03:01:31 -0700384 NewMixerRampOut(p.audio_frame_);
aleloif3882572016-07-29 02:12:41 -0700385 result.emplace_back(p.audio_frame_, false);
tereliusea4c1412016-07-29 01:36:14 -0700386 }
aleloif3882572016-07-29 02:12:41 -0700387
388 p.audio_source_->_mixHistory->SetIsMixed(is_mixed);
tereliusea4c1412016-07-29 01:36:14 -0700389 }
aleloif3882572016-07-29 02:12:41 -0700390 return result;
aleloi77ad3942016-07-04 06:33:02 -0700391}
392
aleloi5d167d62016-08-24 02:20:54 -0700393void AudioMixerImpl::GetAdditionalAudio(
aleloi77ad3942016-07-04 06:33:02 -0700394 AudioFrameList* additionalFramesList) const {
aleloi311525e2016-09-07 06:13:12 -0700395 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700396 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700397 "GetAdditionalAudio(additionalFramesList)");
aleloi09f45102016-07-28 03:52:15 -0700398 // The GetAudioFrameWithMuted() callback may result in the audio source being
aleloia0db81f2016-07-28 06:36:22 -0700399 // removed from additionalAudioFramesList_. If that happens it will
aleloi09f45102016-07-28 03:52:15 -0700400 // invalidate any iterators. Create a copy of the audio sources list such
aleloia0db81f2016-07-28 06:36:22 -0700401 // that the list of participants can be traversed safely.
aleloi09f45102016-07-28 03:52:15 -0700402 MixerAudioSourceList additionalAudioSourceList;
403 additionalAudioSourceList.insert(additionalAudioSourceList.begin(),
404 additional_audio_source_list_.begin(),
405 additional_audio_source_list_.end());
aleloi77ad3942016-07-04 06:33:02 -0700406
aleloi09f45102016-07-28 03:52:15 -0700407 for (MixerAudioSourceList::const_iterator audio_source =
408 additionalAudioSourceList.begin();
409 audio_source != additionalAudioSourceList.end(); ++audio_source) {
aleloia0db81f2016-07-28 06:36:22 -0700410 auto audio_frame_with_info =
aleloi6382a192016-08-08 10:25:04 -0700411 (*audio_source)->GetAudioFrameWithMuted(id_, output_frequency_);
aleloia0db81f2016-07-28 06:36:22 -0700412 auto ret = audio_frame_with_info.audio_frame_info;
413 AudioFrame* audio_frame = audio_frame_with_info.audio_frame;
aleloi77ad3942016-07-04 06:33:02 -0700414 if (ret == MixerAudioSource::AudioFrameInfo::kError) {
aleloi6382a192016-08-08 10:25:04 -0700415 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700416 "failed to GetAudioFrameWithMuted() from audio_source");
aleloi77ad3942016-07-04 06:33:02 -0700417 continue;
418 }
aleloia0db81f2016-07-28 06:36:22 -0700419 if (audio_frame->samples_per_channel_ == 0) {
aleloi77ad3942016-07-04 06:33:02 -0700420 // Empty frame. Don't use it.
aleloi77ad3942016-07-04 06:33:02 -0700421 continue;
422 }
423 additionalFramesList->push_back(FrameAndMuteInfo(
aleloia0db81f2016-07-28 06:36:22 -0700424 audio_frame, ret == MixerAudioSource::AudioFrameInfo::kMuted));
aleloi77ad3942016-07-04 06:33:02 -0700425 }
426}
427
aleloi5d167d62016-08-24 02:20:54 -0700428bool AudioMixerImpl::IsAudioSourceInList(
aleloi09f45102016-07-28 03:52:15 -0700429 const MixerAudioSource& audio_source,
430 const MixerAudioSourceList& audioSourceList) const {
aleloi6382a192016-08-08 10:25:04 -0700431 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700432 "IsAudioSourceInList(audio_source,audioSourceList)");
aleloi6382a192016-08-08 10:25:04 -0700433 return std::find(audioSourceList.begin(), audioSourceList.end(),
434 &audio_source) != audioSourceList.end();
aleloi77ad3942016-07-04 06:33:02 -0700435}
436
aleloi5d167d62016-08-24 02:20:54 -0700437bool AudioMixerImpl::AddAudioSourceToList(
aleloi09f45102016-07-28 03:52:15 -0700438 MixerAudioSource* audio_source,
439 MixerAudioSourceList* audioSourceList) const {
aleloi6382a192016-08-08 10:25:04 -0700440 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700441 "AddAudioSourceToList(audio_source, audioSourceList)");
442 audioSourceList->push_back(audio_source);
aleloi77ad3942016-07-04 06:33:02 -0700443 // Make sure that the mixed status is correct for new MixerAudioSource.
aleloi09f45102016-07-28 03:52:15 -0700444 audio_source->_mixHistory->ResetMixedStatus();
aleloi77ad3942016-07-04 06:33:02 -0700445 return true;
446}
447
aleloi5d167d62016-08-24 02:20:54 -0700448bool AudioMixerImpl::RemoveAudioSourceFromList(
aleloi09f45102016-07-28 03:52:15 -0700449 MixerAudioSource* audio_source,
450 MixerAudioSourceList* audioSourceList) const {
aleloi6382a192016-08-08 10:25:04 -0700451 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi09f45102016-07-28 03:52:15 -0700452 "RemoveAudioSourceFromList(audio_source, audioSourceList)");
aleloi6382a192016-08-08 10:25:04 -0700453 auto iter =
454 std::find(audioSourceList->begin(), audioSourceList->end(), audio_source);
455 if (iter != audioSourceList->end()) {
456 audioSourceList->erase(iter);
457 // AudioSource is no longer mixed, reset to default.
458 audio_source->_mixHistory->ResetMixedStatus();
459 return true;
460 } else {
461 return false;
aleloi77ad3942016-07-04 06:33:02 -0700462 }
aleloi77ad3942016-07-04 06:33:02 -0700463}
464
aleloi5d167d62016-08-24 02:20:54 -0700465int32_t AudioMixerImpl::MixFromList(AudioFrame* mixedAudio,
466 const AudioFrameList& audioFrameList,
467 int32_t id,
468 bool use_limiter) {
aleloi09f45102016-07-28 03:52:15 -0700469 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id,
aleloi77ad3942016-07-04 06:33:02 -0700470 "MixFromList(mixedAudio, audioFrameList)");
471 if (audioFrameList.empty())
472 return 0;
473
474 uint32_t position = 0;
475
aleloi09f45102016-07-28 03:52:15 -0700476 if (audioFrameList.size() == 1) {
aleloi77ad3942016-07-04 06:33:02 -0700477 mixedAudio->timestamp_ = audioFrameList.front().frame->timestamp_;
478 mixedAudio->elapsed_time_ms_ =
479 audioFrameList.front().frame->elapsed_time_ms_;
480 } else {
481 // TODO(wu): Issue 3390.
482 // Audio frame timestamp is only supported in one channel case.
483 mixedAudio->timestamp_ = 0;
484 mixedAudio->elapsed_time_ms_ = -1;
485 }
486
487 for (AudioFrameList::const_iterator iter = audioFrameList.begin();
488 iter != audioFrameList.end(); ++iter) {
aleloi77ad3942016-07-04 06:33:02 -0700489 if (!iter->muted) {
aleloi09f45102016-07-28 03:52:15 -0700490 MixFrames(mixedAudio, iter->frame, use_limiter);
aleloi77ad3942016-07-04 06:33:02 -0700491 }
492
493 position++;
494 }
495
496 return 0;
497}
498
499// TODO(andrew): consolidate this function with MixFromList.
aleloi5d167d62016-08-24 02:20:54 -0700500int32_t AudioMixerImpl::MixAnonomouslyFromList(
aleloi77ad3942016-07-04 06:33:02 -0700501 AudioFrame* mixedAudio,
502 const AudioFrameList& audioFrameList) const {
aleloi311525e2016-09-07 06:13:12 -0700503 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi6382a192016-08-08 10:25:04 -0700504 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700505 "MixAnonomouslyFromList(mixedAudio, audioFrameList)");
506
507 if (audioFrameList.empty())
508 return 0;
509
510 for (AudioFrameList::const_iterator iter = audioFrameList.begin();
511 iter != audioFrameList.end(); ++iter) {
512 if (!iter->muted) {
513 MixFrames(mixedAudio, iter->frame, use_limiter_);
514 }
515 }
516 return 0;
517}
518
aleloi5d167d62016-08-24 02:20:54 -0700519bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixedAudio) const {
aleloi311525e2016-09-07 06:13:12 -0700520 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi77ad3942016-07-04 06:33:02 -0700521 if (!use_limiter_) {
522 return true;
523 }
524
525 // Smoothly limit the mixed frame.
aleloi6382a192016-08-08 10:25:04 -0700526 const int error = limiter_->ProcessStream(mixedAudio);
aleloi77ad3942016-07-04 06:33:02 -0700527
528 // And now we can safely restore the level. This procedure results in
529 // some loss of resolution, deemed acceptable.
530 //
531 // It's possible to apply the gain in the AGC (with a target level of 0 dbFS
532 // and compression gain of 6 dB). However, in the transition frame when this
aleloi09f45102016-07-28 03:52:15 -0700533 // is enabled (moving from one to two audio sources) it has the potential to
aleloi77ad3942016-07-04 06:33:02 -0700534 // create discontinuities in the mixed frame.
535 //
536 // Instead we double the frame (with addition since left-shifting a
537 // negative value is undefined).
538 *mixedAudio += *mixedAudio;
539
aleloi6382a192016-08-08 10:25:04 -0700540 if (error != limiter_->kNoError) {
541 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_,
aleloi77ad3942016-07-04 06:33:02 -0700542 "Error from AudioProcessing: %d", error);
aleloi09f45102016-07-28 03:52:15 -0700543 RTC_NOTREACHED();
aleloi77ad3942016-07-04 06:33:02 -0700544 return false;
545 }
546 return true;
547}
aleloi616df1e2016-08-24 01:17:12 -0700548
aleloi5d167d62016-08-24 02:20:54 -0700549int AudioMixerImpl::GetOutputAudioLevel() {
aleloi311525e2016-09-07 06:13:12 -0700550 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700551 const int level = audio_level_.Level();
552 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
553 "GetAudioOutputLevel() => level=%d", level);
554 return level;
555}
556
aleloi5d167d62016-08-24 02:20:54 -0700557int AudioMixerImpl::GetOutputAudioLevelFullRange() {
aleloi311525e2016-09-07 06:13:12 -0700558 RTC_DCHECK_RUN_ON(&thread_checker_);
aleloi616df1e2016-08-24 01:17:12 -0700559 const int level = audio_level_.LevelFullRange();
560 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_,
561 "GetAudioOutputLevelFullRange() => level=%d", level);
562 return level;
563}
aleloi77ad3942016-07-04 06:33:02 -0700564} // namespace webrtc