blob: 8ef3738fd959ee138571669bb9d87c96a912096d [file] [log] [blame]
// Copyright (c) 2012 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 "content/renderer/media/audio_renderer_mixer_manager.h"
#include <memory>
#include "base/bind.h"
#include "build/build_config.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "content/renderer/media/audio_renderer_sink_cache.h"
#include "media/audio/audio_device_description.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_mixer.h"
#include "media/base/audio_renderer_mixer_input.h"
#include "media/base/fake_audio_render_callback.h"
#include "media/base/mock_audio_renderer_sink.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace content {
namespace {
const int kBitsPerChannel = 16;
const int kSampleRate = 48000;
const int kBufferSize = 8192;
const int kHardwareSampleRate = 44100;
const int kHardwareBufferSize = 128;
const media::ChannelLayout kChannelLayout = media::CHANNEL_LAYOUT_STEREO;
const media::ChannelLayout kAnotherChannelLayout = media::CHANNEL_LAYOUT_2_1;
const char* const kDefaultDeviceId =
media::AudioDeviceDescription::kDefaultDeviceId;
const char kAnotherDeviceId[] = "another-device-id";
const char kMatchedDeviceId[] = "matched-device-id";
const char kNonexistentDeviceId[] = "nonexistent-device-id";
const int kRenderFrameId = 124;
const int kAnotherRenderFrameId = 678;
} // namespace;
using media::AudioParameters;
using media::AudioLatency;
class FakeAudioRendererSinkCache : public AudioRendererSinkCache {
public:
using GetSinkCallback =
base::Callback<scoped_refptr<media::AudioRendererSink>(
int render_frame_id,
int session_id,
const std::string& device_id,
const url::Origin& security_origin)>;
using ReleaseSinkCallback =
base::Callback<void(const media::AudioRendererSink*)>;
FakeAudioRendererSinkCache(const GetSinkCallback& get_sink_cb,
const ReleaseSinkCallback& release_sink_cb)
: get_sink_cb_(get_sink_cb), release_sink_cb_(release_sink_cb) {}
media::OutputDeviceInfo GetSinkInfo(
int source_render_frame_id,
int session_id,
const std::string& device_id,
const url::Origin& security_origin) final {
return get_sink_cb_
.Run(source_render_frame_id, session_id, device_id, security_origin)
->GetOutputDeviceInfo();
}
scoped_refptr<media::AudioRendererSink> GetSink(
int source_render_frame_id,
const std::string& device_id,
const url::Origin& security_origin) final {
return get_sink_cb_.Run(source_render_frame_id, 0, device_id,
security_origin);
}
void ReleaseSink(const media::AudioRendererSink* sink) final {
release_sink_cb_.Run(sink);
}
private:
GetSinkCallback get_sink_cb_;
ReleaseSinkCallback release_sink_cb_;
};
class AudioRendererMixerManagerTest : public testing::Test {
public:
AudioRendererMixerManagerTest()
: manager_(new AudioRendererMixerManager(
std::unique_ptr<AudioRendererSinkCache>(
new FakeAudioRendererSinkCache(
base::Bind(&AudioRendererMixerManagerTest::GetSinkPtr,
base::Unretained(this)),
base::Bind(&AudioRendererMixerManagerTest::ReleaseSinkPtr,
base::Unretained(this)))))),
mock_sink_(new media::MockAudioRendererSink(
kDefaultDeviceId,
media::OUTPUT_DEVICE_STATUS_OK,
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout,
kHardwareSampleRate,
kBitsPerChannel,
kHardwareBufferSize))),
mock_sink_no_device_(new media::MockAudioRendererSink(
kNonexistentDeviceId,
media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND)),
mock_sink_matched_device_(
new media::MockAudioRendererSink(kMatchedDeviceId,
media::OUTPUT_DEVICE_STATUS_OK)),
kSecurityOrigin2(GURL("http://localhost")) {}
media::AudioRendererMixer* GetMixer(
int source_render_frame_id,
const media::AudioParameters& params,
AudioLatency::LatencyType latency,
const std::string& device_id,
const url::Origin& security_origin,
media::OutputDeviceStatus* device_status) {
return manager_->GetMixer(source_render_frame_id, params, latency,
device_id, security_origin, device_status);
}
void ReturnMixer(media::AudioRendererMixer* mixer) {
return manager_->ReturnMixer(mixer);
}
// Number of instantiated mixers.
int mixer_count() {
return manager_->mixers_.size();
}
protected:
scoped_refptr<media::AudioRendererSink> GetSinkPtr(
int source_render_frame_id,
int session_id,
const std::string& device_id,
const url::Origin& security_origin) {
if ((device_id == kDefaultDeviceId) || (device_id == kAnotherDeviceId)) {
// We don't care about separate sinks for these devices.
return mock_sink_;
}
if (device_id == kNonexistentDeviceId)
return mock_sink_no_device_;
if (device_id.empty()) {
// The sink used to get device ID from session ID if it's not empty
return session_id ? mock_sink_matched_device_ : mock_sink_;
}
if (device_id == kMatchedDeviceId)
return mock_sink_matched_device_;
NOTREACHED();
return nullptr;
}
MOCK_METHOD1(ReleaseSinkPtr, void(const media::AudioRendererSink*));
std::unique_ptr<AudioRendererMixerManager> manager_;
scoped_refptr<media::MockAudioRendererSink> mock_sink_;
scoped_refptr<media::MockAudioRendererSink> mock_sink_no_device_;
scoped_refptr<media::MockAudioRendererSink> mock_sink_matched_device_;
// To avoid global/static non-POD constants.
const url::Origin kSecurityOrigin;
const url::Origin kSecurityOrigin2;
private:
DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManagerTest);
};
// Verify GetMixer() and ReturnMixer() both work as expected; particularly with
// respect to the explicit ref counting done.
TEST_F(AudioRendererMixerManagerTest, GetReturnMixer) {
// Since we're testing two different sets of parameters, we expect
// AudioRendererMixerManager to call Start and Stop on our mock twice.
EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);
// We expect 2 mixers to be created; each of them should release the sink.
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);
// There should be no mixers outstanding to start with.
EXPECT_EQ(0, mixer_count());
media::AudioParameters params1(media::AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBitsPerChannel,
kBufferSize);
media::AudioRendererMixer* mixer1 =
GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer1);
EXPECT_EQ(1, mixer_count());
// The same parameters should return the same mixer1.
EXPECT_EQ(mixer1,
GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr));
EXPECT_EQ(1, mixer_count());
// Return the extra mixer we just acquired.
ReturnMixer(mixer1);
EXPECT_EQ(1, mixer_count());
media::AudioParameters params2(
AudioParameters::AUDIO_PCM_LINEAR, kAnotherChannelLayout, kSampleRate * 2,
kBitsPerChannel, kBufferSize * 2);
media::AudioRendererMixer* mixer2 =
GetMixer(kRenderFrameId, params2, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer2);
EXPECT_EQ(2, mixer_count());
// Different parameters should result in a different mixer1.
EXPECT_NE(mixer1, mixer2);
// Return both outstanding mixers.
ReturnMixer(mixer1);
EXPECT_EQ(1, mixer_count());
ReturnMixer(mixer2);
EXPECT_EQ(0, mixer_count());
}
// Verify GetMixer() correctly deduplicates mixer with irrelevant AudioParameter
// differences.
TEST_F(AudioRendererMixerManagerTest, MixerReuse) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);
EXPECT_EQ(mixer_count(), 0);
// We expect 2 mixers to be created; each of them should release the sink.
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);
media::AudioParameters params1(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout,
kSampleRate,
kBitsPerChannel,
kBufferSize);
media::AudioRendererMixer* mixer1 =
GetMixer(kRenderFrameId, params1, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer1);
EXPECT_EQ(1, mixer_count());
// Different sample rates, formats, bit depths, and buffer sizes should not
// result in a different mixer.
media::AudioParameters params2(AudioParameters::AUDIO_PCM_LOW_LATENCY,
kChannelLayout,
kSampleRate * 2,
kBitsPerChannel * 2,
kBufferSize * 2);
media::AudioRendererMixer* mixer2 =
GetMixer(kRenderFrameId, params2, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
EXPECT_EQ(mixer1, mixer2);
EXPECT_EQ(1, mixer_count());
ReturnMixer(mixer2);
EXPECT_EQ(1, mixer_count());
// Modify some parameters that do matter: channel layout
media::AudioParameters params3(AudioParameters::AUDIO_PCM_LOW_LATENCY,
kAnotherChannelLayout,
kSampleRate,
kBitsPerChannel,
kBufferSize);
ASSERT_NE(params3.channel_layout(), params1.channel_layout());
media::AudioRendererMixer* mixer3 =
GetMixer(kRenderFrameId, params3, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
EXPECT_NE(mixer1, mixer3);
EXPECT_EQ(2, mixer_count());
ReturnMixer(mixer3);
EXPECT_EQ(1, mixer_count());
// Return final mixer.
ReturnMixer(mixer1);
EXPECT_EQ(0, mixer_count());
}
// Verify CreateInput() provides AudioRendererMixerInput with the appropriate
// callbacks and they are working as expected. Also, verify that separate
// mixers are created for separate RenderFrames, even though the
// AudioParameters are the same.
TEST_F(AudioRendererMixerManagerTest, CreateInput) {
// Expect AudioRendererMixerManager to call Start and Stop on our mock twice
// each. Note: Under normal conditions, each mixer would get its own sink!
EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);
// We expect 2 mixers to be created; each of them should release the sink.
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);
media::AudioParameters params(
AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate,
kBitsPerChannel, kBufferSize);
// Create two mixer inputs and ensure this doesn't instantiate any mixers yet.
EXPECT_EQ(0, mixer_count());
media::FakeAudioRenderCallback callback(0, kSampleRate);
scoped_refptr<media::AudioRendererMixerInput> input(
manager_->CreateInput(kRenderFrameId, 0, kDefaultDeviceId,
kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK));
input->Initialize(params, &callback);
EXPECT_EQ(0, mixer_count());
media::FakeAudioRenderCallback another_callback(1, kSampleRate);
scoped_refptr<media::AudioRendererMixerInput> another_input(
manager_->CreateInput(kAnotherRenderFrameId, 0, kDefaultDeviceId,
kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK));
another_input->Initialize(params, &another_callback);
EXPECT_EQ(0, mixer_count());
// Implicitly test that AudioRendererMixerInput was provided with the expected
// callbacks needed to acquire an AudioRendererMixer and return it.
input->Start();
EXPECT_EQ(1, mixer_count());
another_input->Start();
EXPECT_EQ(2, mixer_count());
// Destroying the inputs should destroy the mixers.
input->Stop();
input = nullptr;
EXPECT_EQ(1, mixer_count());
another_input->Stop();
another_input = nullptr;
EXPECT_EQ(0, mixer_count());
}
// Verify CreateInput() provided with session id creates AudioRendererMixerInput
// with the appropriate callbacks and they are working as expected.
TEST_F(AudioRendererMixerManagerTest, CreateInputWithSessionId) {
// Expect AudioRendererMixerManager to call Start and Stop on our mock twice
// each: for kDefaultDeviceId and for kAnotherDeviceId. Note: Under normal
// conditions, each mixer would get its own sink!
EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);
// Expect AudioRendererMixerManager to call Start and Stop on the matched sink
// once.
EXPECT_CALL(*mock_sink_matched_device_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_matched_device_.get(), Stop()).Times(1);
// We expect 3 mixers to be created; each of them should release a sink.
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_matched_device_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBitsPerChannel,
kBufferSize);
media::FakeAudioRenderCallback callback(0, kSampleRate);
EXPECT_EQ(0, mixer_count());
// Empty device id, zero session id;
scoped_refptr<media::AudioRendererMixerInput> input_to_default_device(
manager_->CreateInput(kRenderFrameId, 0, // session_id
std::string(), kSecurityOrigin,
AudioLatency::LATENCY_PLAYBACK));
input_to_default_device->Initialize(params, &callback);
EXPECT_EQ(0, mixer_count());
// Specific device id, zero session id;
scoped_refptr<media::AudioRendererMixerInput> input_to_matched_device(
manager_->CreateInput(kRenderFrameId, 0, // session_id
kMatchedDeviceId, kSecurityOrigin,
AudioLatency::LATENCY_PLAYBACK));
input_to_matched_device->Initialize(params, &callback);
EXPECT_EQ(0, mixer_count());
// Specific device id, non-zero session id (to be ignored);
scoped_refptr<media::AudioRendererMixerInput> input_to_another_device(
manager_->CreateInput(kRenderFrameId, 1, // session id
kAnotherDeviceId, kSecurityOrigin,
AudioLatency::LATENCY_PLAYBACK));
input_to_another_device->Initialize(params, &callback);
EXPECT_EQ(0, mixer_count());
// Empty device id, non-zero session id;
scoped_refptr<media::AudioRendererMixerInput>
input_to_matched_device_with_session_id(manager_->CreateInput(
kRenderFrameId, 2, // session id
std::string(), kSecurityOrigin, AudioLatency::LATENCY_PLAYBACK));
input_to_matched_device_with_session_id->Initialize(params, &callback);
EXPECT_EQ(0, mixer_count());
// Implicitly test that AudioRendererMixerInput was provided with the expected
// callbacks needed to acquire an AudioRendererMixer and return it.
input_to_default_device->Start();
EXPECT_EQ(1, mixer_count());
input_to_another_device->Start();
EXPECT_EQ(2, mixer_count());
input_to_matched_device->Start();
EXPECT_EQ(3, mixer_count());
// Should go to the same device as the input above.
input_to_matched_device_with_session_id->Start();
EXPECT_EQ(3, mixer_count());
// Destroying the inputs should destroy the mixers.
input_to_default_device->Stop();
input_to_default_device = nullptr;
EXPECT_EQ(2, mixer_count());
input_to_another_device->Stop();
input_to_another_device = nullptr;
EXPECT_EQ(1, mixer_count());
input_to_matched_device->Stop();
input_to_matched_device = nullptr;
EXPECT_EQ(1, mixer_count());
input_to_matched_device_with_session_id->Stop();
input_to_matched_device_with_session_id = nullptr;
EXPECT_EQ(0, mixer_count());
}
// Verify GetMixer() correctly creates different mixers with the same
// parameters, but different device ID and/or security origin
TEST_F(AudioRendererMixerManagerTest, MixerDevices) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(3);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3);
EXPECT_EQ(0, mixer_count());
// We expect 3 mixers to be created; each of them should release a sink.
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(3);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBitsPerChannel,
kBufferSize);
media::AudioRendererMixer* mixer1 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer1);
EXPECT_EQ(1, mixer_count());
media::AudioRendererMixer* mixer2 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kAnotherDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer2);
EXPECT_EQ(2, mixer_count());
EXPECT_NE(mixer1, mixer2);
media::AudioRendererMixer* mixer3 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kAnotherDeviceId, kSecurityOrigin2, nullptr);
ASSERT_TRUE(mixer3);
EXPECT_EQ(3, mixer_count());
EXPECT_NE(mixer1, mixer3);
EXPECT_NE(mixer2, mixer3);
ReturnMixer(mixer1);
EXPECT_EQ(2, mixer_count());
ReturnMixer(mixer2);
EXPECT_EQ(1, mixer_count());
ReturnMixer(mixer3);
EXPECT_EQ(0, mixer_count());
}
// Verify GetMixer() correctly deduplicate mixers with the same
// parameters, different security origins but default device ID
TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentOriginsDefaultDevice) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_EQ(0, mixer_count());
// We expect 1 mixer to be created; it should release its sink.
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBitsPerChannel,
kBufferSize);
media::AudioRendererMixer* mixer1 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer1);
EXPECT_EQ(1, mixer_count());
media::AudioRendererMixer* mixer2 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
std::string(), kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer2);
EXPECT_EQ(1, mixer_count());
EXPECT_EQ(mixer1, mixer2);
media::AudioRendererMixer* mixer3 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin2, nullptr);
ASSERT_TRUE(mixer3);
EXPECT_EQ(1, mixer_count());
EXPECT_EQ(mixer1, mixer3);
media::AudioRendererMixer* mixer4 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
std::string(), kSecurityOrigin2, nullptr);
ASSERT_TRUE(mixer4);
EXPECT_EQ(1, mixer_count());
EXPECT_EQ(mixer1, mixer4);
ReturnMixer(mixer1);
EXPECT_EQ(1, mixer_count());
ReturnMixer(mixer2);
EXPECT_EQ(1, mixer_count());
ReturnMixer(mixer3);
EXPECT_EQ(1, mixer_count());
ReturnMixer(mixer4);
EXPECT_EQ(0, mixer_count());
}
// Verify that GetMixer() correctly returns a null mixer and an appropriate
// status code when a nonexistent device is requested.
TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) {
EXPECT_EQ(0, mixer_count());
// Mixer manager should release a not-ok sink when failing to create a mixer.
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_no_device_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBitsPerChannel,
kBufferSize);
media::OutputDeviceStatus device_status = media::OUTPUT_DEVICE_STATUS_OK;
media::AudioRendererMixer* mixer =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kNonexistentDeviceId, kSecurityOrigin, &device_status);
EXPECT_FALSE(mixer);
EXPECT_EQ(media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, device_status);
EXPECT_EQ(0, mixer_count());
}
// Verify GetMixer() correctly deduplicate mixers basing on latency
// requirements.
TEST_F(AudioRendererMixerManagerTest, LatencyMixing) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(3);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(3);
EXPECT_EQ(0, mixer_count());
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBitsPerChannel,
kBufferSize);
media::AudioRendererMixer* mixer1 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer1);
EXPECT_EQ(1, mixer_count());
media::AudioRendererMixer* mixer2 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer2);
EXPECT_EQ(mixer1, mixer2); // Same latency => same mixer.
EXPECT_EQ(1, mixer_count());
media::AudioRendererMixer* mixer3 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer3);
EXPECT_NE(mixer1, mixer3);
EXPECT_EQ(2, mixer_count()); // Another latency => another mixer.
media::AudioRendererMixer* mixer4 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC,
kDefaultDeviceId, kSecurityOrigin, nullptr);
EXPECT_EQ(mixer3, mixer4);
EXPECT_EQ(2, mixer_count()); // Same latency => same mixer.
media::AudioRendererMixer* mixer5 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE,
kDefaultDeviceId, kSecurityOrigin, nullptr);
ASSERT_TRUE(mixer5);
EXPECT_EQ(3, mixer_count()); // Another latency => another mixer.
media::AudioRendererMixer* mixer6 =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE,
kDefaultDeviceId, kSecurityOrigin, nullptr);
EXPECT_EQ(mixer5, mixer6);
EXPECT_EQ(3, mixer_count()); // Same latency => same mixer.
ReturnMixer(mixer1);
EXPECT_EQ(3, mixer_count());
ReturnMixer(mixer2);
EXPECT_EQ(2, mixer_count());
ReturnMixer(mixer3);
EXPECT_EQ(2, mixer_count());
ReturnMixer(mixer4);
EXPECT_EQ(1, mixer_count());
ReturnMixer(mixer5);
EXPECT_EQ(1, mixer_count());
ReturnMixer(mixer6);
EXPECT_EQ(0, mixer_count());
}
// Verify output bufer size of the mixer is correctly adjusted for Playback
// latency.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlayback) {
// Expecting hardware buffer size of 128 frames
EXPECT_EQ(44100,
mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
// Expecting hardware buffer size of 128 frames
EXPECT_EQ(
128,
mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, kBitsPerChannel, 512);
media::AudioRendererMixer* mixer =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
#if defined(OS_CHROMEOS)
// Expecting input sample rate
EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());
// Round up 20 ms (640) to the power of 2.
EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
// Expecting hardware sample rate
EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate());
// 20 ms at 44100 is 882 frames per buffer.
#if defined(OS_WIN)
// Round up 882 to the nearest multiple of the output buffer size (128). which
// is 7 * 128 = 896
EXPECT_EQ(896, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
// Round up 882 to the power of 2.
EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif // defined(OS_WIN)
#endif // defined(OS_CHROMEOS)
ReturnMixer(mixer);
}
// Verify output bufer size of the mixer is correctly adjusted for Playback
// latency when the device buffer size exceeds 20 ms.
TEST_F(AudioRendererMixerManagerTest,
MixerParamsLatencyPlaybackLargeDeviceBufferSize) {
mock_sink_ = new media::MockAudioRendererSink(
std::string(), media::OUTPUT_DEVICE_STATUS_OK,
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 44100,
kBitsPerChannel, 2048));
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, kBitsPerChannel, 512);
media::AudioRendererMixer* mixer =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
// 20 ms at 44100 is 882 frames per buffer.
#if defined(OS_CHROMEOS)
// Expecting input sample rate
EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());
// Ignore device buffer size, round up 20 ms (640) to the power of 2.
EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
// Expecting hardware sample rate
EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate());
// Prefer device buffer size (2048) if is larger than 20 ms buffer size (882).
EXPECT_EQ(2048, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif
ReturnMixer(mixer);
}
// Verify output bufer size of the mixer is correctly adjusted for Playback
// latency when output audio is fake.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlaybackFakeAudio) {
mock_sink_ = new media::MockAudioRendererSink(
std::string(), media::OUTPUT_DEVICE_STATUS_OK,
AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout, 44100,
kBitsPerChannel, 2048));
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, kBitsPerChannel, 512);
media::AudioRendererMixer* mixer =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_PLAYBACK,
kDefaultDeviceId, kSecurityOrigin, nullptr);
// Expecting input sample rate
EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());
// 20 ms at 32000 is 640 frames per buffer.
#if defined(OS_WIN)
// Use 20 ms buffer.
EXPECT_EQ(640, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
// Ignore device buffer size, round up 640 to the power of 2.
EXPECT_EQ(1024, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif // defined(OS_WIN)
ReturnMixer(mixer);
}
// Verify output bufer size of the mixer is correctly adjusted for RTC latency.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtc) {
// Expecting hardware buffer size of 128 frames
EXPECT_EQ(44100,
mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
// Expecting hardware buffer size of 128 frames
EXPECT_EQ(
128,
mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, kBitsPerChannel, 512);
media::AudioRendererMixer* mixer =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC,
kDefaultDeviceId, kSecurityOrigin, nullptr);
#if defined(OS_CHROMEOS)
int output_sample_rate = 32000;
#else
// Expecting hardware sample rate.
int output_sample_rate = 44100;
#endif // defined(OS_CHROMEOS)
EXPECT_EQ(output_sample_rate,
mixer->GetOutputParamsForTesting().sample_rate());
#if defined(OS_LINUX) || defined(OS_MACOSX)
// Use 10 ms buffer (441 frames per buffer).
EXPECT_EQ(output_sample_rate / 100,
mixer->GetOutputParamsForTesting().frames_per_buffer());
#elif defined(OS_ANDROID)
// If hardware buffer size (128) is less than 20 ms (882), use 20 ms buffer
// (otherwise, use hardware buffer).
EXPECT_EQ(882, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
// Use hardware buffer size (128).
EXPECT_EQ(128, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif // defined(OS_LINUX) || defined(OS_MACOSX)
ReturnMixer(mixer);
}
// Verify output bufer size of the mixer is correctly adjusted for RTC latency
// when output audio is fake.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtcFakeAudio) {
mock_sink_ = new media::MockAudioRendererSink(
std::string(), media::OUTPUT_DEVICE_STATUS_OK,
AudioParameters(AudioParameters::AUDIO_FAKE, kChannelLayout, 44100,
kBitsPerChannel, 128));
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, kBitsPerChannel, 512);
media::AudioRendererMixer* mixer =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_RTC,
kDefaultDeviceId, kSecurityOrigin, nullptr);
// Expecting input sample rate.
EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());
// 10 ms at 32000 is 320 frames per buffer. Expect it on all the platforms for
// fake audio output.
EXPECT_EQ(320, mixer->GetOutputParamsForTesting().frames_per_buffer());
ReturnMixer(mixer);
}
// Verify output bufer size of the mixer is correctly adjusted for Interactive
// latency.
TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyInteractive) {
// Expecting hardware buffer size of 128 frames
EXPECT_EQ(44100,
mock_sink_->GetOutputDeviceInfo().output_params().sample_rate());
// Expecting hardware buffer size of 128 frames
EXPECT_EQ(
128,
mock_sink_->GetOutputDeviceInfo().output_params().frames_per_buffer());
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, kBitsPerChannel, 512);
media::AudioRendererMixer* mixer =
GetMixer(kRenderFrameId, params, AudioLatency::LATENCY_INTERACTIVE,
kDefaultDeviceId, kSecurityOrigin, nullptr);
#if defined(OS_CHROMEOS)
// Expecting input sample rate.
EXPECT_EQ(32000, mixer->GetOutputParamsForTesting().sample_rate());
#else
// Expecting hardware sample rate.
EXPECT_EQ(44100, mixer->GetOutputParamsForTesting().sample_rate());
#endif // defined(OS_CHROMEOS)
#if defined(OS_ANDROID)
// If hardware buffer size (128) is less than 1024, use 2048.
EXPECT_EQ(2048, mixer->GetOutputParamsForTesting().frames_per_buffer());
#else
// Expect hardware buffer size.
EXPECT_EQ(128, mixer->GetOutputParamsForTesting().frames_per_buffer());
#endif
ReturnMixer(mixer);
}
} // namespace content