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 #include <utility> |
16 | 16 |
17 #include "webrtc/base/logging.h" | |
18 #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" | 17 #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" |
19 #include "webrtc/modules/utility/include/audio_frame_operations.h" | 18 #include "webrtc/modules/utility/include/audio_frame_operations.h" |
20 #include "webrtc/system_wrappers/include/trace.h" | 19 #include "webrtc/system_wrappers/include/trace.h" |
21 | 20 |
22 namespace webrtc { | 21 namespace webrtc { |
23 namespace { | 22 namespace { |
24 | 23 |
25 class SourceFrame { | 24 class SourceFrame { |
26 public: | 25 public: |
27 SourceFrame(AudioSourceWithMixStatus* audio_source, | 26 SourceFrame(MixerAudioSource* p, AudioFrame* a, bool m, bool was_mixed_before) |
28 AudioFrame* audio_frame, | 27 : audio_source_(p), |
29 bool muted) | 28 audio_frame_(a), |
30 : audio_source_(audio_source), audio_frame_(audio_frame), muted_(muted) { | 29 muted_(m), |
| 30 was_mixed_before_(was_mixed_before) { |
31 if (!muted_) { | 31 if (!muted_) { |
32 energy_ = AudioMixerCalculateEnergy(*audio_frame); | 32 energy_ = NewMixerCalculateEnergy(*a); |
33 } | 33 } |
34 } | 34 } |
35 | 35 |
36 SourceFrame(AudioSourceWithMixStatus* audio_source, | 36 SourceFrame(MixerAudioSource* p, |
37 AudioFrame* audio_frame, | 37 AudioFrame* a, |
38 bool muted, | 38 bool m, |
| 39 bool was_mixed_before, |
39 uint32_t energy) | 40 uint32_t energy) |
40 : audio_source_(audio_source), | 41 : audio_source_(p), |
41 audio_frame_(audio_frame), | 42 audio_frame_(a), |
42 muted_(muted), | 43 muted_(m), |
43 energy_(energy) {} | 44 energy_(energy), |
| 45 was_mixed_before_(was_mixed_before) {} |
44 | 46 |
45 // a.ShouldMixBefore(b) is used to select mixer sources. | 47 // a.shouldMixBefore(b) is used to select mixer participants. |
46 bool ShouldMixBefore(const SourceFrame& other) const { | 48 bool shouldMixBefore(const SourceFrame& other) const { |
47 if (muted_ != other.muted_) { | 49 if (muted_ != other.muted_) { |
48 return other.muted_; | 50 return other.muted_; |
49 } | 51 } |
50 | 52 |
51 const auto our_activity = audio_frame_->vad_activity_; | 53 const auto our_activity = audio_frame_->vad_activity_; |
52 const auto other_activity = other.audio_frame_->vad_activity_; | 54 const auto other_activity = other.audio_frame_->vad_activity_; |
53 | 55 |
54 if (our_activity != other_activity) { | 56 if (our_activity != other_activity) { |
55 return our_activity == AudioFrame::kVadActive; | 57 return our_activity == AudioFrame::kVadActive; |
56 } | 58 } |
57 | 59 |
58 return energy_ > other.energy_; | 60 return energy_ > other.energy_; |
59 } | 61 } |
60 | 62 |
61 AudioSourceWithMixStatus* audio_source_ = nullptr; | 63 MixerAudioSource* audio_source_; |
62 AudioFrame* audio_frame_ = nullptr; | 64 AudioFrame* audio_frame_; |
63 bool muted_ = true; | 65 bool muted_; |
64 uint32_t energy_ = 0; | 66 uint32_t energy_; |
| 67 bool was_mixed_before_; |
65 }; | 68 }; |
66 | 69 |
67 // Remixes a frame between stereo and mono. | 70 // Remixes a frame between stereo and mono. |
68 void RemixFrame(AudioFrame* frame, size_t number_of_channels) { | 71 void RemixFrame(AudioFrame* frame, size_t number_of_channels) { |
69 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); | 72 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); |
70 if (frame->num_channels_ == 1 && number_of_channels == 2) { | 73 if (frame->num_channels_ == 1 && number_of_channels == 2) { |
71 AudioFrameOperations::MonoToStereo(frame); | 74 AudioFrameOperations::MonoToStereo(frame); |
72 } else if (frame->num_channels_ == 2 && number_of_channels == 1) { | 75 } else if (frame->num_channels_ == 2 && number_of_channels == 1) { |
73 AudioFrameOperations::StereoToMono(frame); | 76 AudioFrameOperations::StereoToMono(frame); |
74 } | 77 } |
75 } | 78 } |
76 | 79 |
77 void Ramp(const std::vector<SourceFrame>& mixed_sources_and_frames) { | 80 void Ramp(const std::vector<SourceFrame>& mixed_sources_and_frames) { |
78 for (const auto& source_frame : mixed_sources_and_frames) { | 81 for (const auto& source_frame : mixed_sources_and_frames) { |
79 // Ramp in previously unmixed. | 82 // Ramp in previously unmixed. |
80 if (!source_frame.audio_source_->WasMixed()) { | 83 if (!source_frame.was_mixed_before_) { |
81 NewMixerRampIn(source_frame.audio_frame_); | 84 NewMixerRampIn(source_frame.audio_frame_); |
82 } | 85 } |
83 | 86 |
84 const bool is_mixed = source_frame.audio_source_->IsMixed(); | 87 const bool is_mixed = source_frame.audio_source_->IsMixed(); |
85 // Ramp out currently unmixed. | 88 // Ramp out currently unmixed. |
86 if (source_frame.audio_source_->WasMixed() && !is_mixed) { | 89 if (source_frame.was_mixed_before_ && !is_mixed) { |
87 NewMixerRampOut(source_frame.audio_frame_); | 90 NewMixerRampOut(source_frame.audio_frame_); |
88 } | 91 } |
89 } | 92 } |
90 } | 93 } |
91 | 94 |
92 // Mix the AudioFrames stored in audioFrameList into mixed_audio. | 95 // Mix the AudioFrames stored in audioFrameList into mixed_audio. |
93 int32_t MixFromList(AudioFrame* mixed_audio, | 96 int32_t MixFromList(AudioFrame* mixed_audio, |
94 const AudioFrameList& audio_frame_list, | 97 const AudioFrameList& audio_frame_list, |
95 int32_t id, | 98 int32_t id, |
96 bool use_limiter) { | 99 bool use_limiter) { |
(...skipping 26 matching lines...) Expand all Loading... |
123 // Divide by two to avoid saturation in the mixing. | 126 // Divide by two to avoid saturation in the mixing. |
124 // This is only meaningful if the limiter will be used. | 127 // This is only meaningful if the limiter will be used. |
125 *frame >>= 1; | 128 *frame >>= 1; |
126 } | 129 } |
127 RTC_DCHECK_EQ(frame->num_channels_, mixed_audio->num_channels_); | 130 RTC_DCHECK_EQ(frame->num_channels_, mixed_audio->num_channels_); |
128 *mixed_audio += *frame; | 131 *mixed_audio += *frame; |
129 } | 132 } |
130 return 0; | 133 return 0; |
131 } | 134 } |
132 | 135 |
133 MixerAudioSourceList::const_iterator FindSourceInList( | |
134 MixerAudioSource const* audio_source, | |
135 MixerAudioSourceList const* audio_source_list) { | |
136 return std::find_if(audio_source_list->begin(), audio_source_list->end(), | |
137 [audio_source](const AudioSourceWithMixStatus& p) { | |
138 return p.audio_source() == audio_source; | |
139 }); | |
140 } | |
141 | |
142 MixerAudioSourceList::iterator FindSourceInList( | |
143 MixerAudioSource const* audio_source, | |
144 MixerAudioSourceList* audio_source_list) { | |
145 return std::find_if(audio_source_list->begin(), audio_source_list->end(), | |
146 [audio_source](const AudioSourceWithMixStatus& p) { | |
147 return p.audio_source() == audio_source; | |
148 }); | |
149 } | |
150 | |
151 } // namespace | 136 } // namespace |
152 | 137 |
153 std::unique_ptr<AudioMixer> AudioMixer::Create(int id) { | 138 std::unique_ptr<AudioMixer> AudioMixer::Create(int id) { |
154 return AudioMixerImpl::Create(id); | 139 return AudioMixerImpl::Create(id); |
155 } | 140 } |
156 | 141 |
157 AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter) | 142 AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter) |
158 : id_(id), | 143 : id_(id), |
159 audio_source_list_(), | 144 audio_source_list_(), |
160 additional_audio_source_list_(), | 145 additional_audio_source_list_(), |
161 num_mixed_audio_sources_(0), | 146 num_mixed_audio_sources_(0), |
162 use_limiter_(true), | 147 use_limiter_(true), |
163 time_stamp_(0), | 148 time_stamp_(0), |
164 limiter_(std::move(limiter)) { | 149 limiter_(std::move(limiter)) { |
165 SetOutputFrequency(kDefaultFrequency); | 150 SetOutputFrequency(kDefaultFrequency); |
166 thread_checker_.DetachFromThread(); | 151 thread_checker_.DetachFromThread(); |
167 } | 152 } |
168 | 153 |
169 AudioMixerImpl::~AudioMixerImpl() {} | 154 AudioMixerImpl::~AudioMixerImpl() {} |
170 | 155 |
171 std::unique_ptr<AudioMixerImpl> AudioMixerImpl::Create(int id) { | 156 std::unique_ptr<AudioMixer> AudioMixerImpl::Create(int id) { |
172 Config config; | 157 Config config; |
173 config.Set<ExperimentalAgc>(new ExperimentalAgc(false)); | 158 config.Set<ExperimentalAgc>(new ExperimentalAgc(false)); |
174 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config)); | 159 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config)); |
175 if (!limiter.get()) | 160 if (!limiter.get()) |
176 return nullptr; | 161 return nullptr; |
177 | 162 |
178 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) != | 163 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) != |
179 limiter->kNoError) | 164 limiter->kNoError) |
180 return nullptr; | 165 return nullptr; |
181 | 166 |
182 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the | 167 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the |
183 // divide-by-2 but -7 is used instead to give a bit of headroom since the | 168 // divide-by-2 but -7 is used instead to give a bit of headroom since the |
184 // AGC is not a hard limiter. | 169 // AGC is not a hard limiter. |
185 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError) | 170 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError) |
186 return nullptr; | 171 return nullptr; |
187 | 172 |
188 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError) | 173 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError) |
189 return nullptr; | 174 return nullptr; |
190 | 175 |
191 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError) | 176 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError) |
192 return nullptr; | 177 return nullptr; |
193 | 178 |
194 if (limiter->gain_control()->Enable(true) != limiter->kNoError) | 179 if (limiter->gain_control()->Enable(true) != limiter->kNoError) |
195 return nullptr; | 180 return nullptr; |
196 | 181 |
197 return std::unique_ptr<AudioMixerImpl>( | 182 return std::unique_ptr<AudioMixer>( |
198 new AudioMixerImpl(id, std::move(limiter))); | 183 new AudioMixerImpl(id, std::move(limiter))); |
199 } | 184 } |
200 | 185 |
201 void AudioMixerImpl::Mix(int sample_rate, | 186 void AudioMixerImpl::Mix(int sample_rate, |
202 size_t number_of_channels, | 187 size_t number_of_channels, |
203 AudioFrame* audio_frame_for_mixing) { | 188 AudioFrame* audio_frame_for_mixing) { |
204 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); | 189 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); |
205 RTC_DCHECK_RUN_ON(&thread_checker_); | 190 RTC_DCHECK_RUN_ON(&thread_checker_); |
206 | 191 |
207 if (sample_rate != kNbInHz && sample_rate != kWbInHz && | 192 if (sample_rate != kNbInHz && sample_rate != kWbInHz && |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 | 259 |
275 int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source, | 260 int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source, |
276 bool mixable) { | 261 bool mixable) { |
277 if (!mixable) { | 262 if (!mixable) { |
278 // Anonymous audio sources are in a separate list. Make sure that the | 263 // Anonymous audio sources are in a separate list. Make sure that the |
279 // audio source is in the _audioSourceList if it is being mixed. | 264 // audio source is in the _audioSourceList if it is being mixed. |
280 SetAnonymousMixabilityStatus(audio_source, false); | 265 SetAnonymousMixabilityStatus(audio_source, false); |
281 } | 266 } |
282 { | 267 { |
283 rtc::CritScope lock(&crit_); | 268 rtc::CritScope lock(&crit_); |
284 const bool is_mixed = FindSourceInList(audio_source, &audio_source_list_) != | 269 const bool is_mixed = |
285 audio_source_list_.end(); | 270 IsAudioSourceInList(*audio_source, audio_source_list_); |
286 // API must be called with a new state. | 271 // API must be called with a new state. |
287 if (!(mixable ^ is_mixed)) { | 272 if (!(mixable ^ is_mixed)) { |
288 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, | 273 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, |
289 "Mixable is aready %s", is_mixed ? "ON" : "off"); | 274 "Mixable is aready %s", is_mixed ? "ON" : "off"); |
290 return -1; | 275 return -1; |
291 } | 276 } |
292 bool success = false; | 277 bool success = false; |
293 if (mixable) { | 278 if (mixable) { |
294 success = AddAudioSourceToList(audio_source, &audio_source_list_); | 279 success = AddAudioSourceToList(audio_source, &audio_source_list_); |
295 } else { | 280 } else { |
(...skipping 12 matching lines...) Expand all Loading... |
308 } | 293 } |
309 num_mixed_audio_sources_ = | 294 num_mixed_audio_sources_ = |
310 num_mixed_non_anonymous + additional_audio_source_list_.size(); | 295 num_mixed_non_anonymous + additional_audio_source_list_.size(); |
311 } | 296 } |
312 return 0; | 297 return 0; |
313 } | 298 } |
314 | 299 |
315 bool AudioMixerImpl::MixabilityStatus( | 300 bool AudioMixerImpl::MixabilityStatus( |
316 const MixerAudioSource& audio_source) const { | 301 const MixerAudioSource& audio_source) const { |
317 rtc::CritScope lock(&crit_); | 302 rtc::CritScope lock(&crit_); |
318 return FindSourceInList(&audio_source, &audio_source_list_) != | 303 return IsAudioSourceInList(audio_source, audio_source_list_); |
319 audio_source_list_.end(); | |
320 } | 304 } |
321 | 305 |
322 int32_t AudioMixerImpl::SetAnonymousMixabilityStatus( | 306 int32_t AudioMixerImpl::SetAnonymousMixabilityStatus( |
323 MixerAudioSource* audio_source, | 307 MixerAudioSource* audio_source, |
324 bool anonymous) { | 308 bool anonymous) { |
325 rtc::CritScope lock(&crit_); | 309 rtc::CritScope lock(&crit_); |
326 if (FindSourceInList(audio_source, &additional_audio_source_list_) != | 310 if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) { |
327 additional_audio_source_list_.end()) { | |
328 if (anonymous) { | 311 if (anonymous) { |
329 return 0; | 312 return 0; |
330 } | 313 } |
331 if (!RemoveAudioSourceFromList(audio_source, | 314 if (!RemoveAudioSourceFromList(audio_source, |
332 &additional_audio_source_list_)) { | 315 &additional_audio_source_list_)) { |
333 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | 316 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, |
334 "unable to remove audio_source from anonymous list"); | 317 "unable to remove audio_source from anonymous list"); |
335 RTC_NOTREACHED(); | 318 RTC_NOTREACHED(); |
336 return -1; | 319 return -1; |
337 } | 320 } |
(...skipping 13 matching lines...) Expand all Loading... |
351 return -1; | 334 return -1; |
352 } | 335 } |
353 return AddAudioSourceToList(audio_source, &additional_audio_source_list_) | 336 return AddAudioSourceToList(audio_source, &additional_audio_source_list_) |
354 ? 0 | 337 ? 0 |
355 : -1; | 338 : -1; |
356 } | 339 } |
357 | 340 |
358 bool AudioMixerImpl::AnonymousMixabilityStatus( | 341 bool AudioMixerImpl::AnonymousMixabilityStatus( |
359 const MixerAudioSource& audio_source) const { | 342 const MixerAudioSource& audio_source) const { |
360 rtc::CritScope lock(&crit_); | 343 rtc::CritScope lock(&crit_); |
361 return FindSourceInList(&audio_source, &additional_audio_source_list_) != | 344 return IsAudioSourceInList(audio_source, additional_audio_source_list_); |
362 additional_audio_source_list_.end(); | |
363 } | 345 } |
364 | 346 |
365 AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() { | 347 AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() const { |
366 RTC_DCHECK_RUN_ON(&thread_checker_); | 348 RTC_DCHECK_RUN_ON(&thread_checker_); |
367 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | 349 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
368 "GetNonAnonymousAudio()"); | 350 "GetNonAnonymousAudio()"); |
369 AudioFrameList result; | 351 AudioFrameList result; |
370 std::vector<SourceFrame> audio_source_mixing_data_list; | 352 std::vector<SourceFrame> audio_source_mixing_data_list; |
371 std::vector<SourceFrame> ramp_list; | 353 std::vector<SourceFrame> ramp_list; |
372 | 354 |
373 // Get audio source audio and put it in the struct vector. | 355 // Get audio source audio and put it in the struct vector. |
374 for (auto& source_and_status : audio_source_list_) { | 356 for (auto* const audio_source : audio_source_list_) { |
375 auto audio_frame_with_info = | 357 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( |
376 source_and_status.audio_source()->GetAudioFrameWithMuted( | 358 id_, static_cast<int>(OutputFrequency())); |
377 id_, static_cast<int>(OutputFrequency())); | |
378 | 359 |
379 const auto audio_frame_info = audio_frame_with_info.audio_frame_info; | 360 const auto audio_frame_info = audio_frame_with_info.audio_frame_info; |
380 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame; | 361 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame; |
381 | 362 |
382 if (audio_frame_info == MixerAudioSource::AudioFrameInfo::kError) { | 363 if (audio_frame_info == MixerAudioSource::AudioFrameInfo::kError) { |
383 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, | 364 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, |
384 "failed to GetAudioFrameWithMuted() from source"); | 365 "failed to GetAudioFrameWithMuted() from participant"); |
385 continue; | 366 continue; |
386 } | 367 } |
387 audio_source_mixing_data_list.emplace_back( | 368 audio_source_mixing_data_list.emplace_back( |
388 &source_and_status, audio_source_audio_frame, | 369 audio_source, audio_source_audio_frame, |
389 audio_frame_info == MixerAudioSource::AudioFrameInfo::kMuted); | 370 audio_frame_info == MixerAudioSource::AudioFrameInfo::kMuted, |
| 371 audio_source->WasMixed()); |
390 } | 372 } |
391 | 373 |
392 // Sort frames by sorting function. | 374 // Sort frames by sorting function. |
393 std::sort(audio_source_mixing_data_list.begin(), | 375 std::sort(audio_source_mixing_data_list.begin(), |
394 audio_source_mixing_data_list.end(), | 376 audio_source_mixing_data_list.end(), |
395 std::mem_fn(&SourceFrame::ShouldMixBefore)); | 377 std::mem_fn(&SourceFrame::shouldMixBefore)); |
396 | 378 |
397 int max_audio_frame_counter = kMaximumAmountOfMixedAudioSources; | 379 int max_audio_frame_counter = kMaximumAmountOfMixedAudioSources; |
398 | 380 |
399 // Go through list in order and put unmuted frames in result list. | 381 // Go through list in order and put unmuted frames in result list. |
400 for (const auto& p : audio_source_mixing_data_list) { | 382 for (const SourceFrame& p : audio_source_mixing_data_list) { |
401 // Filter muted. | 383 // Filter muted. |
402 if (p.muted_) { | 384 if (p.muted_) { |
403 p.audio_source_->SetIsMixed(false); | 385 p.audio_source_->SetIsMixed(false); |
404 continue; | 386 continue; |
405 } | 387 } |
406 | 388 |
407 // Add frame to result vector for mixing. | 389 // Add frame to result vector for mixing. |
408 bool is_mixed = false; | 390 bool is_mixed = false; |
409 if (max_audio_frame_counter > 0) { | 391 if (max_audio_frame_counter > 0) { |
410 --max_audio_frame_counter; | 392 --max_audio_frame_counter; |
411 result.push_back(p.audio_frame_); | 393 result.push_back(p.audio_frame_); |
412 ramp_list.emplace_back(p.audio_source_, p.audio_frame_, false, -1); | 394 ramp_list.emplace_back(p.audio_source_, p.audio_frame_, false, |
| 395 p.was_mixed_before_, -1); |
413 is_mixed = true; | 396 is_mixed = true; |
414 } | 397 } |
415 p.audio_source_->SetIsMixed(is_mixed); | 398 p.audio_source_->SetIsMixed(is_mixed); |
416 } | 399 } |
417 Ramp(ramp_list); | 400 Ramp(ramp_list); |
418 return result; | 401 return result; |
419 } | 402 } |
420 | 403 |
421 AudioFrameList AudioMixerImpl::GetAnonymousAudio() { | 404 AudioFrameList AudioMixerImpl::GetAnonymousAudio() const { |
422 RTC_DCHECK_RUN_ON(&thread_checker_); | 405 RTC_DCHECK_RUN_ON(&thread_checker_); |
423 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | 406 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
424 "GetAnonymousAudio()"); | 407 "GetAnonymousAudio()"); |
| 408 // The GetAudioFrameWithMuted() callback may result in the audio source being |
| 409 // removed from additionalAudioFramesList_. If that happens it will |
| 410 // invalidate any iterators. Create a copy of the audio sources list such |
| 411 // that the list of participants can be traversed safely. |
425 std::vector<SourceFrame> ramp_list; | 412 std::vector<SourceFrame> ramp_list; |
| 413 MixerAudioSourceList additional_audio_sources_list; |
426 AudioFrameList result; | 414 AudioFrameList result; |
427 for (auto& source_and_status : additional_audio_source_list_) { | 415 additional_audio_sources_list.insert(additional_audio_sources_list.begin(), |
| 416 additional_audio_source_list_.begin(), |
| 417 additional_audio_source_list_.end()); |
| 418 |
| 419 for (const auto& audio_source : additional_audio_sources_list) { |
428 const auto audio_frame_with_info = | 420 const auto audio_frame_with_info = |
429 source_and_status.audio_source()->GetAudioFrameWithMuted( | 421 audio_source->GetAudioFrameWithMuted(id_, OutputFrequency()); |
430 id_, OutputFrequency()); | |
431 const auto ret = audio_frame_with_info.audio_frame_info; | 422 const auto ret = audio_frame_with_info.audio_frame_info; |
432 AudioFrame* audio_frame = audio_frame_with_info.audio_frame; | 423 AudioFrame* audio_frame = audio_frame_with_info.audio_frame; |
433 if (ret == MixerAudioSource::AudioFrameInfo::kError) { | 424 if (ret == MixerAudioSource::AudioFrameInfo::kError) { |
434 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, | 425 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, |
435 "failed to GetAudioFrameWithMuted() from audio_source"); | 426 "failed to GetAudioFrameWithMuted() from audio_source"); |
436 continue; | 427 continue; |
437 } | 428 } |
438 if (ret != MixerAudioSource::AudioFrameInfo::kMuted) { | 429 if (ret != MixerAudioSource::AudioFrameInfo::kMuted) { |
439 result.push_back(audio_frame); | 430 result.push_back(audio_frame); |
440 ramp_list.emplace_back(&source_and_status, audio_frame, false, 0); | 431 ramp_list.emplace_back(audio_source, audio_frame, false, |
441 source_and_status.SetIsMixed(true); | 432 audio_source->IsMixed(), 0); |
| 433 audio_source->SetIsMixed(true); |
442 } | 434 } |
443 } | 435 } |
444 Ramp(ramp_list); | 436 Ramp(ramp_list); |
445 return result; | 437 return result; |
446 } | 438 } |
447 | 439 |
| 440 bool AudioMixerImpl::IsAudioSourceInList( |
| 441 const MixerAudioSource& audio_source, |
| 442 const MixerAudioSourceList& audio_source_list) const { |
| 443 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
| 444 "IsAudioSourceInList(audio_source,audio_source_list)"); |
| 445 return std::find(audio_source_list.begin(), audio_source_list.end(), |
| 446 &audio_source) != audio_source_list.end(); |
| 447 } |
| 448 |
448 bool AudioMixerImpl::AddAudioSourceToList( | 449 bool AudioMixerImpl::AddAudioSourceToList( |
449 MixerAudioSource* audio_source, | 450 MixerAudioSource* audio_source, |
450 MixerAudioSourceList* audio_source_list) const { | 451 MixerAudioSourceList* audio_source_list) const { |
451 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | 452 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
452 "AddAudioSourceToList(audio_source, audio_source_list)"); | 453 "AddAudioSourceToList(audio_source, audio_source_list)"); |
453 audio_source_list->emplace_back(audio_source); | 454 audio_source_list->push_back(audio_source); |
| 455 // Make sure that the mixed status is correct for new MixerAudioSource. |
| 456 audio_source->ResetMixedStatus(); |
454 return true; | 457 return true; |
455 } | 458 } |
456 | 459 |
457 bool AudioMixerImpl::RemoveAudioSourceFromList( | 460 bool AudioMixerImpl::RemoveAudioSourceFromList( |
458 MixerAudioSource* audio_source, | 461 MixerAudioSource* audio_source, |
459 MixerAudioSourceList* audio_source_list) const { | 462 MixerAudioSourceList* audio_source_list) const { |
460 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | 463 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
461 "RemoveAudioSourceFromList(audio_source, audio_source_list)"); | 464 "RemoveAudioSourceFromList(audio_source, audio_source_list)"); |
462 const auto iter = FindSourceInList(audio_source, audio_source_list); | 465 const auto iter = std::find(audio_source_list->begin(), |
| 466 audio_source_list->end(), audio_source); |
463 if (iter != audio_source_list->end()) { | 467 if (iter != audio_source_list->end()) { |
464 audio_source_list->erase(iter); | 468 audio_source_list->erase(iter); |
| 469 // AudioSource is no longer mixed, reset to default. |
| 470 audio_source->ResetMixedStatus(); |
465 return true; | 471 return true; |
466 } else { | 472 } else { |
467 return false; | 473 return false; |
468 } | 474 } |
469 } | 475 } |
470 | 476 |
471 bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixed_audio) const { | 477 bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixed_audio) const { |
472 RTC_DCHECK_RUN_ON(&thread_checker_); | 478 RTC_DCHECK_RUN_ON(&thread_checker_); |
473 if (!use_limiter_) { | 479 if (!use_limiter_) { |
474 return true; | 480 return true; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 return level; | 512 return level; |
507 } | 513 } |
508 | 514 |
509 int AudioMixerImpl::GetOutputAudioLevelFullRange() { | 515 int AudioMixerImpl::GetOutputAudioLevelFullRange() { |
510 RTC_DCHECK_RUN_ON(&thread_checker_); | 516 RTC_DCHECK_RUN_ON(&thread_checker_); |
511 const int level = audio_level_.LevelFullRange(); | 517 const int level = audio_level_.LevelFullRange(); |
512 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, | 518 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, |
513 "GetAudioOutputLevelFullRange() => level=%d", level); | 519 "GetAudioOutputLevelFullRange() => level=%d", level); |
514 return level; | 520 return level; |
515 } | 521 } |
516 | |
517 bool AudioMixerImpl::GetAudioSourceMixabilityStatusForTest( | |
518 MixerAudioSource* audio_source) { | |
519 RTC_DCHECK_RUN_ON(&thread_checker_); | |
520 rtc::CritScope lock(&crit_); | |
521 | |
522 const auto non_anonymous_iter = | |
523 FindSourceInList(audio_source, &audio_source_list_); | |
524 if (non_anonymous_iter != audio_source_list_.end()) { | |
525 return non_anonymous_iter->IsMixed(); | |
526 } | |
527 | |
528 const auto anonymous_iter = | |
529 FindSourceInList(audio_source, &additional_audio_source_list_); | |
530 if (anonymous_iter != audio_source_list_.end()) { | |
531 return anonymous_iter->IsMixed(); | |
532 } | |
533 | |
534 LOG_T_F(LS_ERROR) << "Audio source unknown"; | |
535 return false; | |
536 } | |
537 } // namespace webrtc | 522 } // namespace webrtc |
OLD | NEW |