Commit 72a4baa7 authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Stop using AudioRendererSinkCache for AudioRendererMixerManager.

This is part 3/4 CLs to move the <audio>/<video> elements off of
a synchronous API that can lead to renderer hangs and premature
audio renderer errors.

This moves the AudioRendererSinkCache from AudioRendererMixerManger
to a base::NoDestructor instance in AudioDeviceFactory and stops
ARMM from using the cache at all. The users remaining are WebAudio
and WebRTC, we can reevaluate metrics on keeping it after.

Due to base::(SingleThread|Sequenced)TaskRunner::Get() being
deprecated for content/ I've had to switch to use base::PostTask to
generate a cleanup task runner. Unfortunately this doesn't guarantee
that it runs on the render thread, but since we're now using a static
instance, we can just always use base::Unretained and drop the WeakPtr
factory that was handling the cancellation of these tasks.

There's no point in the cache for ARMM since we're going to require
a sink to get a mixer. That sink will always be used to get output
device info first too and then reused for the mixer.

BUG=905506
TEST=updated tests, compiles.
R=olka

Change-Id: I03408753f974e4c6fb9c89270508e26689162002
Reviewed-on: https://chromium-review.googlesource.com/c/1347730
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612460}
parent 406c33ba
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/task/post_task.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/common/content_constants_internal.h" #include "content/common/content_constants_internal.h"
...@@ -15,6 +17,7 @@ ...@@ -15,6 +17,7 @@
#include "content/renderer/media/audio/audio_input_ipc_factory.h" #include "content/renderer/media/audio/audio_input_ipc_factory.h"
#include "content/renderer/media/audio/audio_output_ipc_factory.h" #include "content/renderer/media/audio/audio_output_ipc_factory.h"
#include "content/renderer/media/audio/audio_renderer_mixer_manager.h" #include "content/renderer/media/audio/audio_renderer_mixer_manager.h"
#include "content/renderer/media/audio/audio_renderer_sink_cache_impl.h"
#include "content/renderer/media/audio/mojo_audio_input_ipc.h" #include "content/renderer/media/audio/mojo_audio_input_ipc.h"
#include "content/renderer/render_frame_impl.h" #include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_thread_impl.h" #include "content/renderer/render_thread_impl.h"
...@@ -182,11 +185,23 @@ AudioDeviceFactory::NewAudioCapturerSource( ...@@ -182,11 +185,23 @@ AudioDeviceFactory::NewAudioCapturerSource(
media::OutputDeviceInfo AudioDeviceFactory::GetOutputDeviceInfo( media::OutputDeviceInfo AudioDeviceFactory::GetOutputDeviceInfo(
int render_frame_id, int render_frame_id,
const media::AudioSinkParameters& params) { const media::AudioSinkParameters& params) {
RenderThreadImpl* render_thread = RenderThreadImpl::current(); DCHECK(RenderThreadImpl::current())
DCHECK(render_thread) << "RenderThreadImpl is not instantiated, or " << "RenderThreadImpl is not instantiated, or "
<< "GetOutputDeviceInfo() is called on a wrong thread "; << "GetOutputDeviceInfo() is called on a wrong thread ";
return render_thread->GetAudioRendererMixerManager()->GetOutputDeviceInfo(
render_frame_id, params.session_id, params.device_id); constexpr base::TimeDelta kDeleteTimeout =
base::TimeDelta::FromMilliseconds(5000);
// There's one process wide instance that lives on the render thread.
static base::NoDestructor<AudioRendererSinkCacheImpl> cache(
base::CreateSequencedTaskRunnerWithTraits(
{base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}),
base::BindRepeating(&AudioDeviceFactory::NewAudioRendererSink,
AudioDeviceFactory::kSourceNone),
kDeleteTimeout);
return cache->GetSinkInfo(render_frame_id, params.session_id,
params.device_id);
} }
AudioDeviceFactory::AudioDeviceFactory() { AudioDeviceFactory::AudioDeviceFactory() {
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/renderer/media/audio/audio_renderer_sink_cache.h" #include "content/renderer/media/audio/audio_device_factory.h"
#include "media/audio/audio_device_description.h" #include "media/audio/audio_device_description.h"
#include "media/base/audio_renderer_mixer.h" #include "media/base/audio_renderer_mixer.h"
#include "media/base/audio_renderer_mixer_input.h" #include "media/base/audio_renderer_mixer_input.h"
...@@ -130,9 +130,9 @@ void LogMixerUmaHistogram(media::AudioLatency::LatencyType latency, int value) { ...@@ -130,9 +130,9 @@ void LogMixerUmaHistogram(media::AudioLatency::LatencyType latency, int value) {
namespace content { namespace content {
AudioRendererMixerManager::AudioRendererMixerManager( AudioRendererMixerManager::AudioRendererMixerManager(
std::unique_ptr<AudioRendererSinkCache> sink_cache) CreateSinkCB create_sink_cb)
: sink_cache_(std::move(sink_cache)) { : create_sink_cb_(std::move(create_sink_cb)) {
DCHECK(sink_cache_); DCHECK(create_sink_cb_);
} }
AudioRendererMixerManager::~AudioRendererMixerManager() { AudioRendererMixerManager::~AudioRendererMixerManager() {
...@@ -143,8 +143,8 @@ AudioRendererMixerManager::~AudioRendererMixerManager() { ...@@ -143,8 +143,8 @@ AudioRendererMixerManager::~AudioRendererMixerManager() {
// static // static
std::unique_ptr<AudioRendererMixerManager> AudioRendererMixerManager::Create() { std::unique_ptr<AudioRendererMixerManager> AudioRendererMixerManager::Create() {
return base::WrapUnique( return base::WrapUnique(new AudioRendererMixerManager(
new AudioRendererMixerManager(AudioRendererSinkCache::Create())); base::BindRepeating(&AudioDeviceFactory::NewAudioRendererMixerSink)));
} }
media::AudioRendererMixerInput* AudioRendererMixerManager::CreateInput( media::AudioRendererMixerInput* AudioRendererMixerManager::CreateInput(
...@@ -197,14 +197,13 @@ media::AudioRendererMixer* AudioRendererMixerManager::GetMixer( ...@@ -197,14 +197,13 @@ media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
return it->second.mixer; return it->second.mixer;
} }
scoped_refptr<media::AudioRendererSink> sink = scoped_refptr<media::AudioRendererSink> sink = create_sink_cb_.Run(
sink_cache_->GetSink(source_render_frame_id, device_id); source_render_frame_id, media::AudioSinkParameters(0, device_id));
const media::OutputDeviceInfo& device_info = sink->GetOutputDeviceInfo(); const media::OutputDeviceInfo& device_info = sink->GetOutputDeviceInfo();
if (device_status) if (device_status)
*device_status = device_info.device_status(); *device_status = device_info.device_status();
if (device_info.device_status() != media::OUTPUT_DEVICE_STATUS_OK) { if (device_info.device_status() != media::OUTPUT_DEVICE_STATUS_OK) {
sink_cache_->ReleaseSink(sink.get());
sink->Stop(); sink->Stop();
return nullptr; return nullptr;
} }
...@@ -212,9 +211,9 @@ media::AudioRendererMixer* AudioRendererMixerManager::GetMixer( ...@@ -212,9 +211,9 @@ media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
const media::AudioParameters& mixer_output_params = const media::AudioParameters& mixer_output_params =
GetMixerOutputParams(input_params, device_info.output_params(), latency); GetMixerOutputParams(input_params, device_info.output_params(), latency);
media::AudioRendererMixer* mixer = new media::AudioRendererMixer( media::AudioRendererMixer* mixer = new media::AudioRendererMixer(
mixer_output_params, sink, base::Bind(LogMixerUmaHistogram, latency)); mixer_output_params, std::move(sink),
AudioRendererMixerReference mixer_reference = {mixer, 1, sink.get()}; base::BindRepeating(LogMixerUmaHistogram, latency));
mixers_[key] = mixer_reference; mixers_[key] = {mixer, 1};
DVLOG(1) << __func__ << " mixer: " << mixer << " latency: " << latency DVLOG(1) << __func__ << " mixer: " << mixer << " latency: " << latency
<< "\n input: " << input_params.AsHumanReadableString() << "\n input: " << input_params.AsHumanReadableString()
<< "\noutput: " << mixer_output_params.AsHumanReadableString(); << "\noutput: " << mixer_output_params.AsHumanReadableString();
...@@ -233,8 +232,6 @@ void AudioRendererMixerManager::ReturnMixer(media::AudioRendererMixer* mixer) { ...@@ -233,8 +232,6 @@ void AudioRendererMixerManager::ReturnMixer(media::AudioRendererMixer* mixer) {
// Only remove the mixer if AudioRendererMixerManager is the last owner. // Only remove the mixer if AudioRendererMixerManager is the last owner.
it->second.ref_count--; it->second.ref_count--;
if (it->second.ref_count == 0) { if (it->second.ref_count == 0) {
// The mixer will be deleted now, so release the sink.
sink_cache_->ReleaseSink(it->second.sink_ptr);
delete it->second.mixer; delete it->second.mixer;
mixers_.erase(it); mixers_.erase(it);
} }
...@@ -244,8 +241,12 @@ media::OutputDeviceInfo AudioRendererMixerManager::GetOutputDeviceInfo( ...@@ -244,8 +241,12 @@ media::OutputDeviceInfo AudioRendererMixerManager::GetOutputDeviceInfo(
int source_render_frame_id, int source_render_frame_id,
int session_id, int session_id,
const std::string& device_id) { const std::string& device_id) {
return sink_cache_->GetSinkInfo(source_render_frame_id, session_id, auto sink =
device_id); create_sink_cb_.Run(source_render_frame_id,
media::AudioSinkParameters(session_id, device_id));
auto info = sink->GetOutputDeviceInfo();
sink->Stop();
return info;
} }
AudioRendererMixerManager::MixerKey::MixerKey( AudioRendererMixerManager::MixerKey::MixerKey(
......
...@@ -10,10 +10,12 @@ ...@@ -10,10 +10,12 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "base/containers/flat_map.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "media/audio/audio_device_description.h" #include "media/audio/audio_device_description.h"
#include "media/audio/audio_sink_parameters.h"
#include "media/base/audio_latency.h" #include "media/base/audio_latency.h"
#include "media/base/audio_parameters.h" #include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_mixer_pool.h" #include "media/base/audio_renderer_mixer_pool.h"
...@@ -26,7 +28,6 @@ class AudioRendererSink; ...@@ -26,7 +28,6 @@ class AudioRendererSink;
} }
namespace content { namespace content {
class AudioRendererSinkCache;
// Manages sharing of an AudioRendererMixer among AudioRendererMixerInputs based // Manages sharing of an AudioRendererMixer among AudioRendererMixerInputs based
// on their AudioParameters configuration. Inputs with the same AudioParameters // on their AudioParameters configuration. Inputs with the same AudioParameters
...@@ -75,8 +76,14 @@ class CONTENT_EXPORT AudioRendererMixerManager ...@@ -75,8 +76,14 @@ class CONTENT_EXPORT AudioRendererMixerManager
const std::string& device_id) final; const std::string& device_id) final;
protected: protected:
explicit AudioRendererMixerManager( // Callback which will be used to create sinks. See AudioDeviceFactory for
std::unique_ptr<AudioRendererSinkCache> sink_cache); // more details on the parameters.
using CreateSinkCB =
base::RepeatingCallback<scoped_refptr<media::AudioRendererSink>(
int source_render_frame_id,
const media::AudioSinkParameters& params)>;
explicit AudioRendererMixerManager(CreateSinkCB create_sink_cb);
private: private:
friend class AudioRendererMixerManagerTest; friend class AudioRendererMixerManagerTest;
...@@ -130,26 +137,23 @@ class CONTENT_EXPORT AudioRendererMixerManager ...@@ -130,26 +137,23 @@ class CONTENT_EXPORT AudioRendererMixerManager
} }
}; };
const CreateSinkCB create_sink_cb_;
// Map of MixerKey to <AudioRendererMixer, Count>. Count allows // Map of MixerKey to <AudioRendererMixer, Count>. Count allows
// AudioRendererMixerManager to keep track explicitly (v.s. RefCounted which // AudioRendererMixerManager to keep track explicitly (v.s. RefCounted which
// is implicit) of the number of outstanding AudioRendererMixers. // is implicit) of the number of outstanding AudioRendererMixers.
struct AudioRendererMixerReference { struct AudioRendererMixerReference {
media::AudioRendererMixer* mixer; media::AudioRendererMixer* mixer;
int ref_count; int ref_count;
// Mixer sink pointer, to remove a sink from cache upon mixer destruction.
const media::AudioRendererSink* sink_ptr;
}; };
using AudioRendererMixerMap = using AudioRendererMixerMap =
std::map<MixerKey, AudioRendererMixerReference, MixerKeyCompare>; base::flat_map<MixerKey, AudioRendererMixerReference, MixerKeyCompare>;
// Active mixers. // Active mixers.
AudioRendererMixerMap mixers_; AudioRendererMixerMap mixers_;
base::Lock mixers_lock_; base::Lock mixers_lock_;
// Mixer sink cache.
const std::unique_ptr<AudioRendererSinkCache> sink_cache_;
// Map of the output latencies encountered throughout mixer manager lifetime. // Map of the output latencies encountered throughout mixer manager lifetime.
// Used for UMA histogram logging. // Used for UMA histogram logging.
std::bitset<media::AudioLatency::LATENCY_COUNT> latency_map_; std::bitset<media::AudioLatency::LATENCY_COUNT> latency_map_;
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/renderer/media/audio/audio_renderer_sink_cache.h"
#include "media/audio/audio_device_description.h" #include "media/audio/audio_device_description.h"
#include "media/base/audio_parameters.h" #include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_mixer.h" #include "media/base/audio_renderer_mixer.h"
...@@ -43,53 +42,12 @@ const int kAnotherRenderFrameId = 678; ...@@ -43,53 +42,12 @@ const int kAnotherRenderFrameId = 678;
using media::AudioParameters; using media::AudioParameters;
using media::AudioLatency; 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)>;
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) final {
return get_sink_cb_.Run(source_render_frame_id, session_id, device_id)
->GetOutputDeviceInfo();
}
scoped_refptr<media::AudioRendererSink> GetSink(
int source_render_frame_id,
const std::string& device_id) final {
return get_sink_cb_.Run(source_render_frame_id, 0, device_id);
}
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 { class AudioRendererMixerManagerTest : public testing::Test {
public: public:
AudioRendererMixerManagerTest() AudioRendererMixerManagerTest()
: manager_(new AudioRendererMixerManager( : manager_(new AudioRendererMixerManager(
std::unique_ptr<AudioRendererSinkCache>( base::BindRepeating(&AudioRendererMixerManagerTest::GetSink,
new FakeAudioRendererSinkCache( base::Unretained(this)))),
base::Bind(&AudioRendererMixerManagerTest::GetSinkPtr,
base::Unretained(this)),
base::Bind(&AudioRendererMixerManagerTest::ReleaseSinkPtr,
base::Unretained(this)))))),
mock_sink_(new media::MockAudioRendererSink( mock_sink_(new media::MockAudioRendererSink(
kDefaultDeviceId, kDefaultDeviceId,
media::OUTPUT_DEVICE_STATUS_OK, media::OUTPUT_DEVICE_STATUS_OK,
...@@ -119,34 +77,30 @@ class AudioRendererMixerManagerTest : public testing::Test { ...@@ -119,34 +77,30 @@ class AudioRendererMixerManagerTest : public testing::Test {
} }
// Number of instantiated mixers. // Number of instantiated mixers.
int mixer_count() { int mixer_count() { return manager_->mixers_.size(); }
return manager_->mixers_.size();
}
protected: protected:
scoped_refptr<media::AudioRendererSink> GetSinkPtr( scoped_refptr<media::AudioRendererSink> GetSink(
int source_render_frame_id, int source_render_frame_id,
int session_id, const media::AudioSinkParameters& params) {
const std::string& device_id) { if ((params.device_id == kDefaultDeviceId) ||
if ((device_id == kDefaultDeviceId) || (device_id == kAnotherDeviceId)) { (params.device_id == kAnotherDeviceId)) {
// We don't care about separate sinks for these devices. // We don't care about separate sinks for these devices.
return mock_sink_; return mock_sink_;
} }
if (device_id == kNonexistentDeviceId) if (params.device_id == kNonexistentDeviceId)
return mock_sink_no_device_; return mock_sink_no_device_;
if (device_id.empty()) { if (params.device_id.empty()) {
// The sink used to get device ID from session ID if it's not 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_; return params.session_id ? mock_sink_matched_device_ : mock_sink_;
} }
if (device_id == kMatchedDeviceId) if (params.device_id == kMatchedDeviceId)
return mock_sink_matched_device_; return mock_sink_matched_device_;
NOTREACHED(); NOTREACHED();
return nullptr; return nullptr;
} }
MOCK_METHOD1(ReleaseSinkPtr, void(const media::AudioRendererSink*));
std::unique_ptr<AudioRendererMixerManager> manager_; std::unique_ptr<AudioRendererMixerManager> manager_;
scoped_refptr<media::MockAudioRendererSink> mock_sink_; scoped_refptr<media::MockAudioRendererSink> mock_sink_;
...@@ -165,9 +119,6 @@ TEST_F(AudioRendererMixerManagerTest, GetReturnMixer) { ...@@ -165,9 +119,6 @@ TEST_F(AudioRendererMixerManagerTest, GetReturnMixer) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
EXPECT_CALL(*mock_sink_.get(), Stop()).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. // There should be no mixers outstanding to start with.
EXPECT_EQ(0, mixer_count()); EXPECT_EQ(0, mixer_count());
...@@ -216,9 +167,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerReuse) { ...@@ -216,9 +167,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerReuse) {
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);
EXPECT_EQ(mixer_count(), 0); 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, media::AudioParameters params1(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kChannelLayout,
kSampleRate, kSampleRate,
...@@ -272,9 +220,6 @@ TEST_F(AudioRendererMixerManagerTest, CreateInput) { ...@@ -272,9 +220,6 @@ TEST_F(AudioRendererMixerManagerTest, CreateInput) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(2); EXPECT_CALL(*mock_sink_.get(), Start()).Times(2);
EXPECT_CALL(*mock_sink_.get(), Stop()).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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBufferSize); kChannelLayout, kSampleRate, kBufferSize);
...@@ -310,7 +255,11 @@ TEST_F(AudioRendererMixerManagerTest, CreateInput) { ...@@ -310,7 +255,11 @@ TEST_F(AudioRendererMixerManagerTest, CreateInput) {
// Verify CreateInput() provided with session id creates AudioRendererMixerInput // Verify CreateInput() provided with session id creates AudioRendererMixerInput
// with the appropriate callbacks and they are working as expected. // with the appropriate callbacks and they are working as expected.
TEST_F(AudioRendererMixerManagerTest, CreateInputWithSessionId) { //
// TODO(grunell): |session_id| support currently requires calling the
// synchronous GetOutputDeviceInfo call, this is not allowed. So this test is
// disabled. This should be deleted in the future, https://crbug.com/870836.
TEST_F(AudioRendererMixerManagerTest, DISABLED_CreateInputWithSessionId) {
// Expect AudioRendererMixerManager to call Start and Stop on our mock twice // Expect AudioRendererMixerManager to call Start and Stop on our mock twice
// each: for kDefaultDeviceId and for kAnotherDeviceId. Note: Under normal // each: for kDefaultDeviceId and for kAnotherDeviceId. Note: Under normal
// conditions, each mixer would get its own sink! // conditions, each mixer would get its own sink!
...@@ -322,10 +271,6 @@ TEST_F(AudioRendererMixerManagerTest, CreateInputWithSessionId) { ...@@ -322,10 +271,6 @@ TEST_F(AudioRendererMixerManagerTest, CreateInputWithSessionId) {
EXPECT_CALL(*mock_sink_matched_device_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_matched_device_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_matched_device_.get(), Stop()).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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBufferSize); kChannelLayout, kSampleRate, kBufferSize);
media::FakeAudioRenderCallback callback(0, kSampleRate); media::FakeAudioRenderCallback callback(0, kSampleRate);
...@@ -397,9 +342,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerDevices) { ...@@ -397,9 +342,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerDevices) {
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2); EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);
EXPECT_EQ(0, mixer_count()); EXPECT_EQ(0, mixer_count());
// We expect 2 mixers to be created; each of them should release a sink.
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(2);
media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBufferSize); kChannelLayout, kSampleRate, kBufferSize);
media::AudioRendererMixer* mixer1 = media::AudioRendererMixer* mixer1 =
...@@ -428,9 +370,6 @@ TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentDefaultDeviceIDs) { ...@@ -428,9 +370,6 @@ TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentDefaultDeviceIDs) {
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_EQ(0, mixer_count()); 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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBufferSize); kChannelLayout, kSampleRate, kBufferSize);
media::AudioRendererMixer* mixer1 = media::AudioRendererMixer* mixer1 =
...@@ -457,9 +396,6 @@ TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentDefaultDeviceIDs) { ...@@ -457,9 +396,6 @@ TEST_F(AudioRendererMixerManagerTest, OneMixerDifferentDefaultDeviceIDs) {
TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) { TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) {
EXPECT_EQ(0, mixer_count()); 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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, kSampleRate, kBufferSize); kChannelLayout, kSampleRate, kBufferSize);
media::OutputDeviceStatus device_status = media::OUTPUT_DEVICE_STATUS_OK; media::OutputDeviceStatus device_status = media::OUTPUT_DEVICE_STATUS_OK;
...@@ -478,7 +414,6 @@ TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) { ...@@ -478,7 +414,6 @@ TEST_F(AudioRendererMixerManagerTest, NonexistentDevice) {
TEST_F(AudioRendererMixerManagerTest, LatencyMixing) { TEST_F(AudioRendererMixerManagerTest, LatencyMixing) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(3); EXPECT_CALL(*mock_sink_.get(), Start()).Times(3);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3); EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(3);
EXPECT_EQ(0, mixer_count()); EXPECT_EQ(0, mixer_count());
...@@ -541,7 +476,6 @@ TEST_F(AudioRendererMixerManagerTest, LatencyMixing) { ...@@ -541,7 +476,6 @@ TEST_F(AudioRendererMixerManagerTest, LatencyMixing) {
TEST_F(AudioRendererMixerManagerTest, EffectsMixing) { TEST_F(AudioRendererMixerManagerTest, EffectsMixing) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(3); EXPECT_CALL(*mock_sink_.get(), Start()).Times(3);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3); EXPECT_CALL(*mock_sink_.get(), Stop()).Times(3);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(3);
EXPECT_EQ(0, mixer_count()); EXPECT_EQ(0, mixer_count());
...@@ -615,7 +549,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlayback) { ...@@ -615,7 +549,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlayback) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, 512); kChannelLayout, 32000, 512);
...@@ -658,7 +591,6 @@ TEST_F(AudioRendererMixerManagerTest, ...@@ -658,7 +591,6 @@ TEST_F(AudioRendererMixerManagerTest,
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, 512); kChannelLayout, 32000, 512);
...@@ -692,7 +624,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlaybackFakeAudio) { ...@@ -692,7 +624,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyPlaybackFakeAudio) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, 512); kChannelLayout, 32000, 512);
...@@ -728,7 +659,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtc) { ...@@ -728,7 +659,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtc) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, 512); kChannelLayout, 32000, 512);
...@@ -770,7 +700,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtcFakeAudio) { ...@@ -770,7 +700,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyRtcFakeAudio) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, 512); kChannelLayout, 32000, 512);
...@@ -802,7 +731,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyInteractive) { ...@@ -802,7 +731,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsLatencyInteractive) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).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, media::AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
kChannelLayout, 32000, 512); kChannelLayout, 32000, 512);
...@@ -835,7 +763,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsBitstreamFormat) { ...@@ -835,7 +763,6 @@ TEST_F(AudioRendererMixerManagerTest, MixerParamsBitstreamFormat) {
EXPECT_CALL(*mock_sink_.get(), Start()).Times(1); EXPECT_CALL(*mock_sink_.get(), Start()).Times(1);
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1); EXPECT_CALL(*mock_sink_.get(), Stop()).Times(1);
EXPECT_CALL(*this, ReleaseSinkPtr(mock_sink_.get())).Times(1);
media::AudioParameters params(AudioParameters::AUDIO_BITSTREAM_EAC3, media::AudioParameters params(AudioParameters::AUDIO_BITSTREAM_EAC3,
kAnotherChannelLayout, 32000, 512); kAnotherChannelLayout, 32000, 512);
......
...@@ -27,9 +27,6 @@ class CONTENT_EXPORT AudioRendererSinkCache { ...@@ -27,9 +27,6 @@ class CONTENT_EXPORT AudioRendererSinkCache {
public: public:
virtual ~AudioRendererSinkCache() {} virtual ~AudioRendererSinkCache() {}
// Creates default cache, to be used by AudioRendererMixerManager.
static std::unique_ptr<AudioRendererSinkCache> Create();
// If called, the cache will drop sinks belonging to the specified frame on // If called, the cache will drop sinks belonging to the specified frame on
// navigation. // navigation.
static void ObserveFrame(RenderFrame* frame); static void ObserveFrame(RenderFrame* frame);
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/task/post_task.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_observer.h"
...@@ -25,14 +25,13 @@ ...@@ -25,14 +25,13 @@
namespace content { namespace content {
AudioRendererSinkCacheImpl* AudioRendererSinkCacheImpl::instance_ = nullptr; AudioRendererSinkCacheImpl* AudioRendererSinkCacheImpl::instance_ = nullptr;
constexpr int kDeleteTimeoutMs = 5000;
constexpr int kDefaultSessionId = 0; constexpr int kDefaultSessionId = 0;
class AudioRendererSinkCacheImpl::FrameObserver : public RenderFrameObserver { class AudioRendererSinkCacheImpl::FrameObserver : public RenderFrameObserver {
public: public:
explicit FrameObserver(content::RenderFrame* render_frame) explicit FrameObserver(content::RenderFrame* render_frame)
: RenderFrameObserver(render_frame) {} : RenderFrameObserver(render_frame) {}
~FrameObserver() override{}; ~FrameObserver() override {}
private: private:
// content::RenderFrameObserver implementation: // content::RenderFrameObserver implementation:
...@@ -87,36 +86,23 @@ struct AudioRendererSinkCacheImpl::CacheEntry { ...@@ -87,36 +86,23 @@ struct AudioRendererSinkCacheImpl::CacheEntry {
bool used; // True if in use by a client. bool used; // True if in use by a client.
}; };
// static
std::unique_ptr<AudioRendererSinkCache> AudioRendererSinkCache::Create() {
return std::make_unique<AudioRendererSinkCacheImpl>(
base::ThreadTaskRunnerHandle::Get(),
base::Bind(&AudioDeviceFactory::NewAudioRendererMixerSink),
base::TimeDelta::FromMilliseconds(kDeleteTimeoutMs));
}
// static // static
void AudioRendererSinkCache::ObserveFrame(RenderFrame* frame) { void AudioRendererSinkCache::ObserveFrame(RenderFrame* frame) {
new AudioRendererSinkCacheImpl::FrameObserver(frame); new AudioRendererSinkCacheImpl::FrameObserver(frame);
} }
AudioRendererSinkCacheImpl::AudioRendererSinkCacheImpl( AudioRendererSinkCacheImpl::AudioRendererSinkCacheImpl(
scoped_refptr<base::SingleThreadTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> cleanup_task_runner,
CreateSinkCallback create_sink_cb, CreateSinkCallback create_sink_cb,
base::TimeDelta delete_timeout) base::TimeDelta delete_timeout)
: task_runner_(std::move(task_runner)), : cleanup_task_runner_(std::move(cleanup_task_runner)),
create_sink_cb_(std::move(create_sink_cb)), create_sink_cb_(std::move(create_sink_cb)),
delete_timeout_(delete_timeout), delete_timeout_(delete_timeout) {
weak_ptr_factory_(this) { DCHECK(!instance_);
weak_this_ = weak_ptr_factory_.GetWeakPtr();
if (instance_)
LOG(ERROR) << "More that one AudioRendererSinkCache instance created. "
"Allowed in tests only.";
instance_ = this; instance_ = this;
} }
AudioRendererSinkCacheImpl::~AudioRendererSinkCacheImpl() { AudioRendererSinkCacheImpl::~AudioRendererSinkCacheImpl() {
DCHECK(task_runner_->BelongsToCurrentThread());
// We just release all the cached sinks here. Stop them first. // We just release all the cached sinks here. Stop them first.
// We can stop all the sinks, no matter they are used or not, since everything // We can stop all the sinks, no matter they are used or not, since everything
// is being destroyed anyways. // is being destroyed anyways.
...@@ -238,10 +224,12 @@ void AudioRendererSinkCacheImpl::ReleaseSink( ...@@ -238,10 +224,12 @@ void AudioRendererSinkCacheImpl::ReleaseSink(
void AudioRendererSinkCacheImpl::DeleteLaterIfUnused( void AudioRendererSinkCacheImpl::DeleteLaterIfUnused(
const media::AudioRendererSink* sink_ptr) { const media::AudioRendererSink* sink_ptr) {
task_runner_->PostDelayedTask( cleanup_task_runner_->PostDelayedTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&AudioRendererSinkCacheImpl::DeleteSink, weak_this_, base::BindOnce(&AudioRendererSinkCacheImpl::DeleteSink,
base::RetainedRef(sink_ptr), // Unretained is safe here since this is a process-wide
// singleton and tests will ensure lifetime.
base::Unretained(this), base::RetainedRef(sink_ptr),
false /*do not delete if used*/), false /*do not delete if used*/),
delete_timeout_); delete_timeout_);
} }
......
...@@ -11,8 +11,7 @@ ...@@ -11,8 +11,7 @@
#include <vector> #include <vector>
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
...@@ -32,8 +31,11 @@ class CONTENT_EXPORT AudioRendererSinkCacheImpl ...@@ -32,8 +31,11 @@ class CONTENT_EXPORT AudioRendererSinkCacheImpl
int render_frame_id, int render_frame_id,
const media::AudioSinkParameters& params)>; const media::AudioSinkParameters& params)>;
// |cleanup_task_runner| will be used to delete sinks when they are unused,
// AudioRendererSinkCacheImpl must outlive any tasks posted to it. Since
// the sink cache is normally a process-wide singleton, this isn't a problem.
AudioRendererSinkCacheImpl( AudioRendererSinkCacheImpl(
scoped_refptr<base::SingleThreadTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> cleanup_task_runner,
CreateSinkCallback create_sink_callback, CreateSinkCallback create_sink_callback,
base::TimeDelta delete_timeout); base::TimeDelta delete_timeout);
...@@ -85,7 +87,7 @@ class CONTENT_EXPORT AudioRendererSinkCacheImpl ...@@ -85,7 +87,7 @@ class CONTENT_EXPORT AudioRendererSinkCacheImpl
static AudioRendererSinkCacheImpl* instance_; static AudioRendererSinkCacheImpl* instance_;
// Renderer main task runner. // Renderer main task runner.
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; const scoped_refptr<base::SequencedTaskRunner> cleanup_task_runner_;
// Callback used for sink creation. // Callback used for sink creation.
const CreateSinkCallback create_sink_cb_; const CreateSinkCallback create_sink_cb_;
...@@ -102,17 +104,6 @@ class CONTENT_EXPORT AudioRendererSinkCacheImpl ...@@ -102,17 +104,6 @@ class CONTENT_EXPORT AudioRendererSinkCacheImpl
base::Lock cache_lock_; base::Lock cache_lock_;
CacheContainer cache_; CacheContainer cache_;
// Weak pointer to be used for delayed sink deletion on |task_runner_|.
// Pre-created in constructor and is used to post all the delayed tasks.
// A delayed task can be concurrently posted from any thread the cache is used
// on, so on-the-flight weak pointer creation with
// weak_ptr_factory_.GetWeakPtr() can't be used, because it will result in the
// racy access to the factory.
base::WeakPtr<AudioRendererSinkCacheImpl> weak_this_;
// Used to produce |weak_this_| on AudioRendererSinkCacheImpl construction.
base::WeakPtrFactory<AudioRendererSinkCacheImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AudioRendererSinkCacheImpl); DISALLOW_COPY_AND_ASSIGN(AudioRendererSinkCacheImpl);
}; };
......
...@@ -40,6 +40,9 @@ class AudioRendererSinkCacheTest : public testing::Test { ...@@ -40,6 +40,9 @@ class AudioRendererSinkCacheTest : public testing::Test {
base::BindRepeating(&AudioRendererSinkCacheTest::CreateSink, base::BindRepeating(&AudioRendererSinkCacheTest::CreateSink,
base::Unretained(this)), base::Unretained(this)),
kDeleteTimeout)) {} kDeleteTimeout)) {}
~AudioRendererSinkCacheTest() override {
task_env_.FastForwardUntilNoTasksRemain();
}
void GetSink(int render_frame_id, void GetSink(int render_frame_id,
const std::string& device_id, const std::string& device_id,
...@@ -245,6 +248,7 @@ TEST_F(AudioRendererSinkCacheTest, UnhealthySinkIsStopped) { ...@@ -245,6 +248,7 @@ TEST_F(AudioRendererSinkCacheTest, UnhealthySinkIsStopped) {
new media::MockAudioRendererSink( new media::MockAudioRendererSink(
kUnhealthyDeviceId, media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); kUnhealthyDeviceId, media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
cache_.reset(); // Destruct first so there's only one cache at a time.
cache_ = std::make_unique<AudioRendererSinkCacheImpl>( cache_ = std::make_unique<AudioRendererSinkCacheImpl>(
task_env_.GetMainThreadTaskRunner(), task_env_.GetMainThreadTaskRunner(),
base::BindRepeating( base::BindRepeating(
...@@ -271,6 +275,7 @@ TEST_F(AudioRendererSinkCacheTest, UnhealthySinkUsingSessionIdIsStopped) { ...@@ -271,6 +275,7 @@ TEST_F(AudioRendererSinkCacheTest, UnhealthySinkUsingSessionIdIsStopped) {
new media::MockAudioRendererSink( new media::MockAudioRendererSink(
kUnhealthyDeviceId, media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); kUnhealthyDeviceId, media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
cache_.reset(); // Destruct first so there's only one cache at a time.
cache_ = std::make_unique<AudioRendererSinkCacheImpl>( cache_ = std::make_unique<AudioRendererSinkCacheImpl>(
task_env_.GetMainThreadTaskRunner(), task_env_.GetMainThreadTaskRunner(),
base::BindRepeating( base::BindRepeating(
......
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