blob: 90e53f2363743fecb39660dfd04717fd418d1f2b [file] [log] [blame]
// Copyright 2025 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_DRIVERS_VIRTUAL_AUDIO_VIRTUAL_AUDIO_COMPOSITE_H_
#define SRC_MEDIA_AUDIO_DRIVERS_VIRTUAL_AUDIO_VIRTUAL_AUDIO_COMPOSITE_H_
#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
#include <fidl/fuchsia.virtualaudio/cpp/fidl.h>
#include <lib/driver/devfs/cpp/connector.h>
#include <lib/driver/node/cpp/add_child.h>
#include <lib/fzl/vmo-mapper.h>
namespace virtual_audio {
class VirtualAudioComposite
: public fidl::Server<fuchsia_virtualaudio::Device>,
public fidl::Server<fuchsia_hardware_audio::Composite>,
public fidl::Server<fuchsia_hardware_audio_signalprocessing::SignalProcessing>,
public fidl::Server<fuchsia_hardware_audio::RingBuffer> {
public:
using InstanceId = uint64_t;
using OnDeviceBindingClosed = fit::callback<void(fidl::UnbindInfo)>;
static constexpr std::string_view kClassName = "audio-composite";
static fuchsia_virtualaudio::Configuration GetDefaultConfig();
static zx::result<std::unique_ptr<VirtualAudioComposite>> Create(
InstanceId instance_id, fuchsia_virtualaudio::Configuration config,
async_dispatcher_t* dispatcher, fidl::ServerEnd<fuchsia_virtualaudio::Device> server,
OnDeviceBindingClosed on_binding_closed,
fidl::UnownedClientEnd<fuchsia_driver_framework::Node> parent);
VirtualAudioComposite(InstanceId instance_id, fuchsia_virtualaudio::Configuration config,
async_dispatcher_t* dispatcher,
fidl::ServerEnd<fuchsia_virtualaudio::Device> server,
OnDeviceBindingClosed on_device_binding_closed)
: config_(std::move(config)),
dispatcher_(dispatcher),
device_binding_(dispatcher_, std::move(server), this, std::move(on_device_binding_closed)),
instance_id_(instance_id) {}
zx::result<> Init(fidl::UnownedClientEnd<fuchsia_driver_framework::Node> parent);
private:
static constexpr size_t kNumberOfElements = 4;
static constexpr fuchsia_hardware_audio_signalprocessing::ElementId kRingBufferId = 123;
static constexpr fuchsia_hardware_audio_signalprocessing::ElementId kGainId = 321;
static constexpr fuchsia_hardware_audio_signalprocessing::ElementId kDaiId = 456;
static constexpr fuchsia_hardware_audio_signalprocessing::ElementId kSingleDaiId = 555;
static constexpr size_t kNumberOfTopologies = 3;
// This topology is RingBuffer (123) -> Gain (321) -> Dai (456)
static constexpr fuchsia_hardware_audio_signalprocessing::TopologyId kPlaybackTopologyId = 789;
// This topology is Dai (456) -> Gain (321) -> RingBuffer (123)
static constexpr fuchsia_hardware_audio_signalprocessing::TopologyId kCaptureTopologyId = 987;
// This topology is Dai (555) -> Dai (555)
static constexpr fuchsia_hardware_audio_signalprocessing::TopologyId kSingleElementTopologyId =
55;
// virtualaudio.Device implementation.
void GetFormat(GetFormatCompleter::Sync& completer) override;
void GetGain(GetGainCompleter::Sync& completer) override;
void GetBuffer(GetBufferCompleter::Sync& completer) override;
void SetNotificationFrequency(SetNotificationFrequencyRequest& request,
SetNotificationFrequencyCompleter::Sync& completer) override;
void GetPosition(GetPositionCompleter::Sync& completer) override;
void ChangePlugState(ChangePlugStateRequest& request,
ChangePlugStateCompleter::Sync& completer) override;
void AdjustClockRate(AdjustClockRateRequest& request,
AdjustClockRateCompleter::Sync& completer) override;
// fuchsia.hardware.audio.Composite implementation.
void Reset(ResetCompleter::Sync& completer) override;
void GetProperties(fidl::Server<fuchsia_hardware_audio::Composite>::GetPropertiesCompleter::Sync&
completer) override;
void GetHealthState(GetHealthStateCompleter::Sync& completer) override;
void SignalProcessingConnect(SignalProcessingConnectRequest& request,
SignalProcessingConnectCompleter::Sync& completer) override;
void GetRingBufferFormats(GetRingBufferFormatsRequest& request,
GetRingBufferFormatsCompleter::Sync& completer) override;
void CreateRingBuffer(CreateRingBufferRequest& request,
CreateRingBufferCompleter::Sync& completer) override;
void GetDaiFormats(GetDaiFormatsRequest& request,
GetDaiFormatsCompleter::Sync& completer) override;
void SetDaiFormat(SetDaiFormatRequest& request, SetDaiFormatCompleter::Sync& completer) override;
// fuchsia.hardware.audio.RingBuffer implementation.
void GetProperties(fidl::Server<fuchsia_hardware_audio::RingBuffer>::GetPropertiesCompleter::Sync&
completer) override;
void GetVmo(GetVmoRequest& request, GetVmoCompleter::Sync& completer) override;
void Start(StartCompleter::Sync& completer) override;
void Stop(StopCompleter::Sync& completer) override;
void WatchClockRecoveryPositionInfo(
WatchClockRecoveryPositionInfoCompleter::Sync& completer) override;
void WatchDelayInfo(WatchDelayInfoCompleter::Sync& completer) override;
void SetActiveChannels(SetActiveChannelsRequest& request,
SetActiveChannelsCompleter::Sync& completer) override;
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_audio::RingBuffer> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override;
// fuchsia.hardware.audio.signalprocessing implementation (SignalProcessing and Reader).
void GetElements(GetElementsCompleter::Sync& completer) override;
void GetTopologies(GetTopologiesCompleter::Sync& completer) override;
void SetTopology(SetTopologyRequest& request, SetTopologyCompleter::Sync& completer) override;
void WatchTopology(WatchTopologyCompleter::Sync& completer) override;
void SetElementState(SetElementStateRequest& request,
SetElementStateCompleter::Sync& completer) override;
void WatchElementState(WatchElementStateRequest& request,
WatchElementStateCompleter::Sync& completer) override;
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_audio_signalprocessing::SignalProcessing>
metadata,
fidl::UnknownMethodCompleter::Sync& completer) override;
void SetupSignalProcessing();
void SetupSignalProcessingElements();
void SetupSignalProcessingTopologies();
void SetupSignalProcessingElementStates();
void MaybeCompleteWatchTopology();
void MaybeCompleteWatchElementState(fuchsia_hardware_audio_signalprocessing::ElementId);
void Serve(fidl::ServerEnd<fuchsia_hardware_audio::Composite> server);
void ResetRingBuffer();
void OnRingBufferClosed(fidl::UnbindInfo info);
void OnSignalProcessingClosed(fidl::UnbindInfo info);
fuchsia_virtualaudio::RingBuffer& GetRingBuffer(uint64_t id);
fuchsia_virtualaudio::Composite& composite_config() {
return config_.device_specific()->composite().value();
}
std::optional<fidl::ServerBinding<fuchsia_hardware_audio::Composite>> composite_binding_;
// This driver exposes only one ring buffer element.
bool ring_buffer_is_outgoing_;
fzl::VmoMapper ring_buffer_mapper_;
uint32_t notifications_per_ring_ = 0;
uint32_t num_ring_buffer_frames_ = 0;
uint32_t frame_size_ = 4;
zx::vmo ring_buffer_vmo_;
// ring-buffer state
bool ring_buffer_vmo_fetched_ = false;
bool ring_buffer_started_ = false;
std::optional<fuchsia_hardware_audio::Format> ring_buffer_format_;
uint64_t ring_buffer_active_channel_mask_;
zx::time active_channel_set_time_;
// ring-buffer hanging gets
bool should_reply_to_delay_request_ = true;
std::optional<WatchDelayInfoCompleter::Async> delay_info_completer_;
bool should_reply_to_position_request_ = true;
std::optional<WatchClockRecoveryPositionInfoCompleter::Async> position_info_completer_;
// This driver exposes only one DAI element.
std::optional<fuchsia_hardware_audio::DaiFormat> dai_format_;
fuchsia_virtualaudio::Configuration config_;
std::optional<fidl::ServerBinding<fuchsia_hardware_audio::RingBuffer>> ring_buffer_;
std::optional<fidl::ServerBinding<fuchsia_hardware_audio_signalprocessing::SignalProcessing>>
signal_;
std::vector<fuchsia_hardware_audio_signalprocessing::Element> elements_;
std::unordered_map<fuchsia_hardware_audio_signalprocessing::ElementId,
fuchsia_hardware_audio_signalprocessing::Element*>
element_map_;
std::vector<fuchsia_hardware_audio_signalprocessing::Topology> topologies_;
fuchsia_hardware_audio_signalprocessing::TopologyId current_topology_id_;
std::optional<fuchsia_hardware_audio_signalprocessing::TopologyId> last_reported_topology_id_;
std::optional<WatchTopologyCompleter::Async> watch_topology_completer_;
struct ElementSnapshot {
ElementSnapshot() = default;
ElementSnapshot(const ElementSnapshot&) = delete;
ElementSnapshot(ElementSnapshot&&) = default;
ElementSnapshot& operator=(const ElementSnapshot&) = delete;
ElementSnapshot& operator=(ElementSnapshot&&) = default;
fuchsia_hardware_audio_signalprocessing::ElementState current;
std::optional<fuchsia_hardware_audio_signalprocessing::ElementState> last_notified;
std::optional<WatchElementStateCompleter::Async> completer;
};
std::unordered_map<fuchsia_hardware_audio_signalprocessing::ElementId, ElementSnapshot>
element_states_;
async_dispatcher_t* dispatcher_;
fidl::ServerBinding<fuchsia_virtualaudio::Device> device_binding_;
driver_devfs::Connector<fuchsia_hardware_audio::Composite> devfs_connector_{
fit::bind_member<&VirtualAudioComposite::Serve>(this)};
std::optional<fdf::OwnedChildNode> child_;
InstanceId instance_id_;
};
} // namespace virtual_audio
#endif // SRC_MEDIA_AUDIO_DRIVERS_VIRTUAL_AUDIO_VIRTUAL_AUDIO_COMPOSITE_H_