blob: bf9f3b34543bc0edb5bf39a80cddefb5fd4096d5 [file] [log] [blame]
// 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 <gtest/gtest.h>
#include "src/lib/testing/loop_fixture/test_loop_fixture.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