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 | 15 |
| 16 #include "webrtc/base/thread_annotations.h" |
16 #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" | 17 #include "webrtc/modules/audio_mixer/audio_frame_manipulator.h" |
17 #include "webrtc/modules/audio_mixer/audio_mixer_defines.h" | 18 #include "webrtc/modules/audio_mixer/audio_mixer_defines.h" |
18 #include "webrtc/modules/audio_processing/include/audio_processing.h" | 19 #include "webrtc/modules/audio_processing/include/audio_processing.h" |
19 #include "webrtc/modules/utility/include/audio_frame_operations.h" | 20 #include "webrtc/modules/utility/include/audio_frame_operations.h" |
20 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 21 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
21 #include "webrtc/system_wrappers/include/trace.h" | 22 #include "webrtc/system_wrappers/include/trace.h" |
22 | 23 |
23 namespace webrtc { | 24 namespace webrtc { |
24 namespace { | 25 namespace { |
25 | 26 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 thread_checker_.DetachFromThread(); | 141 thread_checker_.DetachFromThread(); |
141 } | 142 } |
142 | 143 |
143 AudioMixerImpl::~AudioMixerImpl() {} | 144 AudioMixerImpl::~AudioMixerImpl() {} |
144 | 145 |
145 bool AudioMixerImpl::Init() { | 146 bool AudioMixerImpl::Init() { |
146 crit_.reset(CriticalSectionWrapper::CreateCriticalSection()); | 147 crit_.reset(CriticalSectionWrapper::CreateCriticalSection()); |
147 if (crit_.get() == NULL) | 148 if (crit_.get() == NULL) |
148 return false; | 149 return false; |
149 | 150 |
150 cb_crit_.reset(CriticalSectionWrapper::CreateCriticalSection()); | |
151 if (cb_crit_.get() == NULL) | |
152 return false; | |
153 | |
154 Config config; | 151 Config config; |
155 config.Set<ExperimentalAgc>(new ExperimentalAgc(false)); | 152 config.Set<ExperimentalAgc>(new ExperimentalAgc(false)); |
156 limiter_.reset(AudioProcessing::Create(config)); | 153 limiter_.reset(AudioProcessing::Create(config)); |
157 if (!limiter_.get()) | 154 if (!limiter_.get()) |
158 return false; | 155 return false; |
159 | 156 |
160 if (SetOutputFrequency(kDefaultFrequency) == -1) | 157 if (SetOutputFrequency(kDefaultFrequency) == -1) |
161 return false; | 158 return false; |
162 | 159 |
163 if (limiter_->gain_control()->set_mode(GainControl::kFixedDigital) != | 160 if (limiter_->gain_control()->set_mode(GainControl::kFixedDigital) != |
(...skipping 17 matching lines...) Expand all Loading... |
181 return false; | 178 return false; |
182 | 179 |
183 return true; | 180 return true; |
184 } | 181 } |
185 | 182 |
186 void AudioMixerImpl::Mix(int sample_rate, | 183 void AudioMixerImpl::Mix(int sample_rate, |
187 size_t number_of_channels, | 184 size_t number_of_channels, |
188 AudioFrame* audio_frame_for_mixing) { | 185 AudioFrame* audio_frame_for_mixing) { |
189 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); | 186 RTC_DCHECK(number_of_channels == 1 || number_of_channels == 2); |
190 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 187 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 188 std::map<int, MixerAudioSource*> mixedAudioSourcesMap; |
| 189 |
| 190 if (sample_rate != kNbInHz && sample_rate != kWbInHz && |
| 191 sample_rate != kSwbInHz && sample_rate != kFbInHz) { |
| 192 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, |
| 193 "Invalid frequency: %d", sample_rate); |
| 194 RTC_NOTREACHED(); |
| 195 return; |
| 196 } |
| 197 |
| 198 if (OutputFrequency() != sample_rate) { |
| 199 SetOutputFrequency(static_cast<Frequency>(sample_rate)); |
| 200 } |
| 201 |
191 AudioFrameList mixList; | 202 AudioFrameList mixList; |
192 AudioFrameList additionalFramesList; | 203 AudioFrameList additionalFramesList; |
193 std::map<int, MixerAudioSource*> mixedAudioSourcesMap; | 204 int num_mixed_audio_sources; |
194 { | 205 { |
195 CriticalSectionScoped cs(cb_crit_.get()); | 206 CriticalSectionScoped cs(crit_.get()); |
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); | 207 mixList = UpdateToMix(kMaximumAmountOfMixedAudioSources); |
221 GetAdditionalAudio(&additionalFramesList); | 208 GetAdditionalAudio(&additionalFramesList); |
| 209 num_mixed_audio_sources = num_mixed_audio_sources_; |
222 } | 210 } |
223 | 211 |
224 for (FrameAndMuteInfo& frame_and_mute : mixList) { | 212 for (FrameAndMuteInfo& frame_and_mute : mixList) { |
225 RemixFrame(frame_and_mute.frame, number_of_channels); | 213 RemixFrame(frame_and_mute.frame, number_of_channels); |
226 } | 214 } |
227 for (FrameAndMuteInfo& frame_and_mute : additionalFramesList) { | 215 for (FrameAndMuteInfo& frame_and_mute : additionalFramesList) { |
228 RemixFrame(frame_and_mute.frame, number_of_channels); | 216 RemixFrame(frame_and_mute.frame, number_of_channels); |
229 } | 217 } |
230 | 218 |
231 audio_frame_for_mixing->UpdateFrame( | 219 audio_frame_for_mixing->UpdateFrame( |
232 -1, time_stamp_, NULL, 0, output_frequency_, AudioFrame::kNormalSpeech, | 220 -1, time_stamp_, NULL, 0, output_frequency_, AudioFrame::kNormalSpeech, |
233 AudioFrame::kVadPassive, number_of_channels); | 221 AudioFrame::kVadPassive, number_of_channels); |
234 | 222 |
235 time_stamp_ += static_cast<uint32_t>(sample_size_); | 223 time_stamp_ += static_cast<uint32_t>(sample_size_); |
236 | 224 |
237 use_limiter_ = num_mixed_audio_sources_ > 1; | 225 use_limiter_ = num_mixed_audio_sources > 1; |
238 | 226 |
239 // We only use the limiter if it supports the output sample rate and | 227 // We only use the limiter if it supports the output sample rate and |
240 // we're actually mixing multiple streams. | 228 // we're actually mixing multiple streams. |
241 MixFromList(audio_frame_for_mixing, mixList, id_, use_limiter_); | 229 MixFromList(audio_frame_for_mixing, mixList, id_, use_limiter_); |
242 | 230 MixAnonomouslyFromList(audio_frame_for_mixing, additionalFramesList); |
243 { | 231 if (audio_frame_for_mixing->samples_per_channel_ == 0) { |
244 CriticalSectionScoped cs(crit_.get()); | 232 // Nothing was mixed, set the audio samples to silence. |
245 MixAnonomouslyFromList(audio_frame_for_mixing, additionalFramesList); | 233 audio_frame_for_mixing->samples_per_channel_ = sample_size_; |
246 | 234 audio_frame_for_mixing->Mute(); |
247 if (audio_frame_for_mixing->samples_per_channel_ == 0) { | 235 } else { |
248 // Nothing was mixed, set the audio samples to silence. | 236 // Only call the limiter if we have something to mix. |
249 audio_frame_for_mixing->samples_per_channel_ = sample_size_; | 237 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 } | 238 } |
256 | 239 |
257 // Pass the final result to the level indicator. | 240 // Pass the final result to the level indicator. |
258 audio_level_.ComputeLevel(*audio_frame_for_mixing); | 241 audio_level_.ComputeLevel(*audio_frame_for_mixing); |
259 | 242 |
260 return; | 243 return; |
261 } | 244 } |
262 | 245 |
263 int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) { | 246 int32_t AudioMixerImpl::SetOutputFrequency(const Frequency& frequency) { |
264 CriticalSectionScoped cs(crit_.get()); | 247 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
265 | |
266 output_frequency_ = frequency; | 248 output_frequency_ = frequency; |
267 sample_size_ = | 249 sample_size_ = |
268 static_cast<size_t>((output_frequency_ * kFrameDurationInMs) / 1000); | 250 static_cast<size_t>((output_frequency_ * kFrameDurationInMs) / 1000); |
269 | 251 |
270 return 0; | 252 return 0; |
271 } | 253 } |
272 | 254 |
273 AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const { | 255 AudioMixer::Frequency AudioMixerImpl::OutputFrequency() const { |
274 CriticalSectionScoped cs(crit_.get()); | 256 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
275 return output_frequency_; | 257 return output_frequency_; |
276 } | 258 } |
277 | 259 |
278 int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source, | 260 int32_t AudioMixerImpl::SetMixabilityStatus(MixerAudioSource* audio_source, |
279 bool mixable) { | 261 bool mixable) { |
280 if (!mixable) { | 262 if (!mixable) { |
281 // 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 |
282 // audio source is in the _audioSourceList if it is being mixed. | 264 // audio source is in the _audioSourceList if it is being mixed. |
283 SetAnonymousMixabilityStatus(audio_source, false); | 265 SetAnonymousMixabilityStatus(audio_source, false); |
284 } | 266 } |
285 size_t numMixedAudioSources; | |
286 { | 267 { |
287 CriticalSectionScoped cs(cb_crit_.get()); | 268 CriticalSectionScoped cs(crit_.get()); |
288 const bool isMixed = IsAudioSourceInList(*audio_source, audio_source_list_); | 269 const bool isMixed = IsAudioSourceInList(*audio_source, audio_source_list_); |
289 // API must be called with a new state. | 270 // API must be called with a new state. |
290 if (!(mixable ^ isMixed)) { | 271 if (!(mixable ^ isMixed)) { |
291 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, | 272 WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, id_, |
292 "Mixable is aready %s", isMixed ? "ON" : "off"); | 273 "Mixable is aready %s", isMixed ? "ON" : "off"); |
293 return -1; | 274 return -1; |
294 } | 275 } |
295 bool success = false; | 276 bool success = false; |
296 if (mixable) { | 277 if (mixable) { |
297 success = AddAudioSourceToList(audio_source, &audio_source_list_); | 278 success = AddAudioSourceToList(audio_source, &audio_source_list_); |
298 } else { | 279 } else { |
299 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_); | 280 success = RemoveAudioSourceFromList(audio_source, &audio_source_list_); |
300 } | 281 } |
301 if (!success) { | 282 if (!success) { |
302 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | 283 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, |
303 "failed to %s audio_source", mixable ? "add" : "remove"); | 284 "failed to %s audio_source", mixable ? "add" : "remove"); |
304 RTC_NOTREACHED(); | 285 RTC_NOTREACHED(); |
305 return -1; | 286 return -1; |
306 } | 287 } |
307 | 288 |
308 size_t numMixedNonAnonymous = audio_source_list_.size(); | 289 size_t numMixedNonAnonymous = audio_source_list_.size(); |
309 if (numMixedNonAnonymous > kMaximumAmountOfMixedAudioSources) { | 290 if (numMixedNonAnonymous > kMaximumAmountOfMixedAudioSources) { |
310 numMixedNonAnonymous = kMaximumAmountOfMixedAudioSources; | 291 numMixedNonAnonymous = kMaximumAmountOfMixedAudioSources; |
311 } | 292 } |
312 numMixedAudioSources = | 293 num_mixed_audio_sources_ = |
313 numMixedNonAnonymous + additional_audio_source_list_.size(); | 294 numMixedNonAnonymous + additional_audio_source_list_.size(); |
314 } | 295 } |
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; | 296 return 0; |
321 } | 297 } |
322 | 298 |
323 bool AudioMixerImpl::MixabilityStatus( | 299 bool AudioMixerImpl::MixabilityStatus( |
324 const MixerAudioSource& audio_source) const { | 300 const MixerAudioSource& audio_source) const { |
325 CriticalSectionScoped cs(cb_crit_.get()); | 301 CriticalSectionScoped cs(crit_.get()); |
326 return IsAudioSourceInList(audio_source, audio_source_list_); | 302 return IsAudioSourceInList(audio_source, audio_source_list_); |
327 } | 303 } |
328 | 304 |
329 int32_t AudioMixerImpl::SetAnonymousMixabilityStatus( | 305 int32_t AudioMixerImpl::SetAnonymousMixabilityStatus( |
330 MixerAudioSource* audio_source, | 306 MixerAudioSource* audio_source, |
331 bool anonymous) { | 307 bool anonymous) { |
332 CriticalSectionScoped cs(cb_crit_.get()); | 308 CriticalSectionScoped cs(crit_.get()); |
333 if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) { | 309 if (IsAudioSourceInList(*audio_source, additional_audio_source_list_)) { |
334 if (anonymous) { | 310 if (anonymous) { |
335 return 0; | 311 return 0; |
336 } | 312 } |
337 if (!RemoveAudioSourceFromList(audio_source, | 313 if (!RemoveAudioSourceFromList(audio_source, |
338 &additional_audio_source_list_)) { | 314 &additional_audio_source_list_)) { |
339 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, | 315 WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, id_, |
340 "unable to remove audio_source from anonymous list"); | 316 "unable to remove audio_source from anonymous list"); |
341 RTC_NOTREACHED(); | 317 RTC_NOTREACHED(); |
342 return -1; | 318 return -1; |
(...skipping 13 matching lines...) Expand all Loading... |
356 // already registered. | 332 // already registered. |
357 return -1; | 333 return -1; |
358 } | 334 } |
359 return AddAudioSourceToList(audio_source, &additional_audio_source_list_) | 335 return AddAudioSourceToList(audio_source, &additional_audio_source_list_) |
360 ? 0 | 336 ? 0 |
361 : -1; | 337 : -1; |
362 } | 338 } |
363 | 339 |
364 bool AudioMixerImpl::AnonymousMixabilityStatus( | 340 bool AudioMixerImpl::AnonymousMixabilityStatus( |
365 const MixerAudioSource& audio_source) const { | 341 const MixerAudioSource& audio_source) const { |
366 CriticalSectionScoped cs(cb_crit_.get()); | 342 CriticalSectionScoped cs(crit_.get()); |
367 return IsAudioSourceInList(audio_source, additional_audio_source_list_); | 343 return IsAudioSourceInList(audio_source, additional_audio_source_list_); |
368 } | 344 } |
369 | 345 |
370 AudioFrameList AudioMixerImpl::UpdateToMix(size_t maxAudioFrameCounter) const { | 346 AudioFrameList AudioMixerImpl::UpdateToMix(size_t maxAudioFrameCounter) const { |
371 AudioFrameList result; | 347 AudioFrameList result; |
372 std::vector<SourceFrame> audioSourceMixingDataList; | 348 std::vector<SourceFrame> audioSourceMixingDataList; |
373 | 349 |
374 // Get audio source audio and put it in the struct vector. | 350 // Get audio source audio and put it in the struct vector. |
375 for (MixerAudioSource* audio_source : audio_source_list_) { | 351 for (MixerAudioSource* audio_source : audio_source_list_) { |
376 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( | 352 auto audio_frame_with_info = audio_source->GetAudioFrameWithMuted( |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
584 return level; | 560 return level; |
585 } | 561 } |
586 | 562 |
587 int AudioMixerImpl::GetOutputAudioLevelFullRange() { | 563 int AudioMixerImpl::GetOutputAudioLevelFullRange() { |
588 const int level = audio_level_.LevelFullRange(); | 564 const int level = audio_level_.LevelFullRange(); |
589 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, | 565 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioMixerServer, id_, |
590 "GetAudioOutputLevelFullRange() => level=%d", level); | 566 "GetAudioOutputLevelFullRange() => level=%d", level); |
591 return level; | 567 return level; |
592 } | 568 } |
593 } // namespace webrtc | 569 } // namespace webrtc |
OLD | NEW |