blob: 34faafd4aa9a35448850b6a07d2b46377a784c31 [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.
#ifndef SRC_MEDIA_AUDIO_DRIVERS_VIRTUAL_AUDIO_VIRTUAL_AUDIO_DEVICE_IMPL_H_
#define SRC_MEDIA_AUDIO_DRIVERS_VIRTUAL_AUDIO_VIRTUAL_AUDIO_DEVICE_IMPL_H_
#include <fuchsia/virtualaudio/cpp/fidl.h>
#include <lib/closure-queue/closure_queue.h>
#include <lib/zx/clock.h>
#include <memory>
#include <audio-proto/audio-proto.h>
#include <fbl/ref_ptr.h>
#include "src/media/audio/drivers/virtual_audio/virtual_audio_control_impl.h"
namespace virtual_audio {
class VirtualAudioStream;
class VirtualAudioDeviceImpl : public fuchsia::virtualaudio::Input,
public fuchsia::virtualaudio::Output {
public:
static constexpr char kDefaultDeviceName[] = "Virtual_Audio_Device_(default)";
static constexpr char kDefaultManufacturerName[] =
"Fuchsia Virtual Audio Group (*** default manufacturer name "
"********************************************************************************************"
"********************************************************************************************"
"***********)";
static constexpr char kDefaultProductName[] =
"Virgil v1, a Virtual Volume Vessel (** default product name "
"********************************************************************************************"
"********************************************************************************************"
"**********)";
static constexpr uint8_t kDefaultUniqueId[16] = {1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 0};
// One very limited range for basic audio support by default.
static constexpr audio_stream_format_range_t kDefaultFormatRange = {
.sample_formats = AUDIO_SAMPLE_FORMAT_16BIT,
.min_frames_per_second = 48000,
.max_frames_per_second = 48000,
.min_channels = 2,
.max_channels = 2,
.flags = ASF_RANGE_FLAG_FPS_48000_FAMILY,
};
// Default clock domain is 0, the local system CLOCK_MONOTONIC domain
static constexpr int32_t kDefaultClockDomain = 0;
static constexpr int32_t kDefaultClockRateAdjustment = 0;
// Default FIFO is 250 usec, at 48k stereo 16
static constexpr uint32_t kDefaultFifoDepthBytes = 48;
static constexpr zx_time_t kDefaultExternalDelayNsec = 0;
// Default ring buffer size is at least 250msec (assuming default rate 48k)
static constexpr uint32_t kDefaultMinBufferFrames = 12000;
static constexpr uint32_t kDefaultMaxBufferFrames = 1 << 19; // (10+ sec, at default 48k!)
static constexpr uint32_t kDefaultModuloBufferFrames = 1;
// By default, support a wide gain range with good precision.
static constexpr audio::audio_proto::GetGainResp kDefaultGainState = {.cur_mute = false,
.cur_agc = false,
.cur_gain = -0.75f,
.can_mute = true,
.can_agc = false,
.min_gain = -160.0f,
.max_gain = 24.0f,
.gain_step = 0.25f};
// By default, device is hot-pluggable
static constexpr bool kDefaultPlugged = true;
static constexpr bool kDefaultHardwired = false;
static constexpr bool kDefaultPlugCanNotify = true;
static std::unique_ptr<VirtualAudioDeviceImpl> Create(VirtualAudioControlImpl* owner,
bool is_input);
// Execute the given task on the FIDL channel's main dispatcher thread. Used to deliver callbacks
// or events, from the driver execution domain.
void PostToDispatcher(fit::closure task_to_post);
void SetBinding(fidl::Binding<fuchsia::virtualaudio::Input,
std::unique_ptr<virtual_audio::VirtualAudioDeviceImpl>>* binding);
void SetBinding(fidl::Binding<fuchsia::virtualaudio::Output,
std::unique_ptr<virtual_audio::VirtualAudioDeviceImpl>>* binding);
virtual bool CreateStream(zx_device_t* devnode);
void RemoveStream();
void ClearStream();
bool IsActive() { return (stream_ != nullptr); }
void Init();
//
// virtualaudio.Configuration interface
//
void SetDeviceName(std::string device_name) override;
void SetManufacturer(std::string manufacturer_name) override;
void SetProduct(std::string product_name) override;
void SetUniqueId(std::array<uint8_t, 16> unique_id) override;
void AddFormatRange(uint32_t format_flags, uint32_t min_rate, uint32_t max_rate,
uint8_t min_chans, uint8_t max_chans, uint16_t rate_family_flags) override;
void ClearFormatRanges() override;
void SetClockProperties(int32_t clock_domain, int32_t initial_rate_adjustment_ppm) override;
void SetFifoDepth(uint32_t fifo_depth_bytes) override;
void SetExternalDelay(zx_duration_t external_delay) override;
void SetRingBufferRestrictions(uint32_t min_frames, uint32_t max_frames,
uint32_t modulo_frames) override;
void SetGainProperties(float min_gain_db, float max_gain_db, float gain_step_db,
float current_gain_db, bool can_mute, bool current_mute, bool can_agc,
bool current_agc) override;
void SetPlugProperties(zx_time_t plug_change_time, bool plugged, bool hardwired,
bool can_notify) override;
void ResetConfiguration() override;
//
// virtualaudio.Device interface
//
void Add() override;
void Remove() override;
void GetFormat(fuchsia::virtualaudio::Device::GetFormatCallback callback) override;
virtual void NotifySetFormat(uint32_t frames_per_second, uint32_t sample_format,
uint32_t num_channels, zx_duration_t external_delay);
void GetGain(fuchsia::virtualaudio::Device::GetGainCallback callback) override;
virtual void NotifySetGain(bool current_mute, bool current_agc, float current_gain_db);
void GetBuffer(fuchsia::virtualaudio::Device::GetBufferCallback callback) override;
virtual void NotifyBufferCreated(zx::vmo ring_buffer_vmo, uint32_t num_ring_buffer_frames,
uint32_t notifications_per_ring);
void SetNotificationFrequency(uint32_t notifications_per_ring) override;
virtual void NotifyStart(zx_time_t start_time);
virtual void NotifyStop(zx_time_t stop_time, uint32_t ring_buffer_position);
void GetPosition(fuchsia::virtualaudio::Device::GetPositionCallback callback) override;
virtual void NotifyPosition(zx_time_t monotonic_time, uint32_t ring_buffer_position);
void ChangePlugState(zx_time_t plug_change_time, bool plugged) override;
void AdjustClockRate(int32_t ppm_from_system_monotonic) override;
private:
friend class VirtualAudioStream;
friend class std::default_delete<VirtualAudioDeviceImpl>;
VirtualAudioDeviceImpl(VirtualAudioControlImpl* owner, bool is_input);
virtual ~VirtualAudioDeviceImpl();
void WarnActiveStreamNotAffected(const char* func_name);
VirtualAudioControlImpl const* owner_;
fbl::RefPtr<VirtualAudioStream> stream_;
bool is_input_;
// When the binding is closed, it is removed from the (ControlImpl-owned) BindingSet that contains
// it, which in turn deletes the associated impl (since the binding holds a unique_ptr<impl>, not
// an impl*). Something might get dispatched from other thread at around this time, so we enqueue
// them (ClosureQueue) and use StopAndClear to cancel them during ~DeviceImpl (in RemoveStream).
fidl::Binding<fuchsia::virtualaudio::Input,
std::unique_ptr<virtual_audio::VirtualAudioDeviceImpl>>* input_binding_ = nullptr;
fidl::Binding<fuchsia::virtualaudio::Output,
std::unique_ptr<virtual_audio::VirtualAudioDeviceImpl>>* output_binding_ = nullptr;
// Don't initialize here or in ctor; do it all in Init() so ResetConfiguration has same effect.
std::string device_name_;
std::string mfr_name_;
std::string prod_name_;
uint8_t unique_id_[16];
int32_t clock_domain_;
int32_t clock_rate_adjustment_;
std::vector<audio_stream_format_range_t> supported_formats_;
uint32_t fifo_depth_;
zx_duration_t external_delay_nsec_;
uint32_t min_buffer_frames_;
uint32_t max_buffer_frames_;
uint32_t modulo_buffer_frames_;
audio::audio_proto::GetGainResp cur_gain_state_;
zx_time_t plug_time_;
bool plugged_;
bool hardwired_;
bool async_plug_notify_;
bool override_notification_frequency_;
uint32_t notifications_per_ring_;
// The optional enables this to be emplaced when stream_ is created, minimizing memory churn.
std::optional<ClosureQueue> task_queue_;
};
} // namespace virtual_audio
#endif // SRC_MEDIA_AUDIO_DRIVERS_VIRTUAL_AUDIO_VIRTUAL_AUDIO_DEVICE_IMPL_H_