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" | 17 #include "webrtc/base/logging.h" |
18 #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" | 18 #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" |
19 #include "webrtc/modules/utility/include/audio_frame_operations.h" | 19 #include "webrtc/modules/utility/include/audio_frame_operations.h" |
20 #include "webrtc/system_wrappers/include/trace.h" | |
21 | 20 |
22 namespace webrtc { | 21 namespace webrtc { |
23 namespace { | 22 namespace { |
24 | 23 |
25 struct SourceFrame { | 24 struct SourceFrame { |
26 SourceFrame(AudioMixerImpl::SourceStatus* source_status, | 25 SourceFrame(AudioMixerImpl::SourceStatus* source_status, |
27 AudioFrame* audio_frame, | 26 AudioFrame* audio_frame, |
28 bool muted) | 27 bool muted) |
29 : source_status(source_status), audio_frame(audio_frame), muted(muted) { | 28 : source_status(source_status), audio_frame(audio_frame), muted(muted) { |
30 RTC_DCHECK(source_status); | 29 RTC_DCHECK(source_status); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 float target_gain = source_frame.source_status->is_mixed ? 1.0f : 0.0f; | 73 float target_gain = source_frame.source_status->is_mixed ? 1.0f : 0.0f; |
75 Ramp(source_frame.source_status->gain, target_gain, | 74 Ramp(source_frame.source_status->gain, target_gain, |
76 source_frame.audio_frame); | 75 source_frame.audio_frame); |
77 source_frame.source_status->gain = target_gain; | 76 source_frame.source_status->gain = target_gain; |
78 } | 77 } |
79 } | 78 } |
80 | 79 |
81 // Mix the AudioFrames stored in audioFrameList into mixed_audio. | 80 // Mix the AudioFrames stored in audioFrameList into mixed_audio. |
82 int32_t MixFromList(AudioFrame* mixed_audio, | 81 int32_t MixFromList(AudioFrame* mixed_audio, |
83 const AudioFrameList& audio_frame_list, | 82 const AudioFrameList& audio_frame_list, |
84 int32_t id, | |
85 bool use_limiter) { | 83 bool use_limiter) { |
86 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id, | 84 if (audio_frame_list.empty()) { |
87 "MixFromList(mixed_audio, audio_frame_list)"); | |
88 if (audio_frame_list.empty()) | |
89 return 0; | 85 return 0; |
| 86 } |
90 | 87 |
91 if (audio_frame_list.size() == 1) { | 88 if (audio_frame_list.size() == 1) { |
92 mixed_audio->timestamp_ = audio_frame_list.front()->timestamp_; | 89 mixed_audio->timestamp_ = audio_frame_list.front()->timestamp_; |
93 mixed_audio->elapsed_time_ms_ = audio_frame_list.front()->elapsed_time_ms_; | 90 mixed_audio->elapsed_time_ms_ = audio_frame_list.front()->elapsed_time_ms_; |
94 } else { | 91 } else { |
95 // TODO(wu): Issue 3390. | 92 // TODO(wu): Issue 3390. |
96 // Audio frame timestamp is only supported in one channel case. | 93 // Audio frame timestamp is only supported in one channel case. |
97 mixed_audio->timestamp_ = 0; | 94 mixed_audio->timestamp_ = 0; |
98 mixed_audio->elapsed_time_ms_ = -1; | 95 mixed_audio->elapsed_time_ms_ = -1; |
99 } | 96 } |
(...skipping 21 matching lines...) Expand all Loading... |
121 | 118 |
122 AudioMixerImpl::SourceStatusList::const_iterator FindSourceInList( | 119 AudioMixerImpl::SourceStatusList::const_iterator FindSourceInList( |
123 AudioMixerImpl::Source const* audio_source, | 120 AudioMixerImpl::Source const* audio_source, |
124 AudioMixerImpl::SourceStatusList const* audio_source_list) { | 121 AudioMixerImpl::SourceStatusList const* audio_source_list) { |
125 return std::find_if(audio_source_list->begin(), audio_source_list->end(), | 122 return std::find_if(audio_source_list->begin(), audio_source_list->end(), |
126 [audio_source](const AudioMixerImpl::SourceStatus& p) { | 123 [audio_source](const AudioMixerImpl::SourceStatus& p) { |
127 return p.audio_source == audio_source; | 124 return p.audio_source == audio_source; |
128 }); | 125 }); |
129 } | 126 } |
130 | 127 |
| 128 // TODO(aleloi): remove non-const version when WEBRTC only supports modern STL. |
131 AudioMixerImpl::SourceStatusList::iterator FindSourceInList( | 129 AudioMixerImpl::SourceStatusList::iterator FindSourceInList( |
132 AudioMixerImpl::Source const* audio_source, | 130 AudioMixerImpl::Source const* audio_source, |
133 AudioMixerImpl::SourceStatusList* audio_source_list) { | 131 AudioMixerImpl::SourceStatusList* audio_source_list) { |
134 return std::find_if(audio_source_list->begin(), audio_source_list->end(), | 132 return std::find_if(audio_source_list->begin(), audio_source_list->end(), |
135 [audio_source](const AudioMixerImpl::SourceStatus& p) { | 133 [audio_source](const AudioMixerImpl::SourceStatus& p) { |
136 return p.audio_source == audio_source; | 134 return p.audio_source == audio_source; |
137 }); | 135 }); |
138 } | 136 } |
139 | 137 |
140 } // namespace | 138 } // namespace |
141 | 139 |
142 std::unique_ptr<AudioMixer> AudioMixer::Create(int id) { | 140 std::unique_ptr<AudioMixer> AudioMixer::Create() { |
143 return AudioMixerImpl::Create(id); | 141 return AudioMixerImpl::Create(); |
144 } | 142 } |
145 | 143 |
146 AudioMixerImpl::AudioMixerImpl(int id, std::unique_ptr<AudioProcessing> limiter) | 144 AudioMixerImpl::AudioMixerImpl(std::unique_ptr<AudioProcessing> limiter) |
147 : id_(id), | 145 : audio_source_list_(), |
148 audio_source_list_(), | |
149 additional_audio_source_list_(), | |
150 num_mixed_audio_sources_(0), | 146 num_mixed_audio_sources_(0), |
151 use_limiter_(true), | 147 use_limiter_(true), |
152 time_stamp_(0), | 148 time_stamp_(0), |
153 limiter_(std::move(limiter)) { | 149 limiter_(std::move(limiter)) { |
154 SetOutputFrequency(kDefaultFrequency); | 150 SetOutputFrequency(kDefaultFrequency); |
155 thread_checker_.DetachFromThread(); | 151 thread_checker_.DetachFromThread(); |
156 } | 152 } |
157 | 153 |
158 AudioMixerImpl::~AudioMixerImpl() {} | 154 AudioMixerImpl::~AudioMixerImpl() {} |
159 | 155 |
160 std::unique_ptr<AudioMixerImpl> AudioMixerImpl::Create(int id) { | 156 std::unique_ptr<AudioMixerImpl> AudioMixerImpl::Create() { |
161 Config config; | 157 Config config; |
162 config.Set<ExperimentalAgc>(new ExperimentalAgc(false)); | 158 config.Set<ExperimentalAgc>(new ExperimentalAgc(false)); |
163 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config)); | 159 std::unique_ptr<AudioProcessing> limiter(AudioProcessing::Create(config)); |
164 if (!limiter.get()) | 160 if (!limiter.get()) { |
165 return nullptr; | 161 return nullptr; |
| 162 } |
166 | 163 |
167 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) != | 164 if (limiter->gain_control()->set_mode(GainControl::kFixedDigital) != |
168 limiter->kNoError) | 165 limiter->kNoError) { |
169 return nullptr; | 166 return nullptr; |
| 167 } |
170 | 168 |
171 // We smoothly limit the mixed frame to -7 dbFS. -6 would correspond to the | 169 // 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 | 170 // divide-by-2 but -7 is used instead to give a bit of headroom since the |
173 // AGC is not a hard limiter. | 171 // AGC is not a hard limiter. |
174 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError) | 172 if (limiter->gain_control()->set_target_level_dbfs(7) != limiter->kNoError) { |
175 return nullptr; | 173 return nullptr; |
| 174 } |
176 | 175 |
177 if (limiter->gain_control()->set_compression_gain_db(0) != limiter->kNoError) | 176 if (limiter->gain_control()->set_compression_gain_db(0) != |
| 177 limiter->kNoError) { |
178 return nullptr; | 178 return nullptr; |
| 179 } |
179 | 180 |
180 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError) | 181 if (limiter->gain_control()->enable_limiter(true) != limiter->kNoError) { |
181 return nullptr; | 182 return nullptr; |
| 183 } |
182 | 184 |
183 if (limiter->gain_control()->Enable(true) != limiter->kNoError) | 185 if (limiter->gain_control()->Enable(true) != limiter->kNoError) { |
184 return nullptr; | 186 return nullptr; |
| 187 } |
185 | 188 |
186 return std::unique_ptr<AudioMixerImpl>( | 189 return std::unique_ptr<AudioMixerImpl>( |
187 new AudioMixerImpl(id, std::move(limiter))); | 190 new AudioMixerImpl(std::move(limiter))); |
188 } | 191 } |
189 | 192 |
190 void AudioMixerImpl::Mix(int sample_rate, | 193 void AudioMixerImpl::Mix(int sample_rate, |
191 size_t number_of_channels, | 194 size_t number_of_channels, |
192 AudioFrame* audio_frame_for_mixing) { | 195 AudioFrame* audio_frame_for_mixing) { |
193 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); | 196 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); |
194 RTC_DCHECK_RUN_ON(&thread_checker_); | 197 RTC_DCHECK_RUN_ON(&thread_checker_); |
195 | 198 |
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) { | 199 if (OutputFrequency() != sample_rate) { |
205 SetOutputFrequency(static_cast<Frequency>(sample_rate)); | 200 SetOutputFrequency(sample_rate); |
206 } | 201 } |
207 | 202 |
208 AudioFrameList mix_list; | 203 AudioFrameList mix_list; |
209 AudioFrameList anonymous_mix_list; | |
210 size_t num_mixed_audio_sources; | 204 size_t num_mixed_audio_sources; |
211 { | 205 { |
212 rtc::CritScope lock(&crit_); | 206 rtc::CritScope lock(&crit_); |
213 mix_list = GetNonAnonymousAudio(); | 207 mix_list = GetNonAnonymousAudio(); |
214 anonymous_mix_list = GetAnonymousAudio(); | |
215 num_mixed_audio_sources = num_mixed_audio_sources_; | 208 num_mixed_audio_sources = num_mixed_audio_sources_; |
216 } | 209 } |
217 | 210 |
218 mix_list.insert(mix_list.begin(), anonymous_mix_list.begin(), | |
219 anonymous_mix_list.end()); | |
220 | |
221 for (const auto& frame : mix_list) { | 211 for (const auto& frame : mix_list) { |
222 RemixFrame(number_of_channels, frame); | 212 RemixFrame(number_of_channels, frame); |
223 } | 213 } |
224 | 214 |
225 audio_frame_for_mixing->UpdateFrame( | 215 audio_frame_for_mixing->UpdateFrame( |
226 -1, time_stamp_, NULL, 0, OutputFrequency(), AudioFrame::kNormalSpeech, | 216 -1, time_stamp_, NULL, 0, OutputFrequency(), AudioFrame::kNormalSpeech, |
227 AudioFrame::kVadPassive, number_of_channels); | 217 AudioFrame::kVadPassive, number_of_channels); |
228 | 218 |
229 time_stamp_ += static_cast<uint32_t>(sample_size_); | 219 time_stamp_ += static_cast<uint32_t>(sample_size_); |
230 | 220 |
231 use_limiter_ = num_mixed_audio_sources > 1; | 221 use_limiter_ = num_mixed_audio_sources > 1; |
232 | 222 |
233 // We only use the limiter if we're actually mixing multiple streams. | 223 // We only use the limiter if we're actually mixing multiple streams. |
234 MixFromList(audio_frame_for_mixing, mix_list, id_, use_limiter_); | 224 MixFromList(audio_frame_for_mixing, mix_list, use_limiter_); |
235 | 225 |
236 if (audio_frame_for_mixing->samples_per_channel_ == 0) { | 226 if (audio_frame_for_mixing->samples_per_channel_ == 0) { |
237 // Nothing was mixed, set the audio samples to silence. | 227 // Nothing was mixed, set the audio samples to silence. |
238 audio_frame_for_mixing->samples_per_channel_ = sample_size_; | 228 audio_frame_for_mixing->samples_per_channel_ = sample_size_; |
239 audio_frame_for_mixing->Mute(); | 229 audio_frame_for_mixing->Mute(); |
240 } else { | 230 } else { |
241 // Only call the limiter if we have something to mix. | 231 // Only call the limiter if we have something to mix. |
242 LimitMixedAudio(audio_frame_for_mixing); | 232 LimitMixedAudio(audio_frame_for_mixing); |
243 } | 233 } |
244 | 234 |
245 // Pass the final result to the level indicator. | |
246 audio_level_.ComputeLevel(*audio_frame_for_mixing); | |
247 | |
248 return; | 235 return; |
249 } | 236 } |
250 | 237 |
251 int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) { | 238 void AudioMixerImpl::SetOutputFrequency(int frequency) { |
252 RTC_DCHECK_RUN_ON(&thread_checker_); | 239 RTC_DCHECK_RUN_ON(&thread_checker_); |
253 output_frequency_ = frequency; | 240 output_frequency_ = frequency; |
254 sample_size_ = (output_frequency_ * kFrameDurationInMs) / 1000; | 241 sample_size_ = (output_frequency_ * kFrameDurationInMs) / 1000; |
255 | |
256 return 0; | |
257 } | 242 } |
258 | 243 |
259 AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const { | 244 int AudioMixerImpl::OutputFrequency() const { |
260 RTC_DCHECK_RUN_ON(&thread_checker_); | 245 RTC_DCHECK_RUN_ON(&thread_checker_); |
261 return output_frequency_; | 246 return output_frequency_; |
262 } | 247 } |
263 | 248 |
264 int32_t AudioMixerImpl::SetMixabilityStatus(Source* audio_source, | 249 int32_t AudioMixerImpl::SetMixabilityStatus(Source* audio_source, |
265 bool mixable) { | 250 bool mixable) { |
266 if (!mixable) { | |
267 // 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); | |
270 } | |
271 { | 251 { |
272 rtc::CritScope lock(&crit_); | 252 rtc::CritScope lock(&crit_); |
273 const bool is_mixed = FindSourceInList(audio_source, &audio_source_list_) != | 253 const bool is_mixed = FindSourceInList(audio_source, &audio_source_list_) != |
274 audio_source_list_.end(); | 254 audio_source_list_.end(); |
275 // API must be called with a new state. | 255 // API must be called with a new state. |
276 if (!(mixable ^ is_mixed)) { | 256 if (!(mixable ^ is_mixed)) { |
277 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, | |
278 "Mixable is aready %s", is_mixed ? "ON" : "off"); | |
279 return -1; | 257 return -1; |
280 } | 258 } |
281 bool success = false; | 259 bool success = false; |
282 if (mixable) { | 260 if (mixable) { |
283 success = AddAudioSourceToList(audio_source, &audio_source_list_); | 261 success = AddAudioSourceToList(audio_source, &audio_source_list_); |
284 } else { | 262 } else { |
285 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_); | 263 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_); |
286 } | 264 } |
287 if (!success) { | 265 if (!success) { |
288 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | |
289 "failed to %s audio_source", mixable ? "add" : "remove"); | |
290 RTC_NOTREACHED(); | 266 RTC_NOTREACHED(); |
291 return -1; | 267 return -1; |
292 } | 268 } |
293 | 269 |
294 size_t num_mixed_non_anonymous = audio_source_list_.size(); | 270 size_t num_mixed_non_anonymous = audio_source_list_.size(); |
295 if (num_mixed_non_anonymous > kMaximumAmountOfMixedAudioSources) { | 271 if (num_mixed_non_anonymous > kMaximumAmountOfMixedAudioSources) { |
296 num_mixed_non_anonymous = kMaximumAmountOfMixedAudioSources; | 272 num_mixed_non_anonymous = kMaximumAmountOfMixedAudioSources; |
297 } | 273 } |
298 num_mixed_audio_sources_ = | 274 num_mixed_audio_sources_ = num_mixed_non_anonymous; |
299 num_mixed_non_anonymous + additional_audio_source_list_.size(); | |
300 } | 275 } |
301 return 0; | 276 return 0; |
302 } | 277 } |
303 | 278 |
304 bool AudioMixerImpl::MixabilityStatus(const Source& audio_source) const { | |
305 rtc::CritScope lock(&crit_); | |
306 return FindSourceInList(&audio_source, &audio_source_list_) != | |
307 audio_source_list_.end(); | |
308 } | |
309 | 279 |
310 int32_t AudioMixerImpl::SetAnonymousMixabilityStatus(Source* audio_source, | |
311 bool anonymous) { | |
312 rtc::CritScope lock(&crit_); | |
313 if (FindSourceInList(audio_source, &additional_audio_source_list_) != | |
314 additional_audio_source_list_.end()) { | |
315 if (anonymous) { | |
316 return 0; | |
317 } | |
318 if (!RemoveAudioSourceFromList(audio_source, | |
319 &additional_audio_source_list_)) { | |
320 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | |
321 "unable to remove audio_source from anonymous list"); | |
322 RTC_NOTREACHED(); | |
323 return -1; | |
324 } | |
325 return AddAudioSourceToList(audio_source, &audio_source_list_) ? 0 : -1; | |
326 } | |
327 if (!anonymous) { | |
328 return 0; | |
329 } | |
330 const bool mixable = | |
331 RemoveAudioSourceFromList(audio_source, &audio_source_list_); | |
332 if (!mixable) { | |
333 WEBRTC_TRACE( | |
334 kTraceWarning, kTraceAudioMixerServer, id_, | |
335 "audio_source must be registered before turning it into anonymous"); | |
336 // Setting anonymous status is only possible if MixerAudioSource is | |
337 // already registered. | |
338 return -1; | |
339 } | |
340 return AddAudioSourceToList(audio_source, &additional_audio_source_list_) | |
341 ? 0 | |
342 : -1; | |
343 } | |
344 | |
345 bool AudioMixerImpl::AnonymousMixabilityStatus( | |
346 const Source& audio_source) const { | |
347 rtc::CritScope lock(&crit_); | |
348 return FindSourceInList(&audio_source, &additional_audio_source_list_) != | |
349 additional_audio_source_list_.end(); | |
350 } | |
351 | 280 |
352 AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() { | 281 AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() { |
353 RTC_DCHECK_RUN_ON(&thread_checker_); | 282 RTC_DCHECK_RUN_ON(&thread_checker_); |
354 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | |
355 "GetNonAnonymousAudio()"); | |
356 AudioFrameList result; | 283 AudioFrameList result; |
357 std::vector<SourceFrame> audio_source_mixing_data_list; | 284 std::vector<SourceFrame> audio_source_mixing_data_list; |
358 std::vector<SourceFrame> ramp_list; | 285 std::vector<SourceFrame> ramp_list; |
359 | 286 |
360 // Get audio source audio and put it in the struct vector. | 287 // Get audio source audio and put it in the struct vector. |
361 for (auto& source_and_status : audio_source_list_) { | 288 for (auto& source_and_status : audio_source_list_) { |
362 auto audio_frame_with_info = | 289 auto audio_frame_with_info = |
363 source_and_status.audio_source->GetAudioFrameWithInfo( | 290 source_and_status.audio_source->GetAudioFrameWithInfo( |
364 id_, static_cast<int>(OutputFrequency())); | 291 static_cast<int>(OutputFrequency())); |
365 | 292 |
366 const auto audio_frame_info = audio_frame_with_info.audio_frame_info; | 293 const auto audio_frame_info = audio_frame_with_info.audio_frame_info; |
367 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame; | 294 AudioFrame* audio_source_audio_frame = audio_frame_with_info.audio_frame; |
368 | 295 |
369 if (audio_frame_info == Source::AudioFrameInfo::kError) { | 296 if (audio_frame_info == Source::AudioFrameInfo::kError) { |
370 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, | 297 LOG_F(LS_WARNING) << "failed to GetAudioFrameWithInfo() from source"; |
371 "failed to GetAudioFrameWithMuted() from source"); | |
372 continue; | 298 continue; |
373 } | 299 } |
374 audio_source_mixing_data_list.emplace_back( | 300 audio_source_mixing_data_list.emplace_back( |
375 &source_and_status, audio_source_audio_frame, | 301 &source_and_status, audio_source_audio_frame, |
376 audio_frame_info == Source::AudioFrameInfo::kMuted); | 302 audio_frame_info == Source::AudioFrameInfo::kMuted); |
377 } | 303 } |
378 | 304 |
379 // Sort frames by sorting function. | 305 // Sort frames by sorting function. |
380 std::sort(audio_source_mixing_data_list.begin(), | 306 std::sort(audio_source_mixing_data_list.begin(), |
381 audio_source_mixing_data_list.end(), ShouldMixBefore); | 307 audio_source_mixing_data_list.end(), ShouldMixBefore); |
(...skipping 15 matching lines...) Expand all Loading... |
397 result.push_back(p.audio_frame); | 323 result.push_back(p.audio_frame); |
398 ramp_list.emplace_back(p.source_status, p.audio_frame, false, -1); | 324 ramp_list.emplace_back(p.source_status, p.audio_frame, false, -1); |
399 is_mixed = true; | 325 is_mixed = true; |
400 } | 326 } |
401 p.source_status->is_mixed = is_mixed; | 327 p.source_status->is_mixed = is_mixed; |
402 } | 328 } |
403 RampAndUpdateGain(ramp_list); | 329 RampAndUpdateGain(ramp_list); |
404 return result; | 330 return result; |
405 } | 331 } |
406 | 332 |
407 AudioFrameList AudioMixerImpl::GetAnonymousAudio() { | |
408 RTC_DCHECK_RUN_ON(&thread_checker_); | |
409 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | |
410 "GetAnonymousAudio()"); | |
411 std::vector<SourceFrame> ramp_list; | |
412 AudioFrameList result; | |
413 for (auto& source_and_status : additional_audio_source_list_) { | |
414 const auto audio_frame_with_info = | |
415 source_and_status.audio_source->GetAudioFrameWithInfo( | |
416 id_, OutputFrequency()); | |
417 const auto ret = audio_frame_with_info.audio_frame_info; | |
418 AudioFrame* audio_frame = audio_frame_with_info.audio_frame; | |
419 if (ret == Source::AudioFrameInfo::kError) { | |
420 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, | |
421 "failed to GetAudioFrameWithMuted() from audio_source"); | |
422 continue; | |
423 } | |
424 if (ret != Source::AudioFrameInfo::kMuted) { | |
425 result.push_back(audio_frame); | |
426 ramp_list.emplace_back(&source_and_status, audio_frame, false, 0); | |
427 source_and_status.is_mixed = true; | |
428 } | |
429 } | |
430 RampAndUpdateGain(ramp_list); | |
431 return result; | |
432 } | |
433 | |
434 bool AudioMixerImpl::AddAudioSourceToList( | 333 bool AudioMixerImpl::AddAudioSourceToList( |
435 Source* audio_source, | 334 Source* audio_source, |
436 SourceStatusList* audio_source_list) const { | 335 SourceStatusList* audio_source_list) const { |
437 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | |
438 "AddAudioSourceToList(audio_source, audio_source_list)"); | |
439 audio_source_list->emplace_back(audio_source, false, 0); | 336 audio_source_list->emplace_back(audio_source, false, 0); |
440 return true; | 337 return true; |
441 } | 338 } |
442 | 339 |
443 bool AudioMixerImpl::RemoveAudioSourceFromList( | 340 bool AudioMixerImpl::RemoveAudioSourceFromList( |
444 Source* audio_source, | 341 Source* audio_source, |
445 SourceStatusList* audio_source_list) const { | 342 SourceStatusList* audio_source_list) const { |
446 WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, | |
447 "RemoveAudioSourceFromList(audio_source, audio_source_list)"); | |
448 const auto iter = FindSourceInList(audio_source, audio_source_list); | 343 const auto iter = FindSourceInList(audio_source, audio_source_list); |
449 if (iter != audio_source_list->end()) { | 344 if (iter != audio_source_list->end()) { |
450 audio_source_list->erase(iter); | 345 audio_source_list->erase(iter); |
451 return true; | 346 return true; |
452 } else { | 347 } else { |
453 return false; | 348 return false; |
454 } | 349 } |
455 } | 350 } |
456 | 351 |
457 bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixed_audio) const { | 352 bool AudioMixerImpl::LimitMixedAudio(AudioFrame* mixed_audio) const { |
(...skipping 11 matching lines...) Expand all Loading... |
469 // It's possible to apply the gain in the AGC (with a target level of 0 dbFS | 364 // 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 | 365 // and compression gain of 6 dB). However, in the transition frame when this |
471 // is enabled (moving from one to two audio sources) it has the potential to | 366 // is enabled (moving from one to two audio sources) it has the potential to |
472 // create discontinuities in the mixed frame. | 367 // create discontinuities in the mixed frame. |
473 // | 368 // |
474 // Instead we double the frame (with addition since left-shifting a | 369 // Instead we double the frame (with addition since left-shifting a |
475 // negative value is undefined). | 370 // negative value is undefined). |
476 *mixed_audio += *mixed_audio; | 371 *mixed_audio += *mixed_audio; |
477 | 372 |
478 if (error != limiter_->kNoError) { | 373 if (error != limiter_->kNoError) { |
479 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | 374 LOG_F(LS_ERROR) << "Error from AudioProcessing: " << error; |
480 "Error from AudioProcessing: %d", error); | |
481 RTC_NOTREACHED(); | 375 RTC_NOTREACHED(); |
482 return false; | 376 return false; |
483 } | 377 } |
484 return true; | 378 return true; |
485 } | 379 } |
486 | 380 |
487 int AudioMixerImpl::GetOutputAudioLevel() { | |
488 RTC_DCHECK_RUN_ON(&thread_checker_); | |
489 const int level = audio_level_.Level(); | |
490 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, | |
491 "GetAudioOutputLevel() => level=%d", level); | |
492 return level; | |
493 } | |
494 | |
495 int AudioMixerImpl::GetOutputAudioLevelFullRange() { | |
496 RTC_DCHECK_RUN_ON(&thread_checker_); | |
497 const int level = audio_level_.LevelFullRange(); | |
498 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, | |
499 "GetAudioOutputLevelFullRange() => level=%d", level); | |
500 return level; | |
501 } | |
502 | |
503 bool AudioMixerImpl::GetAudioSourceMixabilityStatusForTest( | 381 bool AudioMixerImpl::GetAudioSourceMixabilityStatusForTest( |
504 AudioMixerImpl::Source* audio_source) { | 382 AudioMixerImpl::Source* audio_source) const { |
505 RTC_DCHECK_RUN_ON(&thread_checker_); | 383 RTC_DCHECK_RUN_ON(&thread_checker_); |
506 rtc::CritScope lock(&crit_); | 384 rtc::CritScope lock(&crit_); |
507 | 385 |
508 const auto non_anonymous_iter = | 386 const auto non_anonymous_iter = |
509 FindSourceInList(audio_source, &audio_source_list_); | 387 FindSourceInList(audio_source, &audio_source_list_); |
510 if (non_anonymous_iter != audio_source_list_.end()) { | 388 if (non_anonymous_iter != audio_source_list_.end()) { |
511 return non_anonymous_iter->is_mixed; | 389 return non_anonymous_iter->is_mixed; |
512 } | 390 } |
513 | 391 |
514 const auto anonymous_iter = | |
515 FindSourceInList(audio_source, &additional_audio_source_list_); | |
516 if (anonymous_iter != audio_source_list_.end()) { | |
517 return anonymous_iter->is_mixed; | |
518 } | |
519 | |
520 LOG(LS_ERROR) << "Audio source unknown"; | 392 LOG(LS_ERROR) << "Audio source unknown"; |
521 return false; | 393 return false; |
522 } | 394 } |
523 } // namespace webrtc | 395 } // namespace webrtc |
OLD | NEW |