Commit 146e6b47 authored by jyw's avatar jyw Committed by Commit bot

[chromecast] Slew stream volume changes in StreamMixerAlsa.

BUG=internal 29459582
BUG=internal 31162371
TEST=cast_alsa_cma_backend_unittests --gtest_filter=StreamMixerAlsaTest.*
     exercise stream volume API; listen for smooth volume transitions

Review-Url: https://codereview.chromium.org/2341783004
Cr-Commit-Position: refs/heads/master@{#419540}
parent f8c96db7
...@@ -55,6 +55,7 @@ source_set("alsa_cma_backend") { ...@@ -55,6 +55,7 @@ source_set("alsa_cma_backend") {
deps = [ deps = [
":alsa_features", ":alsa_features",
":audio_filter_includes", ":audio_filter_includes",
":slew_volume",
"//base", "//base",
"//chromecast/base", "//chromecast/base",
"//chromecast/media/cma/backend", "//chromecast/media/cma/backend",
...@@ -94,6 +95,17 @@ source_set("audio_filter_includes") { ...@@ -94,6 +95,17 @@ source_set("audio_filter_includes") {
] ]
} }
source_set("slew_volume") {
sources = [
"slew_volume.cc",
"slew_volume.h",
]
deps = [
"//base",
"//media",
]
}
# GYP target: chromecast/media/media.gyp:chromecast_alsa_features # GYP target: chromecast/media/media.gyp:chromecast_alsa_features
buildflag_header("alsa_features") { buildflag_header("alsa_features") {
header = "alsa_features.h" header = "alsa_features.h"
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/media/cma/backend/alsa/slew_volume.h"
#include <algorithm>
#include "base/logging.h"
#include "media/base/vector_math.h"
namespace {
// The time to slew from 0.0 to 1.0.
const int kMaxSlewTimeMs = 100;
const int kDefaultSampleRate = 44100;
}
namespace chromecast {
namespace media {
SlewVolume::SlewVolume() : SlewVolume(kMaxSlewTimeMs, kMaxSlewTimeMs) {}
SlewVolume::SlewVolume(int max_slew_time_up_ms, int max_slew_time_down_ms)
: max_slew_time_up_ms_(max_slew_time_up_ms),
max_slew_time_down_ms_(max_slew_time_down_ms),
max_slew_up_(1000.0 / (max_slew_time_up_ms * kDefaultSampleRate)),
max_slew_down_(1000.0 / (max_slew_time_down_ms * kDefaultSampleRate)) {}
// Slew rate should be 1 / (slew_time * sample_rate)
void SlewVolume::SetSampleRate(int sample_rate) {
max_slew_up_ = 1000.0 / (max_slew_time_up_ms_ * sample_rate);
max_slew_down_ = 1000.0 / (max_slew_time_down_ms_ * sample_rate);
}
void SlewVolume::SetVolume(double volume_scale) {
volume_scale_ = volume_scale;
}
void SlewVolume::ProcessFMAC(bool repeat_transition,
const float* src,
int frames,
float* dest) {
DCHECK(src);
DCHECK(dest);
// Ensure |src| and |dest| are 16-byte aligned.
DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) &
(::media::vector_math::kRequiredAlignment - 1));
DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) &
(::media::vector_math::kRequiredAlignment - 1));
if (!frames) {
return;
}
if (repeat_transition) {
current_volume_ = last_starting_volume_;
} else {
last_starting_volume_ = current_volume_;
}
if (current_volume_ == volume_scale_) {
if (current_volume_ == 0.0) {
return;
}
::media::vector_math::FMAC(src, current_volume_, frames, dest);
return;
} else if (current_volume_ < volume_scale_) {
do {
(*dest) += (*src) * current_volume_;
++src;
++dest;
--frames;
current_volume_ += max_slew_up_;
} while (current_volume_ < volume_scale_ && frames);
current_volume_ = std::min(current_volume_, volume_scale_);
} else { // current_volume_ > volume_scale_
do {
(*dest) += (*src) * current_volume_;
++src;
++dest;
--frames;
current_volume_ -= max_slew_down_;
} while (current_volume_ > volume_scale_ && frames);
current_volume_ = std::max(current_volume_, volume_scale_);
}
if (frames) {
for (int f = 0; f < frames; ++f) {
dest[f] += src[f] * current_volume_;
}
}
}
// Scaling samples naively like this takes 0.2% of the CPU's time @ 44100hz
// on pineapple.
// Assumes 2 channel audio.
bool SlewVolume::ProcessInterleaved(int32_t* data, int frames) {
DCHECK(data);
if (!frames) {
return true;
}
if (current_volume_ == volume_scale_) {
if (current_volume_ == 1.0) {
return true;
}
for (int i = 0; i < 2 * frames; ++i) {
data[i] *= current_volume_;
}
return true;
} else if (current_volume_ < volume_scale_) {
do {
(*data) *= current_volume_;
++data;
(*data) *= current_volume_;
++data;
--frames;
current_volume_ += max_slew_up_;
} while (current_volume_ < volume_scale_ && frames);
current_volume_ = std::min(current_volume_, volume_scale_);
} else {
do {
(*data) *= current_volume_;
++data;
(*data) *= current_volume_;
++data;
--frames;
current_volume_ -= max_slew_down_;
} while (current_volume_ > volume_scale_ && frames);
current_volume_ = std::max(current_volume_, volume_scale_);
}
if (current_volume_ == 1.0) {
return true;
}
if (current_volume_ == 0.0) {
std::fill_n(data, frames * 2, 0);
return true;
}
for (int i = 0; i < 2 * frames; ++i) {
data[i] *= current_volume_;
}
return true;
}
} // namespace media
} // namespace chromecast
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Scale volume with slew rate limiting
#ifndef CHROMECAST_MEDIA_CMA_BACKEND_ALSA_SLEW_VOLUME_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_SLEW_VOLUME_H_
#include <stdint.h>
#include "base/macros.h"
namespace chromecast {
namespace media {
class SlewVolume {
public:
SlewVolume();
SlewVolume(int max_slew_up_ms, int max_slew_down_ms);
~SlewVolume() = default;
void SetSampleRate(int sample_rate);
void SetVolume(double volume_scale);
// Assumes 1 channel float data that is 16-byte aligned. Smoothly calculates
// dest[i] += src[i] * volume_scaling
// ProcessFMAC will be called once for each channel of audio present and
// |repeat_transition| will be true for channels 2 through n.
void ProcessFMAC(bool repeat_transition,
const float* src,
int frames,
float* dest);
// Assumes 2 channels.
bool ProcessInterleaved(int32_t* data, int frames);
private:
double volume_scale_ = 1.0;
double current_volume_ = 1.0;
double last_starting_volume_ = 1.0;
int max_slew_time_up_ms_;
int max_slew_time_down_ms_;
double max_slew_up_;
double max_slew_down_;
DISALLOW_COPY_AND_ASSIGN(SlewVolume);
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_SLEW_VOLUME_H_
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h" #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h"
#include "media/base/audio_bus.h" #include "media/base/audio_bus.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/base/vector_math.h"
#define RETURN_REPORT_ERROR(snd_func, ...) \ #define RETURN_REPORT_ERROR(snd_func, ...) \
do { \ do { \
...@@ -827,10 +826,8 @@ bool StreamMixerAlsa::TryWriteFrames() { ...@@ -827,10 +826,8 @@ bool StreamMixerAlsa::TryWriteFrames() {
for (InputQueue* input : active_inputs) { for (InputQueue* input : active_inputs) {
input->GetResampledData(temp_.get(), chunk_size); input->GetResampledData(temp_.get(), chunk_size);
for (int c = 0; c < kNumOutputChannels; ++c) { for (int c = 0; c < kNumOutputChannels; ++c) {
float volume_scalar = input->volume_multiplier(); input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size,
DCHECK(volume_scalar >= 0.0 && volume_scalar <= 1.0) << volume_scalar; mixed_->channel(c));
::media::vector_math::FMAC(temp_->channel(c), volume_scalar, chunk_size,
mixed_->channel(c));
} }
} }
......
...@@ -64,10 +64,6 @@ class StreamMixerAlsa { ...@@ -64,10 +64,6 @@ class StreamMixerAlsa {
// positive. // positive.
virtual int input_samples_per_second() const = 0; virtual int input_samples_per_second() const = 0;
// This number will be used to scale the stream before it is mixed. The
// result must be in the range (0.0, 1.0].
virtual float volume_multiplier() const = 0;
// Returns true if the stream is primary. Primary streams will be given // Returns true if the stream is primary. Primary streams will be given
// precedence for sample rates and will dictate when data is polled. // precedence for sample rates and will dictate when data is polled.
virtual bool primary() const = 0; virtual bool primary() const = 0;
...@@ -93,6 +89,16 @@ class StreamMixerAlsa { ...@@ -93,6 +89,16 @@ class StreamMixerAlsa {
// MaxReadSize(), and |dest->frames()| shall be >= |frames|. // MaxReadSize(), and |dest->frames()| shall be >= |frames|.
virtual void GetResampledData(::media::AudioBus* dest, int frames) = 0; virtual void GetResampledData(::media::AudioBus* dest, int frames) = 0;
// Scale |frames| frames at |src| by the current volume (smoothing as
// needed). Add the scaled result to |dest|.
// VolumeScaleAccumulate will be called once for each channel of audio
// present and |repeat_transition| will be true for channels 2 through n.
// |src| and |dest| should be 16-byte aligned.
virtual void VolumeScaleAccumulate(bool repeat_transition,
const float* src,
int frames,
float* dest) = 0;
// Called when this input has been skipped for output due to not having any // Called when this input has been skipped for output due to not having any
// data available. This indicates that there will be a gap in the playback // data available. This indicates that there will be a gap in the playback
// from this stream. // from this stream.
......
...@@ -56,6 +56,9 @@ const int kPausedReadSamples = 512; ...@@ -56,6 +56,9 @@ const int kPausedReadSamples = 512;
const int kDefaultReadSize = ::media::SincResampler::kDefaultRequestSize; const int kDefaultReadSize = ::media::SincResampler::kDefaultRequestSize;
const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min(); const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min();
const int kMaxSlewTimeUpMs = 100;
const int kMaxSlewTimeDownMs = 100;
} // namespace } // namespace
StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl( StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl(
...@@ -71,7 +74,7 @@ StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl( ...@@ -71,7 +74,7 @@ StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl(
caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), caller_task_runner_(base::ThreadTaskRunnerHandle::Get()),
resample_ratio_(1.0), resample_ratio_(1.0),
state_(kStateUninitialized), state_(kStateUninitialized),
volume_multiplier_(1.0f), slew_volume_(kMaxSlewTimeUpMs, kMaxSlewTimeDownMs),
queued_frames_(0), queued_frames_(0),
queued_frames_including_resampler_(0), queued_frames_including_resampler_(0),
current_buffer_offset_(0), current_buffer_offset_(0),
...@@ -96,10 +99,6 @@ int StreamMixerAlsaInputImpl::input_samples_per_second() const { ...@@ -96,10 +99,6 @@ int StreamMixerAlsaInputImpl::input_samples_per_second() const {
return input_samples_per_second_; return input_samples_per_second_;
} }
float StreamMixerAlsaInputImpl::volume_multiplier() const {
return volume_multiplier_;
}
bool StreamMixerAlsaInputImpl::primary() const { bool StreamMixerAlsaInputImpl::primary() const {
return primary_; return primary_;
} }
...@@ -121,6 +120,7 @@ void StreamMixerAlsaInputImpl::Initialize( ...@@ -121,6 +120,7 @@ void StreamMixerAlsaInputImpl::Initialize(
base::Bind(&StreamMixerAlsaInputImpl::ReadCB, base::Unretained(this)))); base::Bind(&StreamMixerAlsaInputImpl::ReadCB, base::Unretained(this))));
resampler_->PrimeWithSilence(); resampler_->PrimeWithSilence();
} }
slew_volume_.SetSampleRate(mixer_->output_samples_per_second());
mixer_rendering_delay_ = mixer_rendering_delay; mixer_rendering_delay_ = mixer_rendering_delay;
fade_out_frames_total_ = NormalFadeFrames(); fade_out_frames_total_ = NormalFadeFrames();
fade_frames_remaining_ = NormalFadeFrames(); fade_frames_remaining_ = NormalFadeFrames();
...@@ -511,7 +511,14 @@ void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) { ...@@ -511,7 +511,14 @@ void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) {
multiplier = 1.0f; multiplier = 1.0f;
if (multiplier < 0.0f) if (multiplier < 0.0f)
multiplier = 0.0f; multiplier = 0.0f;
volume_multiplier_ = multiplier; slew_volume_.SetVolume(multiplier);
}
void StreamMixerAlsaInputImpl::VolumeScaleAccumulate(bool repeat_transition,
const float* src,
int frames,
float* dest) {
slew_volume_.ProcessFMAC(repeat_transition, src, frames, dest);
} }
} // namespace media } // namespace media
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" #include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h"
#include "chromecast/media/cma/backend/alsa/slew_volume.h"
#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h" #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h"
#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h" #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h"
...@@ -113,7 +114,6 @@ class StreamMixerAlsaInputImpl : public StreamMixerAlsa::InputQueue { ...@@ -113,7 +114,6 @@ class StreamMixerAlsaInputImpl : public StreamMixerAlsa::InputQueue {
private: private:
// StreamMixerAlsa::InputQueue implementation: // StreamMixerAlsa::InputQueue implementation:
int input_samples_per_second() const override; int input_samples_per_second() const override;
float volume_multiplier() const override;
bool primary() const override; bool primary() const override;
bool IsDeleting() const override; bool IsDeleting() const override;
void Initialize(const MediaPipelineBackendAlsa::RenderingDelay& void Initialize(const MediaPipelineBackendAlsa::RenderingDelay&
...@@ -121,6 +121,10 @@ class StreamMixerAlsaInputImpl : public StreamMixerAlsa::InputQueue { ...@@ -121,6 +121,10 @@ class StreamMixerAlsaInputImpl : public StreamMixerAlsa::InputQueue {
int MaxReadSize() override; int MaxReadSize() override;
void GetResampledData(::media::AudioBus* dest, int frames) override; void GetResampledData(::media::AudioBus* dest, int frames) override;
void OnSkipped() override; void OnSkipped() override;
void VolumeScaleAccumulate(bool repeat_transition,
const float* src,
int frames,
float* dest) override;
void AfterWriteFrames(const MediaPipelineBackendAlsa::RenderingDelay& void AfterWriteFrames(const MediaPipelineBackendAlsa::RenderingDelay&
mixer_rendering_delay) override; mixer_rendering_delay) override;
void SignalError(StreamMixerAlsaInput::MixerError error) override; void SignalError(StreamMixerAlsaInput::MixerError error) override;
...@@ -150,7 +154,7 @@ class StreamMixerAlsaInputImpl : public StreamMixerAlsa::InputQueue { ...@@ -150,7 +154,7 @@ class StreamMixerAlsaInputImpl : public StreamMixerAlsa::InputQueue {
double resample_ratio_; double resample_ratio_;
State state_; State state_;
float volume_multiplier_; SlewVolume slew_volume_;
base::Lock queue_lock_; // Lock for the following queue-related members. base::Lock queue_lock_; // Lock for the following queue-related members.
scoped_refptr<DecoderBufferBase> pending_data_; scoped_refptr<DecoderBufferBase> pending_data_;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" #include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h"
#include "media/base/audio_bus.h" #include "media/base/audio_bus.h"
#include "media/base/vector_math.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -134,6 +135,8 @@ class MockInputQueue : public StreamMixerAlsa::InputQueue { ...@@ -134,6 +135,8 @@ class MockInputQueue : public StreamMixerAlsa::InputQueue {
deleting_(false) { deleting_(false) {
ON_CALL(*this, GetResampledData(_, _)).WillByDefault( ON_CALL(*this, GetResampledData(_, _)).WillByDefault(
testing::Invoke(this, &MockInputQueue::DoGetResampledData)); testing::Invoke(this, &MockInputQueue::DoGetResampledData));
ON_CALL(*this, VolumeScaleAccumulate(_, _, _, _)).WillByDefault(
testing::Invoke(this, &MockInputQueue::DoVolumeScaleAccumulate));
ON_CALL(*this, PrepareToDelete(_)).WillByDefault( ON_CALL(*this, PrepareToDelete(_)).WillByDefault(
testing::Invoke(this, &MockInputQueue::DoPrepareToDelete)); testing::Invoke(this, &MockInputQueue::DoPrepareToDelete));
} }
...@@ -143,7 +146,6 @@ class MockInputQueue : public StreamMixerAlsa::InputQueue { ...@@ -143,7 +146,6 @@ class MockInputQueue : public StreamMixerAlsa::InputQueue {
// StreamMixerAlsa::InputQueue implementation: // StreamMixerAlsa::InputQueue implementation:
int input_samples_per_second() const override { return samples_per_second_; } int input_samples_per_second() const override { return samples_per_second_; }
float volume_multiplier() const override { return multiplier_; }
bool primary() const override { return primary_; } bool primary() const override { return primary_; }
bool IsDeleting() const override { return deleting_; } bool IsDeleting() const override { return deleting_; }
MOCK_METHOD1(Initialize, MOCK_METHOD1(Initialize,
...@@ -151,6 +153,9 @@ class MockInputQueue : public StreamMixerAlsa::InputQueue { ...@@ -151,6 +153,9 @@ class MockInputQueue : public StreamMixerAlsa::InputQueue {
mixer_rendering_delay)); mixer_rendering_delay));
int MaxReadSize() override { return max_read_size_; } int MaxReadSize() override { return max_read_size_; }
MOCK_METHOD2(GetResampledData, void(::media::AudioBus* dest, int frames)); MOCK_METHOD2(GetResampledData, void(::media::AudioBus* dest, int frames));
MOCK_METHOD4(
VolumeScaleAccumulate,
void(bool repeat_transition, const float* src, int frames, float* dest));
MOCK_METHOD0(OnSkipped, void()); MOCK_METHOD0(OnSkipped, void());
MOCK_METHOD1(AfterWriteFrames, MOCK_METHOD1(AfterWriteFrames,
void(const MediaPipelineBackendAlsa::RenderingDelay& void(const MediaPipelineBackendAlsa::RenderingDelay&
...@@ -188,6 +193,16 @@ class MockInputQueue : public StreamMixerAlsa::InputQueue { ...@@ -188,6 +193,16 @@ class MockInputQueue : public StreamMixerAlsa::InputQueue {
} }
} }
void DoVolumeScaleAccumulate(bool repeat_transition,
const float* src,
int frames,
float* dest) {
CHECK(src);
CHECK(dest);
CHECK(multiplier_ >= 0.0 && multiplier_ <= 1.0);
::media::vector_math::FMAC(src, multiplier_, frames, dest);
}
void DoPrepareToDelete(const OnReadyToDeleteCb& delete_cb) { void DoPrepareToDelete(const OnReadyToDeleteCb& delete_cb) {
deleting_ = true; deleting_ = true;
delete_cb.Run(this); delete_cb.Run(this);
...@@ -365,6 +380,8 @@ TEST_F(StreamMixerAlsaTest, WriteFrames) { ...@@ -365,6 +380,8 @@ TEST_F(StreamMixerAlsaTest, WriteFrames) {
inputs[2]->SetMaxReadSize(2048); inputs[2]->SetMaxReadSize(2048);
for (auto* input : inputs) { for (auto* input : inputs) {
EXPECT_CALL(*input, GetResampledData(_, 512)).Times(1); EXPECT_CALL(*input, GetResampledData(_, 512)).Times(1);
EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, 512, _))
.Times(kNumChannels);
EXPECT_CALL(*input, AfterWriteFrames(_)).Times(1); EXPECT_CALL(*input, AfterWriteFrames(_)).Times(1);
} }
...@@ -380,8 +397,11 @@ TEST_F(StreamMixerAlsaTest, WriteFrames) { ...@@ -380,8 +397,11 @@ TEST_F(StreamMixerAlsaTest, WriteFrames) {
EXPECT_CALL(*inputs[1], OnSkipped()); EXPECT_CALL(*inputs[1], OnSkipped());
inputs[2]->SetPrimary(false); inputs[2]->SetPrimary(false);
for (auto* input : inputs) { for (auto* input : inputs) {
if (input != inputs[1]) if (input != inputs[1]) {
EXPECT_CALL(*input, GetResampledData(_, 1024)).Times(1); EXPECT_CALL(*input, GetResampledData(_, 1024)).Times(1);
EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, 1024, _))
.Times(kNumChannels);
}
EXPECT_CALL(*input, AfterWriteFrames(_)).Times(1); EXPECT_CALL(*input, AfterWriteFrames(_)).Times(1);
} }
// Note that the new smallest stream shall dictate the length of the write. // Note that the new smallest stream shall dictate the length of the write.
...@@ -412,6 +432,8 @@ TEST_F(StreamMixerAlsaTest, OneStreamMixesProperly) { ...@@ -412,6 +432,8 @@ TEST_F(StreamMixerAlsaTest, OneStreamMixesProperly) {
// Write the stream to ALSA. // Write the stream to ALSA.
EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); EXPECT_CALL(*input, GetResampledData(_, kNumFrames));
EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, kNumFrames, _))
.Times(kNumChannels);
EXPECT_CALL(*input, AfterWriteFrames(_)); EXPECT_CALL(*input, AfterWriteFrames(_));
mixer->WriteFramesForTest(); mixer->WriteFramesForTest();
...@@ -444,6 +466,8 @@ TEST_F(StreamMixerAlsaTest, OneStreamIsScaledDownProperly) { ...@@ -444,6 +466,8 @@ TEST_F(StreamMixerAlsaTest, OneStreamIsScaledDownProperly) {
// Write the stream to ALSA. // Write the stream to ALSA.
EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); EXPECT_CALL(*input, GetResampledData(_, kNumFrames));
EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, kNumFrames, _))
.Times(kNumChannels);
EXPECT_CALL(*input, AfterWriteFrames(_)); EXPECT_CALL(*input, AfterWriteFrames(_));
mixer->WriteFramesForTest(); mixer->WriteFramesForTest();
...@@ -476,6 +500,8 @@ TEST_F(StreamMixerAlsaTest, TwoUnscaledStreamsMixProperly) { ...@@ -476,6 +500,8 @@ TEST_F(StreamMixerAlsaTest, TwoUnscaledStreamsMixProperly) {
for (size_t i = 0; i < inputs.size(); ++i) { for (size_t i = 0; i < inputs.size(); ++i) {
inputs[i]->SetData(GetTestData(i)); inputs[i]->SetData(GetTestData(i));
EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames));
EXPECT_CALL(*inputs[i], VolumeScaleAccumulate(_, _, kNumFrames, _))
.Times(kNumChannels);
EXPECT_CALL(*inputs[i], AfterWriteFrames(_)); EXPECT_CALL(*inputs[i], AfterWriteFrames(_));
} }
...@@ -548,6 +574,8 @@ TEST_F(StreamMixerAlsaTest, TwoUnscaledStreamsMixProperlyWithEdgeCases) { ...@@ -548,6 +574,8 @@ TEST_F(StreamMixerAlsaTest, TwoUnscaledStreamsMixProperlyWithEdgeCases) {
test_data->FromInterleaved(kEdgeData[i], kNumFrames, kBytesPerSample); test_data->FromInterleaved(kEdgeData[i], kNumFrames, kBytesPerSample);
inputs[i]->SetData(std::move(test_data)); inputs[i]->SetData(std::move(test_data));
EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames));
EXPECT_CALL(*inputs[i], VolumeScaleAccumulate(_, _, kNumFrames, _))
.Times(kNumChannels);
EXPECT_CALL(*inputs[i], AfterWriteFrames(_)); EXPECT_CALL(*inputs[i], AfterWriteFrames(_));
} }
...@@ -578,24 +606,28 @@ TEST_F(StreamMixerAlsaTest, WriteBuffersOfVaryingLength) { ...@@ -578,24 +606,28 @@ TEST_F(StreamMixerAlsaTest, WriteBuffersOfVaryingLength) {
// The input stream will provide buffers of several different lengths. // The input stream will provide buffers of several different lengths.
input->SetMaxReadSize(7); input->SetMaxReadSize(7);
EXPECT_CALL(*input, GetResampledData(_, 7)); EXPECT_CALL(*input, GetResampledData(_, 7));
EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, 7, _)).Times(kNumChannels);
EXPECT_CALL(*input, AfterWriteFrames(_)); EXPECT_CALL(*input, AfterWriteFrames(_));
EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 7)).Times(1); EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 7)).Times(1);
mixer->WriteFramesForTest(); mixer->WriteFramesForTest();
input->SetMaxReadSize(100); input->SetMaxReadSize(100);
EXPECT_CALL(*input, GetResampledData(_, 100)); EXPECT_CALL(*input, GetResampledData(_, 100));
EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, 100, _)).Times(kNumChannels);
EXPECT_CALL(*input, AfterWriteFrames(_)); EXPECT_CALL(*input, AfterWriteFrames(_));
EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 100)).Times(1); EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 100)).Times(1);
mixer->WriteFramesForTest(); mixer->WriteFramesForTest();
input->SetMaxReadSize(32); input->SetMaxReadSize(32);
EXPECT_CALL(*input, GetResampledData(_, 32)); EXPECT_CALL(*input, GetResampledData(_, 32));
EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, 32, _)).Times(kNumChannels);
EXPECT_CALL(*input, AfterWriteFrames(_)); EXPECT_CALL(*input, AfterWriteFrames(_));
EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 32)).Times(1); EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 32)).Times(1);
mixer->WriteFramesForTest(); mixer->WriteFramesForTest();
input->SetMaxReadSize(1024); input->SetMaxReadSize(1024);
EXPECT_CALL(*input, GetResampledData(_, 1024)); EXPECT_CALL(*input, GetResampledData(_, 1024));
EXPECT_CALL(*input, VolumeScaleAccumulate(_, _, 1024, _)).Times(kNumChannels);
EXPECT_CALL(*input, AfterWriteFrames(_)); EXPECT_CALL(*input, AfterWriteFrames(_));
EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 1024)).Times(1); EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 1024)).Times(1);
mixer->WriteFramesForTest(); mixer->WriteFramesForTest();
...@@ -622,6 +654,7 @@ TEST_F(StreamMixerAlsaTest, StuckStreamWithoutUnderrun) { ...@@ -622,6 +654,7 @@ TEST_F(StreamMixerAlsaTest, StuckStreamWithoutUnderrun) {
// to give. // to give.
inputs[0]->SetData(GetTestData(0)); inputs[0]->SetData(GetTestData(0));
EXPECT_CALL(*inputs[0], GetResampledData(_, _)).Times(0); EXPECT_CALL(*inputs[0], GetResampledData(_, _)).Times(0);
EXPECT_CALL(*inputs[0], VolumeScaleAccumulate(_, _, _, _)).Times(0);
EXPECT_CALL(*inputs[0], AfterWriteFrames(_)).Times(0); EXPECT_CALL(*inputs[0], AfterWriteFrames(_)).Times(0);
EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, _)).Times(0); EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, _)).Times(0);
...@@ -654,8 +687,11 @@ TEST_F(StreamMixerAlsaTest, StuckStreamWithUnderrun) { ...@@ -654,8 +687,11 @@ TEST_F(StreamMixerAlsaTest, StuckStreamWithUnderrun) {
const int kNumFrames = 32; const int kNumFrames = 32;
inputs[0]->SetData(GetTestData(0)); inputs[0]->SetData(GetTestData(0));
EXPECT_CALL(*inputs[0], GetResampledData(_, kNumFrames)); EXPECT_CALL(*inputs[0], GetResampledData(_, kNumFrames));
EXPECT_CALL(*inputs[0], VolumeScaleAccumulate(_, _, kNumFrames, _))
.Times(kNumChannels);
EXPECT_CALL(*inputs[0], AfterWriteFrames(_)); EXPECT_CALL(*inputs[0], AfterWriteFrames(_));
EXPECT_CALL(*inputs[1], GetResampledData(_, _)).Times(0); EXPECT_CALL(*inputs[1], GetResampledData(_, _)).Times(0);
EXPECT_CALL(*inputs[1], VolumeScaleAccumulate(_, _, kNumFrames, _)).Times(0);
EXPECT_CALL(*inputs[1], OnSkipped()); EXPECT_CALL(*inputs[1], OnSkipped());
EXPECT_CALL(*inputs[1], AfterWriteFrames(_)); EXPECT_CALL(*inputs[1], AfterWriteFrames(_));
...@@ -689,8 +725,11 @@ TEST_F(StreamMixerAlsaTest, StuckStreamWithLowBuffer) { ...@@ -689,8 +725,11 @@ TEST_F(StreamMixerAlsaTest, StuckStreamWithLowBuffer) {
const int kNumFrames = 32; const int kNumFrames = 32;
inputs[0]->SetData(GetTestData(0)); inputs[0]->SetData(GetTestData(0));
EXPECT_CALL(*inputs[0], GetResampledData(_, kNumFrames)); EXPECT_CALL(*inputs[0], GetResampledData(_, kNumFrames));
EXPECT_CALL(*inputs[0], VolumeScaleAccumulate(_, _, kNumFrames, _))
.Times(kNumChannels);
EXPECT_CALL(*inputs[0], AfterWriteFrames(_)); EXPECT_CALL(*inputs[0], AfterWriteFrames(_));
EXPECT_CALL(*inputs[1], GetResampledData(_, _)).Times(0); EXPECT_CALL(*inputs[1], GetResampledData(_, _)).Times(0);
EXPECT_CALL(*inputs[1], VolumeScaleAccumulate(_, _, _, _)).Times(0);
EXPECT_CALL(*inputs[1], OnSkipped()); EXPECT_CALL(*inputs[1], OnSkipped());
EXPECT_CALL(*inputs[1], AfterWriteFrames(_)); EXPECT_CALL(*inputs[1], AfterWriteFrames(_));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment