OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/audio_mixer/audio_mixer_impl.h" | 11 #include "webrtc/modules/audio_mixer/audio_mixer_impl.h" |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 #include <functional> | 14 #include <functional> |
| 15 #include <utility> |
15 | 16 |
| 17 #include "webrtc/base/thread_annotations.h" |
16 #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" | 18 #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" |
17 #include "webrtc/modules/audio_mixer/audio_mixer_defines.h" | 19 #include "webrtc/modules/audio_mixer/audio_mixer_defines.h" |
18 #include "webrtc/modules/audio_processing/include/audio_processing.h" | 20 #include "webrtc/modules/audio_processing/include/audio_processing.h" |
19 #include "webrtc/modules/utility/include/audio_frame_operations.h" | 21 #include "webrtc/modules/utility/include/audio_frame_operations.h" |
20 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 22 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
21 #include "webrtc/system_wrappers/include/trace.h" | 23 #include "webrtc/system_wrappers/include/trace.h" |
22 | 24 |
23 namespace webrtc { | 25 namespace webrtc { |
24 namespace { | 26 namespace { |
25 | 27 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 int32_t NewMixHistory::SetIsMixed(const bool mixed) { | 115 int32_t NewMixHistory::SetIsMixed(const bool mixed) { |
114 is_mixed_ = mixed; | 116 is_mixed_ = mixed; |
115 return 0; | 117 return 0; |
116 } | 118 } |
117 | 119 |
118 void NewMixHistory::ResetMixedStatus() { | 120 void NewMixHistory::ResetMixedStatus() { |
119 is_mixed_ = false; | 121 is_mixed_ = false; |
120 } | 122 } |
121 | 123 |
122 std::unique_ptr<AudioMixer> AudioMixer::Create(int id) { | 124 std::unique_ptr<AudioMixer> AudioMixer::Create(int id) { |
123 AudioMixerImpl* mixer = new AudioMixerImpl(id); | 125 return AudioMixerImpl::Create(id); |
124 if (!mixer->Init()) { | |
125 delete mixer; | |
126 return NULL; | |
127 } | |
128 return std::unique_ptr<AudioMixer>(mixer); | |
129 } | 126 } |
130 | 127 |
131 AudioMixerImpl::AudioMixerImpl(int id) | 128 AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter) |
132 : id_(id), | 129 : id_(id), |
133 output_frequency_(kDefaultFrequency), | |
134 sample_size_(0), | |
135 audio_source_list_(), | 130 audio_source_list_(), |
136 additional_audio_source_list_(), | 131 additional_audio_source_list_(), |
137 num_mixed_audio_sources_(0), | 132 num_mixed_audio_sources_(0), |
138 use_limiter_(true), | 133 use_limiter_(true), |
139 time_stamp_(0) { | 134 time_stamp_(0), |
| 135 limiter_(std::move(limiter)) { |
| 136 SetOutputFrequency(kDefaultFrequency); |
140 thread_checker_.DetachFromThread(); | 137 thread_checker_.DetachFromThread(); |
141 } | 138 } |
142 | 139 |
143 AudioMixerImpl::~AudioMixerImpl() {} | 140 AudioMixerImpl::~AudioMixerImpl() {} |
144 | 141 |
145 bool AudioMixerImpl::Init() { | 142 std::unique_ptr<AudioMixer> AudioMixerImpl::Create(int id) { |
146 crit_.reset(CriticalSectionWrapper::CreateCriticalSection()); | |
147 if (crit_.get() == NULL) | |
148 return false; | |
149 | |
150 cb_crit_.reset(CriticalSectionWrapper::CreateCriticalSection()); | |
151 if (cb_crit_.get() == NULL) | |
152 return false; | |
153 | |
154 Config config; | 143 Config config; |
155 config.Set<ExperimentalAgc>(new ExperimentalAgc(false)); | 144 config.Set<ExperimentalAgc>(new ExperimentalAgc(false)); |
156 limiter_.reset(AudioProcessing::Create(config)); | 145 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config)); |
157 if (!limiter_.get()) | 146 if (!limiter.get()) |
158 return false; | 147 return nullptr; |
159 | 148 |
160 if (SetOutputFrequency(kDefaultFrequency) == -1) | 149 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) != |
161 return false; | 150 limiter->kNoError) |
162 | 151 return nullptr; |
163 if (limiter_->gain_control()->set_mode(GainControl::kFixedDigital) != | |
164 limiter_->kNoError) | |
165 return false; | |
166 | 152 |
167 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the | 153 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the |
168 // divide-by-2 but -7 is used instead to give a bit of headroom since the | 154 // divide-by-2 but -7 is used instead to give a bit of headroom since the |
169 // AGC is not a hard limiter. | 155 // AGC is not a hard limiter. |
170 if (limiter_->gain_control()->set_target_level_dbfs(7) != limiter_->kNoError) | 156 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError) |
171 return false; | 157 return nullptr; |
172 | 158 |
173 if (limiter_->gain_control()->set_compression_gain_db(0) != | 159 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError) |
174 limiter_->kNoError) | 160 return nullptr; |
175 return false; | |
176 | 161 |
177 if (limiter_->gain_control()->enable_limiter(true) != limiter_->kNoError) | 162 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError) |
178 return false; | 163 return nullptr; |
179 | 164 |
180 if (limiter_->gain_control()->Enable(true) != limiter_->kNoError) | 165 if (limiter->gain_control()->Enable(true) != limiter->kNoError) |
181 return false; | 166 return nullptr; |
182 | 167 |
183 return true; | 168 return std::unique_ptr<AudioMixer>( |
| 169 new AudioMixerImpl(id, std::move(limiter))); |
184 } | 170 } |
185 | 171 |
186 void AudioMixerImpl::Mix(int sample_rate, | 172 void AudioMixerImpl::Mix(int sample_rate, |
187 size_t number_of_channels, | 173 size_t number_of_channels, |
188 AudioFrame* audio_frame_for_mixing) { | 174 AudioFrame* audio_frame_for_mixing) { |
189 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); | 175 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); |
190 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 176 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 |
191 AudioFrameList mixList; | 191 AudioFrameList mixList; |
192 AudioFrameList additionalFramesList; | 192 AudioFrameList additionalFramesList; |
193 std::map<int, MixerAudioSource*> mixedAudioSourcesMap; | 193 int num_mixed_audio_sources; |
194 { | 194 { |
195 CriticalSectionScoped cs(cb_crit_.get()); | 195 rtc::CritScope lock(&crit_); |
196 Frequency mixing_frequency; | |
197 | |
198 switch (sample_rate) { | |
199 case 8000: | |
200 mixing_frequency = kNbInHz; | |
201 break; | |
202 case 16000: | |
203 mixing_frequency = kWbInHz; | |
204 break; | |
205 case 32000: | |
206 mixing_frequency = kSwbInHz; | |
207 break; | |
208 case 48000: | |
209 mixing_frequency = kFbInHz; | |
210 break; | |
211 default: | |
212 RTC_NOTREACHED(); | |
213 return; | |
214 } | |
215 | |
216 if (OutputFrequency() != mixing_frequency) { | |
217 SetOutputFrequency(mixing_frequency); | |
218 } | |
219 | |
220 mixList = UpdateToMix(kMaximumAmountOfMixedAudioSources); | 196 mixList = UpdateToMix(kMaximumAmountOfMixedAudioSources); |
221 GetAdditionalAudio(&additionalFramesList); | 197 GetAdditionalAudio(&additionalFramesList); |
| 198 num_mixed_audio_sources = static_cast<int>(num_mixed_audio_sources_); |
222 } | 199 } |
223 | 200 |
224 for (FrameAndMuteInfo& frame_and_mute : mixList) { | 201 for (FrameAndMuteInfo& frame_and_mute : mixList) { |
225 RemixFrame(frame_and_mute.frame, number_of_channels); | 202 RemixFrame(frame_and_mute.frame, number_of_channels); |
226 } | 203 } |
227 for (FrameAndMuteInfo& frame_and_mute : additionalFramesList) { | 204 for (FrameAndMuteInfo& frame_and_mute : additionalFramesList) { |
228 RemixFrame(frame_and_mute.frame, number_of_channels); | 205 RemixFrame(frame_and_mute.frame, number_of_channels); |
229 } | 206 } |
230 | 207 |
231 audio_frame_for_mixing->UpdateFrame( | 208 audio_frame_for_mixing->UpdateFrame( |
232 -1, time_stamp_, NULL, 0, output_frequency_, AudioFrame::kNormalSpeech, | 209 -1, time_stamp_, NULL, 0, output_frequency_, AudioFrame::kNormalSpeech, |
233 AudioFrame::kVadPassive, number_of_channels); | 210 AudioFrame::kVadPassive, number_of_channels); |
234 | 211 |
235 time_stamp_ += static_cast<uint32_t>(sample_size_); | 212 time_stamp_ += static_cast<uint32_t>(sample_size_); |
236 | 213 |
237 use_limiter_ = num_mixed_audio_sources_ > 1; | 214 use_limiter_ = num_mixed_audio_sources > 1; |
238 | 215 |
239 // We only use the limiter if it supports the output sample rate and | 216 // We only use the limiter if it supports the output sample rate and |
240 // we're actually mixing multiple streams. | 217 // we're actually mixing multiple streams. |
241 MixFromList(audio_frame_for_mixing, mixList, id_, use_limiter_); | 218 MixFromList(audio_frame_for_mixing, mixList, id_, use_limiter_); |
242 | 219 MixAnonomouslyFromList(audio_frame_for_mixing, additionalFramesList); |
243 { | 220 if (audio_frame_for_mixing->samples_per_channel_ == 0) { |
244 CriticalSectionScoped cs(crit_.get()); | 221 // Nothing was mixed, set the audio samples to silence. |
245 MixAnonomouslyFromList(audio_frame_for_mixing, additionalFramesList); | 222 audio_frame_for_mixing->samples_per_channel_ = sample_size_; |
246 | 223 audio_frame_for_mixing->Mute(); |
247 if (audio_frame_for_mixing->samples_per_channel_ == 0) { | 224 } else { |
248 // Nothing was mixed, set the audio samples to silence. | 225 // Only call the limiter if we have something to mix. |
249 audio_frame_for_mixing->samples_per_channel_ = sample_size_; | 226 LimitMixedAudio(audio_frame_for_mixing); |
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); | |
254 } | |
255 } | 227 } |
256 | 228 |
257 // Pass the final result to the level indicator. | 229 // Pass the final result to the level indicator. |
258 audio_level_.ComputeLevel(*audio_frame_for_mixing); | 230 audio_level_.ComputeLevel(*audio_frame_for_mixing); |
259 | 231 |
260 return; | 232 return; |
261 } | 233 } |
262 | 234 |
263 int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) { | 235 int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) { |
264 CriticalSectionScoped cs(crit_.get()); | 236 RTC_DCHECK_RUN_ON(&thread_checker_); |
265 | |
266 output_frequency_ = frequency; | 237 output_frequency_ = frequency; |
267 sample_size_ = | 238 sample_size_ = |
268 static_cast<size_t>((output_frequency_ * kFrameDurationInMs) / 1000); | 239 static_cast<size_t>((output_frequency_ * kFrameDurationInMs) / 1000); |
269 | 240 |
270 return 0; | 241 return 0; |
271 } | 242 } |
272 | 243 |
273 AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const { | 244 AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const { |
274 CriticalSectionScoped cs(crit_.get()); | 245 RTC_DCHECK_RUN_ON(&thread_checker_); |
275 return output_frequency_; | 246 return output_frequency_; |
276 } | 247 } |
277 | 248 |
278 int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source, | 249 int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source, |
279 bool mixable) { | 250 bool mixable) { |
280 if (!mixable) { | 251 if (!mixable) { |
281 // Anonymous audio sources are in a separate list. Make sure that the | 252 // Anonymous audio sources are in a separate list. Make sure that the |
282 // audio source is in the _audioSourceList if it is being mixed. | 253 // audio source is in the _audioSourceList if it is being mixed. |
283 SetAnonymousMixabilityStatus(audio_source, false); | 254 SetAnonymousMixabilityStatus(audio_source, false); |
284 } | 255 } |
285 size_t numMixedAudioSources; | |
286 { | 256 { |
287 CriticalSectionScoped cs(cb_crit_.get()); | 257 rtc::CritScope lock(&crit_); |
288 const bool isMixed = IsAudioSourceInList(*audio_source, audio_source_list_); | 258 const bool isMixed = IsAudioSourceInList(*audio_source, audio_source_list_); |
289 // API must be called with a new state. | 259 // API must be called with a new state. |
290 if (!(mixable ^ isMixed)) { | 260 if (!(mixable ^ isMixed)) { |
291 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, | 261 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, |
292 "Mixable is aready %s", isMixed ? "ON" : "off"); | 262 "Mixable is aready %s", isMixed ? "ON" : "off"); |
293 return -1; | 263 return -1; |
294 } | 264 } |
295 bool success = false; | 265 bool success = false; |
296 if (mixable) { | 266 if (mixable) { |
297 success = AddAudioSourceToList(audio_source, &audio_source_list_); | 267 success = AddAudioSourceToList(audio_source, &audio_source_list_); |
298 } else { | 268 } else { |
299 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_); | 269 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_); |
300 } | 270 } |
301 if (!success) { | 271 if (!success) { |
302 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | 272 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, |
303 "failed to %s audio_source", mixable ? "add" : "remove"); | 273 "failed to %s audio_source", mixable ? "add" : "remove"); |
304 RTC_NOTREACHED(); | 274 RTC_NOTREACHED(); |
305 return -1; | 275 return -1; |
306 } | 276 } |
307 | 277 |
308 size_t numMixedNonAnonymous = audio_source_list_.size(); | 278 size_t numMixedNonAnonymous = audio_source_list_.size(); |
309 if (numMixedNonAnonymous > kMaximumAmountOfMixedAudioSources) { | 279 if (numMixedNonAnonymous > kMaximumAmountOfMixedAudioSources) { |
310 numMixedNonAnonymous = kMaximumAmountOfMixedAudioSources; | 280 numMixedNonAnonymous = kMaximumAmountOfMixedAudioSources; |
311 } | 281 } |
312 numMixedAudioSources = | 282 num_mixed_audio_sources_ = |
313 numMixedNonAnonymous + additional_audio_source_list_.size(); | 283 numMixedNonAnonymous + additional_audio_source_list_.size(); |
314 } | 284 } |
315 // A MixerAudioSource was added or removed. Make sure the scratch | |
316 // buffer is updated if necessary. | |
317 // Note: The scratch buffer may only be updated in Process(). | |
318 CriticalSectionScoped cs(crit_.get()); | |
319 num_mixed_audio_sources_ = numMixedAudioSources; | |
320 return 0; | 285 return 0; |
321 } | 286 } |
322 | 287 |
323 bool AudioMixerImpl::MixabilityStatus( | 288 bool AudioMixerImpl::MixabilityStatus( |
324 const MixerAudioSource& audio_source) const { | 289 const MixerAudioSource& audio_source) const { |
325 CriticalSectionScoped cs(cb_crit_.get()); | 290 rtc::CritScope lock(&crit_); |
326 return IsAudioSourceInList(audio_source, audio_source_list_); | 291 return IsAudioSourceInList(audio_source, audio_source_list_); |
327 } | 292 } |
328 | 293 |
329 int32_t AudioMixerImpl::SetAnonymousMixabilityStatus( | 294 int32_t AudioMixerImpl::SetAnonymousMixabilityStatus( |
330 MixerAudioSource* audio_source, | 295 MixerAudioSource* audio_source, |
331 bool anonymous) { | 296 bool anonymous) { |
332 CriticalSectionScoped cs(cb_crit_.get()); | 297 rtc::CritScope lock(&crit_); |
333 if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) { | 298 if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) { |
334 if (anonymous) { | 299 if (anonymous) { |
335 return 0; | 300 return 0; |
336 } | 301 } |
337 if (!RemoveAudioSourceFromList(audio_source, | 302 if (!RemoveAudioSourceFromList(audio_source, |
338 &additional_audio_source_list_)) { | 303 &additional_audio_source_list_)) { |
339 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | 304 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, |
340 "unable to remove audio_source from anonymous list"); | 305 "unable to remove audio_source from anonymous list"); |
341 RTC_NOTREACHED(); | 306 RTC_NOTREACHED(); |
342 return -1; | 307 return -1; |
(...skipping 13 matching lines...) Expand all Loading... |
356 // already registered. | 321 // already registered. |
357 return -1; | 322 return -1; |
358 } | 323 } |
359 return AddAudioSourceToList(audio_source, &additional_audio_source_list_) | 324 return AddAudioSourceToList(audio_source, &additional_audio_source_list_) |
360 ? 0 | 325 ? 0 |
361 : -1; | 326 : -1; |
362 } | 327 } |
363 | 328 |
364 bool AudioMixerImpl::AnonymousMixabilityStatus( | 329 bool AudioMixerImpl::AnonymousMixabilityStatus( |
365 const MixerAudioSource& audio_source) const { | 330 const MixerAudioSource& audio_source) const { |
366 CriticalSectionScoped cs(cb_crit_.get()); | 331 rtc::CritScope lock(&crit_); |
367 return IsAudioSourceInList(audio_source, additional_audio_source_list_); | 332 return IsAudioSourceInList(audio_source, additional_audio_source_list_); |
368 } | 333 } |
369 | 334 |
370 AudioFrameList AudioMixerImpl::UpdateToMix(size_t maxAudioFrameCounter) const { | 335 AudioFrameList AudioMixerImpl::UpdateToMix(size_t maxAudioFrameCounter) const { |
| 336 RTC_DCHECK_RUN_ON(&thread_checker_); |
371 AudioFrameList result; | 337 AudioFrameList result; |
372 std::vector<SourceFrame> audioSourceMixingDataList; | 338 std::vector<SourceFrame> audioSourceMixingDataList; |
373 | 339 |
374 // Get audio source audio and put it in the struct vector. | 340 // Get audio source audio and put it in the struct vector. |
375 for (MixerAudioSource* audio_source : audio_source_list_) { | 341 for (MixerAudioSource* audio_source : audio_source_list_) { |
376 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( | 342 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( |
377 id_, static_cast<int>(output_frequency_)); | 343 id_, static_cast<int>(output_frequency_)); |
378 | 344 |
379 auto audio_frame_info = audio_frame_with_info.audio_frame_info; | 345 auto audio_frame_info = audio_frame_with_info.audio_frame_info; |
380 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame; | 346 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 result.emplace_back(p.audio_frame_, false); | 385 result.emplace_back(p.audio_frame_, false); |
420 } | 386 } |
421 | 387 |
422 p.audio_source_->_mixHistory->SetIsMixed(is_mixed); | 388 p.audio_source_->_mixHistory->SetIsMixed(is_mixed); |
423 } | 389 } |
424 return result; | 390 return result; |
425 } | 391 } |
426 | 392 |
427 void AudioMixerImpl::GetAdditionalAudio( | 393 void AudioMixerImpl::GetAdditionalAudio( |
428 AudioFrameList* additionalFramesList) const { | 394 AudioFrameList* additionalFramesList) const { |
| 395 RTC_DCHECK_RUN_ON(&thread_checker_); |
429 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | 396 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
430 "GetAdditionalAudio(additionalFramesList)"); | 397 "GetAdditionalAudio(additionalFramesList)"); |
431 // The GetAudioFrameWithMuted() callback may result in the audio source being | 398 // The GetAudioFrameWithMuted() callback may result in the audio source being |
432 // removed from additionalAudioFramesList_. If that happens it will | 399 // removed from additionalAudioFramesList_. If that happens it will |
433 // invalidate any iterators. Create a copy of the audio sources list such | 400 // invalidate any iterators. Create a copy of the audio sources list such |
434 // that the list of participants can be traversed safely. | 401 // that the list of participants can be traversed safely. |
435 MixerAudioSourceList additionalAudioSourceList; | 402 MixerAudioSourceList additionalAudioSourceList; |
436 additionalAudioSourceList.insert(additionalAudioSourceList.begin(), | 403 additionalAudioSourceList.insert(additionalAudioSourceList.begin(), |
437 additional_audio_source_list_.begin(), | 404 additional_audio_source_list_.begin(), |
438 additional_audio_source_list_.end()); | 405 additional_audio_source_list_.end()); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 position++; | 493 position++; |
527 } | 494 } |
528 | 495 |
529 return 0; | 496 return 0; |
530 } | 497 } |
531 | 498 |
532 // TODO(andrew): consolidate this function with MixFromList. | 499 // TODO(andrew): consolidate this function with MixFromList. |
533 int32_t AudioMixerImpl::MixAnonomouslyFromList( | 500 int32_t AudioMixerImpl::MixAnonomouslyFromList( |
534 AudioFrame* mixedAudio, | 501 AudioFrame* mixedAudio, |
535 const AudioFrameList& audioFrameList) const { | 502 const AudioFrameList& audioFrameList) const { |
| 503 RTC_DCHECK_RUN_ON(&thread_checker_); |
536 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | 504 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
537 "MixAnonomouslyFromList(mixedAudio, audioFrameList)"); | 505 "MixAnonomouslyFromList(mixedAudio, audioFrameList)"); |
538 | 506 |
539 if (audioFrameList.empty()) | 507 if (audioFrameList.empty()) |
540 return 0; | 508 return 0; |
541 | 509 |
542 for (AudioFrameList::const_iterator iter = audioFrameList.begin(); | 510 for (AudioFrameList::const_iterator iter = audioFrameList.begin(); |
543 iter != audioFrameList.end(); ++iter) { | 511 iter != audioFrameList.end(); ++iter) { |
544 if (!iter->muted) { | 512 if (!iter->muted) { |
545 MixFrames(mixedAudio, iter->frame, use_limiter_); | 513 MixFrames(mixedAudio, iter->frame, use_limiter_); |
546 } | 514 } |
547 } | 515 } |
548 return 0; | 516 return 0; |
549 } | 517 } |
550 | 518 |
551 bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixedAudio) const { | 519 bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixedAudio) const { |
| 520 RTC_DCHECK_RUN_ON(&thread_checker_); |
552 if (!use_limiter_) { | 521 if (!use_limiter_) { |
553 return true; | 522 return true; |
554 } | 523 } |
555 | 524 |
556 // Smoothly limit the mixed frame. | 525 // Smoothly limit the mixed frame. |
557 const int error = limiter_->ProcessStream(mixedAudio); | 526 const int error = limiter_->ProcessStream(mixedAudio); |
558 | 527 |
559 // And now we can safely restore the level. This procedure results in | 528 // And now we can safely restore the level. This procedure results in |
560 // some loss of resolution, deemed acceptable. | 529 // some loss of resolution, deemed acceptable. |
561 // | 530 // |
562 // It's possible to apply the gain in the AGC (with a target level of 0 dbFS | 531 // It's possible to apply the gain in the AGC (with a target level of 0 dbFS |
563 // and compression gain of 6 dB). However, in the transition frame when this | 532 // and compression gain of 6 dB). However, in the transition frame when this |
564 // is enabled (moving from one to two audio sources) it has the potential to | 533 // is enabled (moving from one to two audio sources) it has the potential to |
565 // create discontinuities in the mixed frame. | 534 // create discontinuities in the mixed frame. |
566 // | 535 // |
567 // Instead we double the frame (with addition since left-shifting a | 536 // Instead we double the frame (with addition since left-shifting a |
568 // negative value is undefined). | 537 // negative value is undefined). |
569 *mixedAudio += *mixedAudio; | 538 *mixedAudio += *mixedAudio; |
570 | 539 |
571 if (error != limiter_->kNoError) { | 540 if (error != limiter_->kNoError) { |
572 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | 541 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, |
573 "Error from AudioProcessing: %d", error); | 542 "Error from AudioProcessing: %d", error); |
574 RTC_NOTREACHED(); | 543 RTC_NOTREACHED(); |
575 return false; | 544 return false; |
576 } | 545 } |
577 return true; | 546 return true; |
578 } | 547 } |
579 | 548 |
580 int AudioMixerImpl::GetOutputAudioLevel() { | 549 int AudioMixerImpl::GetOutputAudioLevel() { |
| 550 RTC_DCHECK_RUN_ON(&thread_checker_); |
581 const int level = audio_level_.Level(); | 551 const int level = audio_level_.Level(); |
582 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, | 552 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, |
583 "GetAudioOutputLevel() => level=%d", level); | 553 "GetAudioOutputLevel() => level=%d", level); |
584 return level; | 554 return level; |
585 } | 555 } |
586 | 556 |
587 int AudioMixerImpl::GetOutputAudioLevelFullRange() { | 557 int AudioMixerImpl::GetOutputAudioLevelFullRange() { |
| 558 RTC_DCHECK_RUN_ON(&thread_checker_); |
588 const int level = audio_level_.LevelFullRange(); | 559 const int level = audio_level_.LevelFullRange(); |
589 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, | 560 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, |
590 "GetAudioOutputLevelFullRange() => level=%d", level); | 561 "GetAudioOutputLevelFullRange() => level=%d", level); |
591 return level; | 562 return level; |
592 } | 563 } |
593 } // namespace webrtc | 564 } // namespace webrtc |
OLD | NEW |