blob: 68e6ea695bc5f408f0c65a0183a6a8c42f804bc1 [file] [log] [blame]
// 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/activity_dispatcher.h"
#include <optional>
namespace media::audio {
namespace {
using fuchsia::media::AudioRenderUsage;
std::vector<AudioRenderUsage> ActivityToUsageVector(
const ActivityDispatcherImpl::Activity& activity) {
std::vector<AudioRenderUsage> usage_vector;
usage_vector.reserve(activity.count());
for (int i = 0; i < fuchsia::media::CAPTURE_USAGE_COUNT; i++) {
if (activity[i]) {
usage_vector.push_back(static_cast<AudioRenderUsage>(i));
}
}
return usage_vector;
}
} // namespace
class ActivityDispatcherImpl::ActivityReporterImpl : public fuchsia::media::ActivityReporter {
public:
// The activity must outlive the ActivityReporterImpl.
explicit ActivityReporterImpl(const Activity& last_known_activity,
fit::callback<void(ActivityReporterImpl*)> on_client_error);
~ActivityReporterImpl() override;
// Signal that the activity changed.
void OnActivityChanged();
private:
// fuchsia::media::ActivityReporter.
void WatchRenderActivity(WatchRenderActivityCallback callback) override;
// Send Activity if there was some update.
void MaybeSendActivity();
// Last state known by the dispatcher.
const Activity& last_known_activity_;
// Last activity sent to client.
// Absent if no state was sent to the client yet.
std::optional<Activity> last_sent_activity_;
// If present, callback to call next time a state is available.
WatchRenderActivityCallback waiting_callback_;
// Called when the client has more than one hanging gets in flight.
fit::callback<void(ActivityReporterImpl*)> on_client_error_;
};
ActivityDispatcherImpl::ActivityDispatcherImpl() = default;
ActivityDispatcherImpl::~ActivityDispatcherImpl() = default;
ActivityDispatcherImpl::ActivityReporterImpl::ActivityReporterImpl(
const Activity& last_known_activity, fit::callback<void(ActivityReporterImpl*)> on_client_error)
: last_known_activity_(last_known_activity), on_client_error_(std::move(on_client_error)) {}
ActivityDispatcherImpl::ActivityReporterImpl::~ActivityReporterImpl() = default;
void ActivityDispatcherImpl::ActivityReporterImpl::OnActivityChanged() { MaybeSendActivity(); }
void ActivityDispatcherImpl::ActivityReporterImpl::WatchRenderActivity(
WatchRenderActivityCallback callback) {
// If there is more than one hanging get in flight, disconnect the client.
if (waiting_callback_) {
on_client_error_(this);
return;
}
waiting_callback_ = std::move(callback);
MaybeSendActivity();
}
void ActivityDispatcherImpl::ActivityReporterImpl::MaybeSendActivity() {
// No request in flight.
if (!waiting_callback_) {
return;
}
// No new update.
if (last_sent_activity_.has_value() && (last_sent_activity_.value() == last_known_activity_)) {
return;
}
waiting_callback_(ActivityToUsageVector(last_known_activity_));
last_sent_activity_ = last_known_activity_;
waiting_callback_ = nullptr;
}
fidl::InterfaceRequestHandler<fuchsia::media::ActivityReporter>
ActivityDispatcherImpl::GetFidlRequestHandler() {
return fit::bind_member(this, &ActivityDispatcherImpl::Bind);
}
void ActivityDispatcherImpl::Bind(
fidl::InterfaceRequest<fuchsia::media::ActivityReporter> request) {
constexpr auto kEpitaphValue = ZX_ERR_PEER_CLOSED;
bindings_.AddBinding(
std::make_unique<ActivityReporterImpl>(
last_known_activity_,
[this](ActivityReporterImpl* impl) { bindings_.CloseBinding(impl, kEpitaphValue); }),
std::move(request));
}
void ActivityDispatcherImpl::OnActivityChanged(Activity activity) {
last_known_activity_ = activity;
for (const auto& listener : bindings_.bindings()) {
listener->impl()->OnActivityChanged();
}
}
} // namespace media::audio