Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Unified Diff: chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc

Issue 2722673004: Revert of [Chromecast] Process streams with different post-processing. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
index e0ea0e0696b79c2b233f649b249943cc9b5eec6f..463a300aba2498a5aca63e6438cf046cc7c816c3 100644
--- a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
+++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
@@ -7,26 +7,20 @@
#include <algorithm>
#include <cmath>
#include <limits>
-#include <unordered_set>
#include <utility>
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
-#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
-#include "base/numerics/saturated_arithmetic.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromecast/base/chromecast_switches.h"
-#include "chromecast/media/base/audio_device_ids.h"
#include "chromecast/media/cma/backend/alsa/alsa_wrapper.h"
#include "chromecast/media/cma/backend/alsa/audio_filter_factory.h"
-#include "chromecast/media/cma/backend/alsa/filter_group.h"
#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h"
-#include "media/audio/audio_device_description.h"
#include "media/base/audio_bus.h"
#include "media/base/media_switches.h"
@@ -118,6 +112,9 @@
const snd_pcm_format_t kPreferredSampleFormats[] = {SND_PCM_FORMAT_S32,
SND_PCM_FORMAT_S16};
+// How many seconds of silence should be passed to the filters to flush them.
+const float kSilenceSecondsToFilter = 1.0f;
+
const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min();
int64_t TimespecToMicroseconds(struct timespec time) {
@@ -168,12 +165,6 @@
return false;
}
return true;
-}
-
-void VectorAccumulate(const int32_t* source, size_t size, int32_t* dest) {
- for (size_t i = 0; i < size; ++i) {
- dest[i] = base::SaturatedAddition(source[i], dest[i]);
- }
}
class StreamMixerAlsaInstance : public StreamMixerAlsa {
@@ -254,23 +245,11 @@
? kLowSampleRateCutoff
: 0;
- // Create filter groups.
- // TODO(bshaya): Switch to filter groups based on AudioContentType
- filter_groups_.push_back(base::MakeUnique<FilterGroup>(
- std::unordered_set<std::string>(
- {::media::AudioDeviceDescription::kCommunicationsDeviceId}),
- AudioFilterFactory::COMMUNICATION_AUDIO_FILTER));
- filter_groups_.push_back(base::MakeUnique<FilterGroup>(
- std::unordered_set<std::string>({kAlarmAudioDeviceId}),
- AudioFilterFactory::ALARM_AUDIO_FILTER));
- filter_groups_.push_back(base::MakeUnique<FilterGroup>(
- std::unordered_set<std::string>({kTtsAudioDeviceId}),
- AudioFilterFactory::TTS_AUDIO_FILTER));
- filter_groups_.push_back(base::MakeUnique<FilterGroup>(
- std::unordered_set<std::string>(
- {::media::AudioDeviceDescription::kDefaultDeviceId,
- kEarconAudioDeviceId}),
- AudioFilterFactory::MEDIA_AUDIO_FILTER));
+ // Create filters
+ pre_loopback_filter_ = AudioFilterFactory::MakeAudioFilter(
+ AudioFilterFactory::PRE_LOOPBACK_FILTER);
+ post_loopback_filter_ = AudioFilterFactory::MakeAudioFilter(
+ AudioFilterFactory::POST_LOOPBACK_FILTER);
DefineAlsaParameters();
}
@@ -550,9 +529,14 @@
}
// Initialize filters
- for (auto&& filter_group : filter_groups_) {
- filter_group->Initialize(output_samples_per_second_,
- ::media::SampleFormat::kSampleFormatS32);
+ if (pre_loopback_filter_) {
+ pre_loopback_filter_->SetSampleRateAndFormat(
+ output_samples_per_second_, ::media::SampleFormat::kSampleFormatS32);
+ }
+
+ if (post_loopback_filter_) {
+ post_loopback_filter_->SetSampleRateAndFormat(
+ output_samples_per_second_, ::media::SampleFormat::kSampleFormatS32);
}
RETURN_REPORT_ERROR(PcmPrepare, pcm_);
@@ -651,7 +635,6 @@
}
DCHECK(input);
-
// If the new input is a primary one, we may need to change the output
// sample rate to match its input sample rate.
// We only change the output rate if it is not set to a fixed value.
@@ -661,31 +644,17 @@
}
check_close_timer_->Stop();
- switch (state_) {
- case kStateUninitialized:
- requested_output_samples_per_second_ = input->input_samples_per_second();
- Start();
- // Fallthrough intended
- case kStateNormalPlayback: {
- bool found_filter_group = false;
- input->Initialize(rendering_delay_);
- for (auto&& filter_group : filter_groups_) {
- if (filter_group->CanProcessInput(input.get())) {
- found_filter_group = true;
- input->set_filter_group(filter_group.get());
- break;
- }
- }
- DCHECK(found_filter_group) << "Could not find a filter group for "
- << input->device_id();
- inputs_.push_back(std::move(input));
- } break;
- case kStateError:
- input->SignalError(StreamMixerAlsaInput::MixerError::kInternalError);
- ignored_inputs_.push_back(std::move(input));
- break;
- default:
- NOTREACHED();
+ if (state_ == kStateUninitialized) {
+ requested_output_samples_per_second_ = input->input_samples_per_second();
+ Start();
+ input->Initialize(rendering_delay_);
+ inputs_.push_back(std::move(input));
+ } else if (state_ == kStateNormalPlayback) {
+ input->Initialize(rendering_delay_);
+ inputs_.push_back(std::move(input));
+ } else {
+ input->SignalError(StreamMixerAlsaInput::MixerError::kInternalError);
+ ignored_inputs_.push_back(std::move(input));
}
}
@@ -793,8 +762,6 @@
bool StreamMixerAlsa::TryWriteFrames() {
DCHECK(mixer_task_runner_->BelongsToCurrentThread());
- DCHECK_GE(filter_groups_.size(), 1u);
-
if (state_ != kStateNormalPlayback) {
return false;
}
@@ -802,17 +769,12 @@
const int min_frames_in_buffer =
output_samples_per_second_ * kMinBufferedDataMs / 1000;
int chunk_size = output_samples_per_second_ * kMaxWriteSizeMs / 1000;
- bool is_silence = true;
- for (auto&& filter_group : filter_groups_) {
- filter_group->ClearActiveInputs();
- }
+ std::vector<InputQueue*> active_inputs;
for (auto&& input : inputs_) {
int read_size = input->MaxReadSize();
if (read_size > 0) {
- DCHECK(input->filter_group());
- input->filter_group()->AddActiveInput(input.get());
+ active_inputs.push_back(input.get());
chunk_size = std::min(chunk_size, read_size);
- is_silence = false;
} else if (input->primary()) {
if (alsa_->PcmStatus(pcm_, pcm_status_) != 0) {
LOG(ERROR) << "Failed to get status";
@@ -839,52 +801,57 @@
}
}
- if (is_silence) {
- // No inputs have any data to provide. Push silence to prevent underrun.
+ if (active_inputs.empty()) {
+ // No inputs have any data to provide. Fill with silence to avoid underrun.
chunk_size = kPreventUnderrunChunkSize;
- }
-
- // Mix and filter each group.
- std::vector<uint8_t>* interleaved = nullptr;
- for (auto&& filter_group : filter_groups_) {
- if (filter_group->MixAndFilter(chunk_size)) {
- if (!interleaved) {
- interleaved = filter_group->GetInterleaved();
- } else {
- DCHECK_EQ(4, BytesPerOutputFormatSample());
- VectorAccumulate(
- reinterpret_cast<int32_t*>(filter_group->GetInterleaved()->data()),
- chunk_size * kNumOutputChannels,
- reinterpret_cast<int32_t*>(interleaved->data()));
- }
- }
- }
-
- if (!interleaved) {
- // No group has any data, write empty buffer.
- filter_groups_[0]->ClearInterleaved(chunk_size);
- interleaved = filter_groups_[0]->GetInterleaved();
- }
-
- WriteMixedPcm(interleaved, chunk_size);
+ if (!mixed_ || mixed_->frames() < chunk_size) {
+ mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
+ }
+
+ mixed_->Zero();
+ WriteMixedPcm(*mixed_, chunk_size, true /* is_silence */);
+ return true;
+ }
+
+ // If |mixed_| has not been allocated, or it is too small, allocate a buffer.
+ if (!mixed_ || mixed_->frames() < chunk_size) {
+ mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
+ }
+
+ // If |temp_| has not been allocated, or is too small, allocate a buffer.
+ if (!temp_ || temp_->frames() < chunk_size) {
+ temp_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
+ }
+
+ mixed_->ZeroFramesPartial(0, chunk_size);
+
+ // Loop through active inputs, polling them for data, and mixing them.
+ for (InputQueue* input : active_inputs) {
+ input->GetResampledData(temp_.get(), chunk_size);
+ for (int c = 0; c < kNumOutputChannels; ++c) {
+ input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size,
+ mixed_->channel(c));
+ }
+ }
+
+ WriteMixedPcm(*mixed_, chunk_size, false /* is_silence */);
return true;
-}
-
-size_t StreamMixerAlsa::InterleavedSize(int frames) {
- return BytesPerOutputFormatSample() *
- static_cast<size_t>(frames * kNumOutputChannels);
}
ssize_t StreamMixerAlsa::BytesPerOutputFormatSample() {
return alsa_->PcmFormatSize(pcm_format_, 1);
}
-void StreamMixerAlsa::WriteMixedPcm(std::vector<uint8_t>* interleaved,
- int frames) {
+void StreamMixerAlsa::WriteMixedPcm(const ::media::AudioBus& mixed,
+ int frames, bool is_silence) {
DCHECK(mixer_task_runner_->BelongsToCurrentThread());
CHECK_PCM_INITIALIZED();
- DCHECK(interleaved);
- DCHECK_GE(interleaved->size(), InterleavedSize(frames));
+
+ size_t interleaved_size = static_cast<size_t>(frames * kNumOutputChannels) *
+ BytesPerOutputFormatSample();
+ if (interleaved_.size() < interleaved_size) {
+ interleaved_.resize(interleaved_size);
+ }
int64_t expected_playback_time;
if (rendering_delay_.timestamp_microseconds == kNoTimestamp) {
@@ -894,10 +861,37 @@
rendering_delay_.delay_microseconds;
}
+ mixed.ToInterleaved(frames, BytesPerOutputFormatSample(),
+ interleaved_.data());
+
+ // Ensure that, on onset of silence, at least |kSilenceSecondsToFilter|
+ // second of audio get pushed through the filters to clear any memory.
+ bool filter_frames = true;
+ if (is_silence) {
+ int silence_frames_to_filter =
+ output_samples_per_second_ * kSilenceSecondsToFilter;
+ if (silence_frames_filtered_ < silence_frames_to_filter) {
+ silence_frames_filtered_ += frames;
+ } else {
+ filter_frames = false;
+ }
+ } else {
+ silence_frames_filtered_ = 0;
+ }
+
+ // Filter, send to observers, and post filter
+ if (pre_loopback_filter_ && filter_frames) {
+ pre_loopback_filter_->ProcessInterleaved(interleaved_.data(), frames);
+ }
+
for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) {
observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32,
output_samples_per_second_, kNumOutputChannels,
- interleaved->data(), InterleavedSize(frames));
+ interleaved_.data(), interleaved_size);
+ }
+
+ if (post_loopback_filter_ && filter_frames) {
+ post_loopback_filter_->ProcessInterleaved(interleaved_.data(), frames);
}
// If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need
@@ -907,7 +901,7 @@
}
int frames_left = frames;
- uint8_t* data = interleaved->data();
+ uint8_t* data = &interleaved_[0];
while (frames_left) {
int frames_or_error;
while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) {
« no previous file with comments | « chromecast/media/cma/backend/alsa/stream_mixer_alsa.h ('k') | chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698