Index: webrtc/modules/audio_mixer/audio_mixer_impl.cc |
diff --git a/webrtc/modules/audio_mixer/audio_mixer_impl.cc b/webrtc/modules/audio_mixer/audio_mixer_impl.cc |
index 93b78bd4c34947ec91a514097384e4644e0a6402..ee78eef2a13a9767b0d47651834c24a7eb0a9660 100644 |
--- a/webrtc/modules/audio_mixer/audio_mixer_impl.cc |
+++ b/webrtc/modules/audio_mixer/audio_mixer_impl.cc |
@@ -37,6 +37,17 @@ class SourceFrame { |
} |
} |
+ SourceFrame(MixerAudioSource* p, |
+ AudioFrame* a, |
+ bool m, |
+ bool was_mixed_before, |
+ uint32_t energy) |
+ : audio_source_(p), |
+ audio_frame_(a), |
+ muted_(m), |
+ energy_(energy), |
+ was_mixed_before_(was_mixed_before) {} |
+ |
// a.shouldMixBefore(b) is used to select mixer participants. |
bool shouldMixBefore(const SourceFrame& other) const { |
if (muted_ != other.muted_) { |
@@ -70,20 +81,19 @@ void RemixFrame(AudioFrame* frame, size_t number_of_channels) { |
} |
} |
-// Mix |frame| into |mixed_frame|, with saturation protection and upmixing. |
-// These effects are applied to |frame| itself prior to mixing. Assumes that |
-// |mixed_frame| always has at least as many channels as |frame|. Supports |
-// stereo at most. |
-// |
-void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) { |
- RTC_DCHECK_GE(mixed_frame->num_channels_, frame->num_channels_); |
- if (use_limiter) { |
- // Divide by two to avoid saturation in the mixing. |
- // This is only meaningful if the limiter will be used. |
- *frame >>= 1; |
+void Ramp(const std::vector<SourceFrame>& mixed_sources_and_frames) { |
+ for (const auto& source_frame : mixed_sources_and_frames) { |
+ // Ramp in previously unmixed. |
+ if (!source_frame.was_mixed_before_) { |
+ NewMixerRampIn(source_frame.audio_frame_); |
+ } |
+ |
+ const bool is_mixed = source_frame.audio_source_->_mixHistory->IsMixed(); |
+ // Ramp out currently unmixed. |
+ if (source_frame.was_mixed_before_ && !is_mixed) { |
+ NewMixerRampOut(source_frame.audio_frame_); |
+ } |
} |
- RTC_DCHECK_EQ(frame->num_channels_, mixed_frame->num_channels_); |
- *mixed_frame += *frame; |
} |
} // namespace |
@@ -188,21 +198,21 @@ void AudioMixerImpl::Mix(int sample_rate, |
SetOutputFrequency(static_cast<Frequency>(sample_rate)); |
} |
- AudioFrameList mixList; |
- AudioFrameList additionalFramesList; |
+ AudioFrameList mix_list; |
+ AudioFrameList anonymous_mix_list; |
int num_mixed_audio_sources; |
{ |
rtc::CritScope lock(&crit_); |
- mixList = UpdateToMix(kMaximumAmountOfMixedAudioSources); |
- GetAdditionalAudio(&additionalFramesList); |
+ mix_list = GetNonAnonymousAudio(); |
+ anonymous_mix_list = GetAnonymousAudio(); |
num_mixed_audio_sources = static_cast<int>(num_mixed_audio_sources_); |
} |
- for (FrameAndMuteInfo& frame_and_mute : mixList) { |
- RemixFrame(frame_and_mute.frame, number_of_channels); |
- } |
- for (FrameAndMuteInfo& frame_and_mute : additionalFramesList) { |
- RemixFrame(frame_and_mute.frame, number_of_channels); |
+ mix_list.insert(mix_list.begin(), anonymous_mix_list.begin(), |
+ anonymous_mix_list.end()); |
+ |
+ for (const auto& frame : mix_list) { |
+ RemixFrame(frame, number_of_channels); |
} |
audio_frame_for_mixing->UpdateFrame( |
@@ -213,10 +223,9 @@ void AudioMixerImpl::Mix(int sample_rate, |
use_limiter_ = num_mixed_audio_sources > 1; |
- // We only use the limiter if it supports the output sample rate and |
- // we're actually mixing multiple streams. |
- MixFromList(audio_frame_for_mixing, mixList, id_, use_limiter_); |
- MixAnonomouslyFromList(audio_frame_for_mixing, additionalFramesList); |
+ // We only use the limiter if we're actually mixing multiple streams. |
+ MixFromList(audio_frame_for_mixing, mix_list, id_, use_limiter_); |
+ |
if (audio_frame_for_mixing->samples_per_channel_ == 0) { |
// Nothing was mixed, set the audio samples to silence. |
audio_frame_for_mixing->samples_per_channel_ = sample_size_; |
@@ -332,10 +341,13 @@ bool AudioMixerImpl::AnonymousMixabilityStatus( |
return IsAudioSourceInList(audio_source, additional_audio_source_list_); |
} |
-AudioFrameList AudioMixerImpl::UpdateToMix(size_t maxAudioFrameCounter) const { |
+AudioFrameList AudioMixerImpl::GetNonAnonymousAudio() const { |
RTC_DCHECK_RUN_ON(&thread_checker_); |
+ WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
+ "GetNonAnonymousAudio()"); |
AudioFrameList result; |
std::vector<SourceFrame> audioSourceMixingDataList; |
+ std::vector<SourceFrame> ramp_list; |
// Get audio source audio and put it in the struct vector. |
for (MixerAudioSource* audio_source : audio_source_list_) { |
@@ -360,6 +372,7 @@ AudioFrameList AudioMixerImpl::UpdateToMix(size_t maxAudioFrameCounter) const { |
std::sort(audioSourceMixingDataList.begin(), audioSourceMixingDataList.end(), |
std::mem_fn(&SourceFrame::shouldMixBefore)); |
+ int maxAudioFrameCounter = kMaximumAmountOfMixedAudioSources; |
// Go through list in order and put things in mixList. |
for (SourceFrame& p : audioSourceMixingDataList) { |
// Filter muted. |
@@ -372,34 +385,28 @@ AudioFrameList AudioMixerImpl::UpdateToMix(size_t maxAudioFrameCounter) const { |
bool is_mixed = false; |
if (maxAudioFrameCounter > 0) { |
--maxAudioFrameCounter; |
- if (!p.was_mixed_before_) { |
- NewMixerRampIn(p.audio_frame_); |
- } |
- result.emplace_back(p.audio_frame_, false); |
+ result.push_back(p.audio_frame_); |
+ ramp_list.emplace_back(p.audio_source_, p.audio_frame_, false, |
+ p.was_mixed_before_, -1); |
is_mixed = true; |
} |
- |
- // Ramp out unmuted. |
- if (p.was_mixed_before_ && !is_mixed) { |
- NewMixerRampOut(p.audio_frame_); |
- result.emplace_back(p.audio_frame_, false); |
- } |
- |
p.audio_source_->_mixHistory->SetIsMixed(is_mixed); |
} |
+ Ramp(ramp_list); |
return result; |
} |
-void AudioMixerImpl::GetAdditionalAudio( |
- AudioFrameList* additionalFramesList) const { |
+AudioFrameList AudioMixerImpl::GetAnonymousAudio() const { |
RTC_DCHECK_RUN_ON(&thread_checker_); |
WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
- "GetAdditionalAudio(additionalFramesList)"); |
+ "GetAnonymousAudio()"); |
// The GetAudioFrameWithMuted() callback may result in the audio source being |
// removed from additionalAudioFramesList_. If that happens it will |
// invalidate any iterators. Create a copy of the audio sources list such |
// that the list of participants can be traversed safely. |
+ std::vector<SourceFrame> ramp_list; |
MixerAudioSourceList additionalAudioSourceList; |
+ AudioFrameList result; |
additionalAudioSourceList.insert(additionalAudioSourceList.begin(), |
additional_audio_source_list_.begin(), |
additional_audio_source_list_.end()); |
@@ -416,13 +423,15 @@ void AudioMixerImpl::GetAdditionalAudio( |
"failed to GetAudioFrameWithMuted() from audio_source"); |
continue; |
} |
- if (audio_frame->samples_per_channel_ == 0) { |
- // Empty frame. Don't use it. |
- continue; |
+ if (ret != MixerAudioSource::AudioFrameInfo::kMuted) { |
+ result.push_back(audio_frame); |
+ ramp_list.emplace_back(*audio_source, audio_frame, false, |
+ (*audio_source)->_mixHistory->IsMixed(), -1); |
+ (*audio_source)->_mixHistory->SetIsMixed(true); |
} |
- additionalFramesList->push_back(FrameAndMuteInfo( |
- audio_frame, ret == MixerAudioSource::AudioFrameInfo::kMuted)); |
} |
+ Ramp(ramp_list); |
+ return result; |
} |
bool AudioMixerImpl::IsAudioSourceInList( |
@@ -474,9 +483,8 @@ int32_t AudioMixerImpl::MixFromList(AudioFrame* mixedAudio, |
uint32_t position = 0; |
if (audioFrameList.size() == 1) { |
- mixedAudio->timestamp_ = audioFrameList.front().frame->timestamp_; |
- mixedAudio->elapsed_time_ms_ = |
- audioFrameList.front().frame->elapsed_time_ms_; |
+ mixedAudio->timestamp_ = audioFrameList.front()->timestamp_; |
+ mixedAudio->elapsed_time_ms_ = audioFrameList.front()->elapsed_time_ms_; |
} else { |
// TODO(wu): Issue 3390. |
// Audio frame timestamp is only supported in one channel case. |
@@ -484,35 +492,24 @@ int32_t AudioMixerImpl::MixFromList(AudioFrame* mixedAudio, |
mixedAudio->elapsed_time_ms_ = -1; |
} |
- for (AudioFrameList::const_iterator iter = audioFrameList.begin(); |
- iter != audioFrameList.end(); ++iter) { |
- if (!iter->muted) { |
- MixFrames(mixedAudio, iter->frame, use_limiter); |
+ for (const auto& frame : audioFrameList) { |
+ RTC_DCHECK_EQ(mixedAudio->sample_rate_hz_, frame->sample_rate_hz_); |
+ RTC_DCHECK_EQ( |
+ frame->samples_per_channel_, |
+ static_cast<size_t>((mixedAudio->sample_rate_hz_ * kFrameDurationInMs) / |
+ 1000)); |
+ |
+ // Mix |f.frame| into |mixedAudio|, with saturation protection. |
+ // These effect is applied to |f.frame| itself prior to mixing. |
+ if (use_limiter) { |
+ // Divide by two to avoid saturation in the mixing. |
+ // This is only meaningful if the limiter will be used. |
+ *frame >>= 1; |
} |
- |
+ RTC_DCHECK_EQ(frame->num_channels_, mixedAudio->num_channels_); |
+ *mixedAudio += *frame; |
position++; |
} |
- |
- return 0; |
-} |
- |
-// TODO(andrew): consolidate this function with MixFromList. |
-int32_t AudioMixerImpl::MixAnonomouslyFromList( |
- AudioFrame* mixedAudio, |
- const AudioFrameList& audioFrameList) const { |
- RTC_DCHECK_RUN_ON(&thread_checker_); |
- WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, id_, |
- "MixAnonomouslyFromList(mixedAudio, audioFrameList)"); |
- |
- if (audioFrameList.empty()) |
- return 0; |
- |
- for (AudioFrameList::const_iterator iter = audioFrameList.begin(); |
- iter != audioFrameList.end(); ++iter) { |
- if (!iter->muted) { |
- MixFrames(mixedAudio, iter->frame, use_limiter_); |
- } |
- } |
return 0; |
} |