| // Copyright 2019 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_reporter_impl.h" |
| |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/gtest/test_loop_fixture.h> |
| |
| #include <gtest/gtest.h> |
| |
| #include "src/media/audio/audio_core/usage_settings.h" |
| |
| namespace media::audio { |
| |
| const auto kMediaUsage = |
| fuchsia::media::Usage::WithRenderUsage(fuchsia::media::AudioRenderUsage::MEDIA); |
| const auto kMutedState = fuchsia::media::UsageState::WithMuted({}); |
| const auto kUnadjustedState = fuchsia::media::UsageState::WithUnadjusted({}); |
| const auto kActivateCallback = true; |
| const auto kDeactivateCallback = false; |
| |
| class FakeUsageWatcher : public fuchsia::media::UsageWatcher { |
| public: |
| explicit FakeUsageWatcher(bool activate_callback) : activate_callback_(activate_callback){}; |
| |
| const fuchsia::media::Usage& last_usage() const { return last_usage_; } |
| |
| const fuchsia::media::UsageState& last_usage_state() const { return last_usage_state_; } |
| |
| private: |
| void OnStateChanged(fuchsia::media::Usage usage, fuchsia::media::UsageState usage_state, |
| OnStateChangedCallback callback) override { |
| last_usage_ = std::move(usage); |
| last_usage_state_ = std::move(usage_state); |
| |
| if (activate_callback_) { |
| callback(); |
| } |
| } |
| |
| bool activate_callback_; |
| fuchsia::media::Usage last_usage_; |
| fuchsia::media::UsageState last_usage_state_; |
| }; |
| |
| class UsageReporterImplTest : public gtest::TestLoopFixture { |
| protected: |
| fidl::Binding<fuchsia::media::UsageWatcher, std::unique_ptr<FakeUsageWatcher>> Watch( |
| fuchsia::media::Usage usage, bool activate_callback) { |
| fidl::InterfaceHandle<fuchsia::media::UsageWatcher> state_watcher_handle; |
| auto request = state_watcher_handle.NewRequest(); |
| usage_reporter_->Watch(std::move(usage), std::move(state_watcher_handle)); |
| return fidl::Binding(std::make_unique<FakeUsageWatcher>(activate_callback), std::move(request)); |
| } |
| |
| bool AcksComplete(const fuchsia::media::Usage& usage) { |
| auto& set = usage_reporter_impl_.watcher_set(usage); |
| for (auto& watcher : set.watchers) { |
| if (watcher.second.outstanding_ack_count != 0) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool WatchersDisconnected(const fuchsia::media::Usage& usage) { |
| auto& set = usage_reporter_impl_.watcher_set(usage); |
| return set.watchers.empty(); |
| } |
| |
| UsageReporterImpl usage_reporter_impl_; |
| AudioAdmin::PolicyActionReporter* policy_action_reporter_ = &usage_reporter_impl_; |
| fuchsia::media::UsageReporter* usage_reporter_ = &usage_reporter_impl_; |
| const int kMaxStates = UsageReporterImpl::MAX_STATES; |
| }; |
| |
| TEST_F(UsageReporterImplTest, StateIsEmittedToWatcher) { |
| auto watcher = Watch(fidl::Clone(kMediaUsage), kActivateCallback); |
| |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(fidl::Equals(watcher.impl()->last_usage(), kMediaUsage)); |
| EXPECT_TRUE(fidl::Equals(watcher.impl()->last_usage_state(), kMutedState)); |
| EXPECT_TRUE(AcksComplete(kMediaUsage)); |
| } |
| |
| TEST_F(UsageReporterImplTest, StatesAreEmittedToWatcher) { |
| auto watcher = Watch(fidl::Clone(kMediaUsage), kActivateCallback); |
| |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(fidl::Equals(watcher.impl()->last_usage(), kMediaUsage)); |
| EXPECT_TRUE(fidl::Equals(watcher.impl()->last_usage_state(), kMutedState)); |
| EXPECT_TRUE(AcksComplete(kMediaUsage)); |
| } |
| |
| TEST_F(UsageReporterImplTest, ErrorHandlerDisconnectsWatcher) { |
| // Watcher dropped after block scope to trigger error handler. |
| { |
| auto watcher = Watch(fidl::Clone(kMediaUsage), kDeactivateCallback); |
| |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| |
| EXPECT_FALSE(WatchersDisconnected(kMediaUsage)); |
| } |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(WatchersDisconnected(kMediaUsage)); |
| } |
| |
| TEST_F(UsageReporterImplTest, StateIsEmittedToAllWatchers) { |
| auto watcher1 = Watch(fidl::Clone(kMediaUsage), kActivateCallback); |
| auto watcher2 = Watch(fidl::Clone(kMediaUsage), kActivateCallback); |
| |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(fidl::Equals(watcher1.impl()->last_usage(), kMediaUsage)); |
| EXPECT_TRUE(fidl::Equals(watcher1.impl()->last_usage_state(), kMutedState)); |
| EXPECT_TRUE(fidl::Equals(watcher2.impl()->last_usage(), kMediaUsage)); |
| EXPECT_TRUE(fidl::Equals(watcher2.impl()->last_usage_state(), kMutedState)); |
| EXPECT_TRUE(AcksComplete(kMediaUsage)); |
| } |
| |
| TEST_F(UsageReporterImplTest, StatesAreEmittedToAllWatchers) { |
| auto watcher1 = Watch(fidl::Clone(kMediaUsage), kActivateCallback); |
| auto watcher2 = Watch(fidl::Clone(kMediaUsage), kActivateCallback); |
| |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(fidl::Equals(watcher1.impl()->last_usage(), kMediaUsage)); |
| EXPECT_TRUE(fidl::Equals(watcher1.impl()->last_usage_state(), kMutedState)); |
| EXPECT_TRUE(fidl::Equals(watcher2.impl()->last_usage(), kMediaUsage)); |
| EXPECT_TRUE(fidl::Equals(watcher2.impl()->last_usage_state(), kMutedState)); |
| EXPECT_TRUE(AcksComplete(kMediaUsage)); |
| } |
| |
| TEST_F(UsageReporterImplTest, WatchersThatDontReplyAreDisconnected) { |
| auto watcher1 = Watch(fidl::Clone(kMediaUsage), kDeactivateCallback); |
| auto watcher2 = Watch(fidl::Clone(kMediaUsage), kDeactivateCallback); |
| |
| // Report up to kMaxStates and allow watchers to ack if enabled. |
| for (int i = 0; i < kMaxStates; ++i) { |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| } |
| RunLoopUntilIdle(); |
| EXPECT_FALSE(WatchersDisconnected(kMediaUsage)); |
| |
| // Report additional state to reach kMaxStates and cause disconnect of un-acking watchers. |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(WatchersDisconnected(kMediaUsage)); |
| } |
| |
| TEST_F(UsageReporterImplTest, WatchersReceiveCachedState) { |
| // The watcher should receive the current state on connection. |
| auto watcher1 = Watch(fidl::Clone(kMediaUsage), kActivateCallback); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(fidl::Equals(watcher1.impl()->last_usage(), kMediaUsage)); |
| EXPECT_TRUE(fidl::Equals(watcher1.impl()->last_usage_state(), kUnadjustedState)); |
| |
| policy_action_reporter_->ReportPolicyAction(fidl::Clone(kMediaUsage), |
| fuchsia::media::Behavior::MUTE); |
| |
| // The new watcher should receive the current state when it connects, and that state should be |
| // updated by the policy action. |
| auto watcher2 = Watch(fidl::Clone(kMediaUsage), kActivateCallback); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(fidl::Equals(watcher2.impl()->last_usage(), kMediaUsage)); |
| EXPECT_TRUE(fidl::Equals(watcher2.impl()->last_usage_state(), kMutedState)); |
| EXPECT_TRUE(AcksComplete(kMediaUsage)); |
| } |
| |
| } // namespace media::audio |