blob: 533b945de6c97a8827f69a7d5f1f446e6544fbb9 [file] [log] [blame]
// Copyright 2022 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.
#ifndef SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_CONTROL_SERVER_H_
#define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_CONTROL_SERVER_H_
#include <fidl/fuchsia.audio.device/cpp/fidl.h>
#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/fidl.h>
#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
#include <lib/fidl/cpp/wire/internal/transport_channel.h>
#include <cstdint>
#include <memory>
#include <optional>
#include "src/media/audio/services/common/base_fidl_server.h"
#include "src/media/audio/services/device_registry/audio_device_registry.h"
#include "src/media/audio/services/device_registry/control_notify.h"
#include "src/media/audio/services/device_registry/device.h"
namespace media_audio {
class RingBufferServer;
// FIDL server for fuchsia_audio_device/Control. Claims a Device and makes "mutable" calls on it.
class ControlServer
: public std::enable_shared_from_this<ControlServer>,
public ControlNotify,
public BaseFidlServer<ControlServer, fidl::Server, fuchsia_audio_device::Control> {
public:
static std::shared_ptr<ControlServer> Create(
std::shared_ptr<const FidlThread> thread,
fidl::ServerEnd<fuchsia_audio_device::Control> server_end,
std::shared_ptr<AudioDeviceRegistry> parent, std::shared_ptr<Device> device);
void OnShutdown(fidl::UnbindInfo info) override;
~ControlServer() override;
// ObserverNotify
//
void DeviceIsRemoved() final;
void DeviceHasError() final;
void GainStateChanged(const fuchsia_audio_device::GainState&) final;
void PlugStateChanged(const fuchsia_audio_device::PlugState& new_plug_state,
zx::time plug_change_time) final;
void TopologyChanged(TopologyId topology_id) final;
void ElementStateChanged(
ElementId element_id,
fuchsia_hardware_audio_signalprocessing::ElementState element_state) final;
// ControlNotify
//
void DeviceDroppedRingBuffer(ElementId element_id) final;
void DelayInfoChanged(ElementId element_id, const fuchsia_audio_device::DelayInfo&) final;
// If `dai_format` contains no value, no DaiFormat is set. The Device might be newly-initialized,
// or `Reset` may have been called. `SetDaiFormat` must be called.
void DaiFormatChanged(
ElementId element_id, const std::optional<fuchsia_hardware_audio::DaiFormat>& dai_format,
const std::optional<fuchsia_hardware_audio::CodecFormatInfo>& codec_format_info) final;
// `SetDaiFormat` did not change the format. The previously-set DaiFormat is still be in effect.
void DaiFormatNotSet(ElementId element_id, const fuchsia_hardware_audio::DaiFormat& dai_format,
fuchsia_audio_device::ControlSetDaiFormatError error) final;
void CodecStarted(const zx::time& start_time) final;
// A call to `CodecStart` did not succeed.
void CodecNotStarted() final;
void CodecStopped(const zx::time& stop_time) final;
// A call to `CodecStop` did not succeed.
void CodecNotStopped() final;
// fuchsia.audio.device.Control
//
void SetGain(SetGainRequest& request, SetGainCompleter::Sync& completer) final;
void CreateRingBuffer(CreateRingBufferRequest& request,
CreateRingBufferCompleter::Sync& completer) final;
void SetDaiFormat(SetDaiFormatRequest& request, SetDaiFormatCompleter::Sync& completer) final;
void Reset(ResetCompleter::Sync& completer) final;
void CodecStart(CodecStartCompleter::Sync& completer) final;
void CodecStop(CodecStopCompleter::Sync& completer) final;
// fuchsia.hardware.audio.signalprocessing support
//
void GetTopologies(GetTopologiesCompleter::Sync& completer) final;
void GetElements(GetElementsCompleter::Sync& completer) final;
void WatchTopology(WatchTopologyCompleter::Sync& completer) final {
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
void WatchElementState(WatchElementStateRequest& request,
WatchElementStateCompleter::Sync& completer) final {
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
void SetTopology(SetTopologyRequest& request, SetTopologyCompleter::Sync& completer) final {
completer.Reply(fit::error(ZX_ERR_NOT_SUPPORTED));
}
void SetElementState(SetElementStateRequest& request,
SetElementStateCompleter::Sync& completer) final {
completer.Reply(fit::error(ZX_ERR_NOT_SUPPORTED));
}
// Static object count, for debugging purposes.
static inline uint64_t count() { return count_; }
bool ControlledDeviceReceivedError() const { return device_has_error_; }
private:
template <typename ServerT, template <typename T> typename FidlServerT, typename ProtocolT>
friend class BaseFidlServer;
static inline const std::string_view kClassName = "ControlServer";
static inline uint64_t count_ = 0;
ControlServer(std::shared_ptr<AudioDeviceRegistry> parent, std::shared_ptr<Device> device);
std::shared_ptr<AudioDeviceRegistry> parent_;
std::shared_ptr<Device> device_;
std::optional<CodecStartCompleter::Async> codec_start_completer_;
std::optional<CodecStopCompleter::Async> codec_stop_completer_;
bool device_has_error_ = false;
// per-ElementId fields:
//
std::unordered_map<ElementId, SetDaiFormatCompleter::Async> set_dai_format_completers_;
std::unordered_map<ElementId, CreateRingBufferCompleter::Async> create_ring_buffer_completers_;
// Locks a weak_ptr ring_buffer_server_ to shared_ptr and returns it, or returns nullptr.
std::shared_ptr<RingBufferServer> TryGetRingBufferServer(ElementId element_id);
std::unordered_map<ElementId, std::weak_ptr<RingBufferServer>> ring_buffer_servers_;
};
} // namespace media_audio
#endif // SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_CONTROL_SERVER_H_