/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_mixer/audio_mixer_impl.h" #include #include #include #include #include #include "modules/audio_mixer/audio_frame_manipulator.h" #include "modules/audio_mixer/default_output_rate_calculator.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/trace_event.h" #include "system_wrappers/include/metrics.h" namespace webrtc { struct AudioMixerImpl::SourceStatus { explicit SourceStatus(Source* audio_source) : audio_source(audio_source) {} Source* audio_source = nullptr; // A frame that will be passed to audio_source->GetAudioFrameWithInfo. AudioFrame audio_frame; }; namespace { std::vector>::const_iterator FindSourceInList( AudioMixerImpl::Source const* audio_source, std::vector> const* audio_source_list) { return std::find_if( audio_source_list->begin(), audio_source_list->end(), [audio_source](const std::unique_ptr& p) { return p->audio_source == audio_source; }); } } // namespace struct AudioMixerImpl::HelperContainers { void resize(size_t size) { audio_to_mix.resize(size); preferred_rates.resize(size); } std::vector audio_to_mix; std::vector preferred_rates; }; AudioMixerImpl::AudioMixerImpl( std::unique_ptr output_rate_calculator, bool use_limiter) : output_rate_calculator_(std::move(output_rate_calculator)), audio_source_list_(), helper_containers_(std::make_unique()), frame_combiner_(use_limiter) {} AudioMixerImpl::~AudioMixerImpl() {} rtc::scoped_refptr AudioMixerImpl::Create() { return Create(std::unique_ptr( new DefaultOutputRateCalculator()), /*use_limiter=*/true); } rtc::scoped_refptr AudioMixerImpl::Create( std::unique_ptr output_rate_calculator, bool use_limiter) { return rtc::make_ref_counted( std::move(output_rate_calculator), use_limiter); } void AudioMixerImpl::Mix(size_t number_of_channels, AudioFrame* audio_frame_for_mixing) { TRACE_EVENT0("webrtc", "AudioMixerImpl::Mix"); RTC_DCHECK(number_of_channels >= 1); MutexLock lock(&mutex_); size_t number_of_streams = audio_source_list_.size(); std::transform(audio_source_list_.begin(), audio_source_list_.end(), helper_containers_->preferred_rates.begin(), [&](std::unique_ptr& a) { return a->audio_source->PreferredSampleRate(); }); int output_frequency = output_rate_calculator_->CalculateOutputRateFromRange( rtc::ArrayView(helper_containers_->preferred_rates.data(), number_of_streams)); frame_combiner_.Combine(GetAudioFromSources(output_frequency), number_of_channels, output_frequency, number_of_streams, audio_frame_for_mixing); } bool AudioMixerImpl::AddSource(Source* audio_source) { RTC_DCHECK(audio_source); MutexLock lock(&mutex_); RTC_DCHECK(FindSourceInList(audio_source, &audio_source_list_) == audio_source_list_.end()) << "Source already added to mixer"; audio_source_list_.emplace_back(new SourceStatus(audio_source)); helper_containers_->resize(audio_source_list_.size()); UpdateSourceCountStats(); return true; } void AudioMixerImpl::RemoveSource(Source* audio_source) { RTC_DCHECK(audio_source); MutexLock lock(&mutex_); const auto iter = FindSourceInList(audio_source, &audio_source_list_); RTC_DCHECK(iter != audio_source_list_.end()) << "Source not present in mixer"; audio_source_list_.erase(iter); } rtc::ArrayView AudioMixerImpl::GetAudioFromSources( int output_frequency) { int audio_to_mix_count = 0; for (auto& source_and_status : audio_source_list_) { const auto audio_frame_info = source_and_status->audio_source->GetAudioFrameWithInfo( output_frequency, &source_and_status->audio_frame); switch (audio_frame_info) { case Source::AudioFrameInfo::kError: RTC_LOG_F(LS_WARNING) << "failed to GetAudioFrameWithInfo() from source"; break; case Source::AudioFrameInfo::kMuted: break; case Source::AudioFrameInfo::kNormal: helper_containers_->audio_to_mix[audio_to_mix_count++] = &source_and_status->audio_frame; } } return rtc::ArrayView( helper_containers_->audio_to_mix.data(), audio_to_mix_count); } void AudioMixerImpl::UpdateSourceCountStats() { size_t current_source_count = audio_source_list_.size(); // Log to the histogram whenever the maximum number of sources increases. if (current_source_count > max_source_count_ever_) { RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.AudioMixer.NewHighestSourceCount", current_source_count, 1, 20, 20); max_source_count_ever_ = current_source_count; } } } // namespace webrtc