| // Copyright 2020 The Fuchsia 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 "src/media/audio/audio_core/usage_gain_reporter_impl.h" |
| |
| #include <lib/fidl/cpp/binding.h> |
| |
| #include <gtest/gtest.h> |
| |
| #include "src/media/audio/audio_core/testing/threading_model_fixture.h" |
| #include "src/media/audio/lib/logging/logging.h" |
| |
| namespace media::audio { |
| namespace { |
| |
| const std::string DEVICE_ID_STRING = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"; |
| const audio_stream_unique_id_t DEVICE_ID_AUDIO_STREAM = |
| AudioDevice::UniqueIdFromString(DEVICE_ID_STRING).take_value(); |
| |
| const std::string BLUETOOTH_DEVICE_ID_STRING = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; |
| const audio_stream_unique_id_t BLUETOOTH_DEVICE_ID_AUDIO_STREAM = |
| AudioDevice::UniqueIdFromString(BLUETOOTH_DEVICE_ID_STRING).take_value(); |
| |
| class FakeGainListener : public fuchsia::media::UsageGainListener { |
| public: |
| fidl::InterfaceHandle<fuchsia::media::UsageGainListener> NewBinding() { |
| return binding_.NewBinding(); |
| } |
| |
| void CloseBinding() { binding_.Close(0); } |
| |
| bool muted() const { return last_muted_; } |
| |
| float gain_dbfs() const { return last_gain_dbfs_; } |
| |
| size_t call_count() const { return call_count_; } |
| |
| private: |
| // |fuchsia::media::UsageGainListener| |
| void OnGainMuteChanged(bool muted, float gain_dbfs, OnGainMuteChangedCallback callback) final { |
| last_muted_ = muted; |
| last_gain_dbfs_ = gain_dbfs; |
| call_count_++; |
| } |
| |
| fidl::Binding<fuchsia::media::UsageGainListener> binding_{this}; |
| bool last_muted_ = false; |
| float last_gain_dbfs_ = 0.0; |
| size_t call_count_ = 0; |
| }; |
| |
| class TestDeviceRegistry : public DeviceRegistry { |
| public: |
| void AddDeviceInfo(fuchsia::media::AudioDeviceInfo device_info) { |
| device_info_.push_back(device_info); |
| } |
| |
| // |DeviceRegistry| |
| void AddDevice(const std::shared_ptr<AudioDevice>& device) final {} |
| void ActivateDevice(const std::shared_ptr<AudioDevice>& device) final {} |
| void RemoveDevice(const std::shared_ptr<AudioDevice>& device) final {} |
| void OnPlugStateChanged(const std::shared_ptr<AudioDevice>& device, bool plugged, |
| zx::time plug_time) final {} |
| std::vector<fuchsia::media::AudioDeviceInfo> GetDeviceInfos() final { return device_info_; } |
| |
| private: |
| std::vector<fuchsia::media::AudioDeviceInfo> device_info_; |
| }; |
| |
| } // namespace |
| |
| class UsageGainReporterTest : public gtest::TestLoopFixture { |
| protected: |
| UsageGainReporterTest() |
| : process_config_( |
| ProcessConfigBuilder() |
| .SetDefaultVolumeCurve(VolumeCurve::DefaultForMinGain(-60.0)) |
| .AddDeviceProfile({std::vector<audio_stream_unique_id_t>{DEVICE_ID_AUDIO_STREAM}, |
| DeviceConfig::OutputDeviceProfile( |
| /* eligible_for_loopback=*/true, /*supported_usages=*/{})}) |
| .AddDeviceProfile( |
| {std::vector<audio_stream_unique_id_t>{BLUETOOTH_DEVICE_ID_AUDIO_STREAM}, |
| DeviceConfig::OutputDeviceProfile( |
| /* eligible_for_loopback=*/true, |
| /*supported_usages=*/{}, VolumeCurve::DefaultForMinGain(-60.0), |
| /* independent_volume_control=*/true, PipelineConfig::Default(), |
| /*driver_gain_db=*/0.0)}) |
| .Build()), |
| usage_(fuchsia::media::Usage::WithRenderUsage(fuchsia::media::AudioRenderUsage::MEDIA)) {} |
| |
| std::unique_ptr<FakeGainListener> Listen(std::string device_id) { |
| const auto handle = ProcessConfig::set_instance(process_config_); |
| |
| auto device_registry = std::make_unique<TestDeviceRegistry>(); |
| device_registry->AddDeviceInfo({.unique_id = device_id}); |
| |
| stream_volume_manager_ = std::make_unique<StreamVolumeManager>(dispatcher()); |
| under_test_ = std::make_unique<UsageGainReporterImpl>( |
| *device_registry.get(), *stream_volume_manager_.get(), process_config_); |
| |
| auto fake_gain_listener = std::make_unique<FakeGainListener>(); |
| under_test_->RegisterListener(device_id, fidl::Clone(usage_), fake_gain_listener->NewBinding()); |
| |
| return fake_gain_listener; |
| } |
| |
| size_t NumListeners() { return under_test_->listeners_.size(); } |
| |
| std::unique_ptr<StreamVolumeManager> stream_volume_manager_; |
| std::unique_ptr<UsageGainReporterImpl> under_test_; |
| ProcessConfig process_config_; |
| const fuchsia::media::Usage usage_; |
| }; |
| |
| TEST_F(UsageGainReporterTest, UpdatesSingleListenerUsageGain) { |
| auto fake_listener = Listen(DEVICE_ID_STRING); |
| const float expected_gain_dbfs = -10.0; |
| stream_volume_manager_->SetUsageGain(fidl::Clone(usage_), expected_gain_dbfs); |
| |
| RunLoopUntilIdle(); |
| EXPECT_FLOAT_EQ(fake_listener->gain_dbfs(), expected_gain_dbfs); |
| EXPECT_EQ(fake_listener->call_count(), 2u); |
| } |
| |
| TEST_F(UsageGainReporterTest, UpdatesSingleListenerUsageGainAdjustment) { |
| auto fake_listener = Listen(DEVICE_ID_STRING); |
| const float expected_gain_dbfs = -10.0; |
| stream_volume_manager_->SetUsageGainAdjustment(fidl::Clone(usage_), expected_gain_dbfs); |
| |
| RunLoopUntilIdle(); |
| EXPECT_FLOAT_EQ(fake_listener->gain_dbfs(), expected_gain_dbfs); |
| EXPECT_EQ(fake_listener->call_count(), 2u); |
| } |
| |
| TEST_F(UsageGainReporterTest, UpdatesSingleListenerUsageGainCombination) { |
| auto fake_listener = Listen(DEVICE_ID_STRING); |
| const float expected_gain_dbfs = -10.0; |
| stream_volume_manager_->SetUsageGain(fidl::Clone(usage_), expected_gain_dbfs); |
| stream_volume_manager_->SetUsageGainAdjustment(fidl::Clone(usage_), expected_gain_dbfs); |
| |
| RunLoopUntilIdle(); |
| EXPECT_FLOAT_EQ(fake_listener->gain_dbfs(), (2 * expected_gain_dbfs)); |
| EXPECT_EQ(fake_listener->call_count(), 3u); |
| } |
| |
| TEST_F(UsageGainReporterTest, NoUpdateIndependentVolumeControlSingleListener) { |
| auto fake_listener = Listen(BLUETOOTH_DEVICE_ID_STRING); |
| const float attempted_gain_dbfs = -10.0; |
| stream_volume_manager_->SetUsageGain(fidl::Clone(usage_), attempted_gain_dbfs); |
| |
| RunLoopUntilIdle(); |
| EXPECT_FLOAT_EQ(fake_listener->gain_dbfs(), 0.0f); |
| EXPECT_EQ(fake_listener->call_count(), 0u); |
| } |
| |
| TEST_F(UsageGainReporterTest, HandlesClosedChannel) { |
| auto fake_listener = Listen(DEVICE_ID_STRING); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(fake_listener->call_count(), 1u); |
| EXPECT_EQ(NumListeners(), 1ul); |
| |
| fake_listener->CloseBinding(); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(NumListeners(), 0ul); |
| |
| // Destruct. |
| fake_listener = nullptr; |
| |
| // Verify we removed the listener from StreamVolumeManager. |
| // If we did not, this will crash. |
| stream_volume_manager_->SetUsageGain( |
| fuchsia::media::Usage::WithRenderUsage(fuchsia::media::AudioRenderUsage::MEDIA), 0.42); |
| } |
| |
| } // namespace media::audio |