blob: 3273fefdc15e5a859635bec6ebda64bd28f21295 [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_STREAM_H_
#define SRC_MEDIA_AUDIO_DRIVERS_VIRTUAL_AUDIO_VIRTUAL_AUDIO_STREAM_H_
#include <fuchsia/virtualaudio/cpp/fidl.h>
#include <lib/affine/transform.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/simple-audio-stream/simple-audio-stream.h>
#include <deque>
#include <audio-proto/audio-proto.h>
#include <fbl/ref_ptr.h>
namespace virtual_audio {
class VirtualAudioDeviceImpl;
class VirtualAudioStream : public audio::SimpleAudioStream {
public:
void EnqueuePlugChange(bool plugged) __TA_EXCLUDES(wakeup_queue_lock_);
void EnqueueGainRequest(fuchsia::virtualaudio::Device::GetGainCallback gain_callback)
__TA_EXCLUDES(wakeup_queue_lock_);
void EnqueueFormatRequest(fuchsia::virtualaudio::Device::GetFormatCallback format_callback)
__TA_EXCLUDES(wakeup_queue_lock_);
void EnqueueBufferRequest(fuchsia::virtualaudio::Device::GetBufferCallback buffer_callback)
__TA_EXCLUDES(wakeup_queue_lock_);
void EnqueuePositionRequest(fuchsia::virtualaudio::Device::GetPositionCallback position_callback)
__TA_EXCLUDES(wakeup_queue_lock_);
void EnqueueNotificationOverride(uint32_t notifications_per_ring)
__TA_EXCLUDES(wakeup_queue_lock_);
void EnqueueClockRateAdjustment(int32_t ppm_from_monotonic) __TA_EXCLUDES(wakeup_queue_lock_);
static fbl::RefPtr<VirtualAudioStream> CreateStream(VirtualAudioDeviceImpl* owner,
zx_device_t* devnode, bool is_input);
// Only set by DeviceImpl -- on dtor, Disable or Remove
bool shutdown_by_parent_ = false;
protected:
friend class audio::SimpleAudioStream;
friend class fbl::RefPtr<VirtualAudioStream>;
VirtualAudioStream(VirtualAudioDeviceImpl* parent, zx_device_t* dev_node, bool is_input)
: audio::SimpleAudioStream(dev_node, is_input), parent_(parent) {}
zx_status_t Init() __TA_REQUIRES(domain_token()) override;
zx_status_t EstablishReferenceClock() __TA_REQUIRES(domain_token());
zx_status_t AdjustClockRate() __TA_REQUIRES(domain_token());
zx_status_t ChangeFormat(const audio::audio_proto::StreamSetFmtReq& req)
__TA_REQUIRES(domain_token()) override;
zx_status_t SetGain(const audio::audio_proto::SetGainReq& req)
__TA_REQUIRES(domain_token()) override;
zx_status_t GetBuffer(const audio::audio_proto::RingBufGetBufferReq& req,
uint32_t* out_num_rb_frames, zx::vmo* out_buffer)
__TA_REQUIRES(domain_token()) override;
zx_status_t Start(uint64_t* out_start_time) __TA_REQUIRES(domain_token()) override;
zx_status_t Stop() __TA_REQUIRES(domain_token()) override;
void ShutdownHook() __TA_REQUIRES(domain_token()) override;
// RingBufferShutdown() is unneeded: no hardware shutdown tasks needed...
enum class PlugType { Plug, Unplug };
void HandlePlugChanges() __TA_EXCLUDES(wakeup_queue_lock_);
void HandleSetNotifications() __TA_EXCLUDES(wakeup_queue_lock_);
void HandleClockRateAdjustments() __TA_EXCLUDES(wakeup_queue_lock_);
void HandleGainRequests() __TA_EXCLUDES(wakeup_queue_lock_);
void HandleFormatRequests() __TA_EXCLUDES(wakeup_queue_lock_);
void HandleBufferRequests() __TA_EXCLUDES(wakeup_queue_lock_);
void HandlePositionRequests() __TA_EXCLUDES(wakeup_queue_lock_);
void ProcessRingNotification();
void SetNotificationPeriods() __TA_REQUIRES(domain_token());
void PostForNotify() __TA_REQUIRES(domain_token());
void PostForNotifyAt(zx::time ref_notification_time) __TA_REQUIRES(domain_token());
void ProcessVaClientRingNotification();
void SetVaClientNotificationPeriods() __TA_REQUIRES(domain_token());
void PostForVaClientNotify() __TA_REQUIRES(domain_token());
void PostForVaClientNotifyAt(zx::time ref_notification_time) __TA_REQUIRES(domain_token());
private:
static zx::time MonoTimeFromRefTime(const zx::clock& clock, zx::time ref_time);
// Accessed in GetBuffer, defended by token.
fzl::VmoMapper ring_buffer_mapper_ __TA_GUARDED(domain_token());
zx::vmo ring_buffer_vmo_ __TA_GUARDED(domain_token());
uint32_t num_ring_buffer_frames_ __TA_GUARDED(domain_token()) = 0;
uint32_t max_buffer_frames_ __TA_GUARDED(domain_token());
uint32_t min_buffer_frames_ __TA_GUARDED(domain_token());
uint32_t modulo_buffer_frames_ __TA_GUARDED(domain_token());
zx::time ref_start_time_ __TA_GUARDED(domain_token());
// Members related to the driver's delivery of position notifications to AudioCore.
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::ProcessRingNotification>
notify_timer_ __TA_GUARDED(domain_token()){this};
uint32_t notifications_per_ring_ __TA_GUARDED(domain_token()) = 0;
zx::duration ref_notification_period_ __TA_GUARDED(domain_token()) = zx::duration(0);
zx::time target_mono_notification_time_ __TA_GUARDED(domain_token()) = zx::time(0);
zx::time target_ref_notification_time_ __TA_GUARDED(domain_token()) = zx::time(0);
// Members related to driver delivery of position notifications to a VirtualAudio client, with an
// alternate notifications-per-ring cadence. If a VirtualAudio client specifies the same cadence
// that AudioCore has requested, then we simply use the above members and deliver those same
// notifications to the VA client as well.
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::ProcessVaClientRingNotification>
va_client_notify_timer_ __TA_GUARDED(domain_token()){this};
std::optional<uint32_t> va_client_notifications_per_ring_ __TA_GUARDED(domain_token()) =
std::nullopt;
zx::duration va_client_ref_notification_period_ __TA_GUARDED(domain_token()) = zx::duration(0);
zx::time target_va_client_mono_notification_time_ __TA_GUARDED(domain_token()) = zx::time(0);
zx::time target_va_client_ref_notification_time_ __TA_GUARDED(domain_token()) = zx::time(0);
uint32_t bytes_per_sec_ __TA_GUARDED(domain_token()) = 0;
uint32_t frame_rate_ __TA_GUARDED(domain_token()) = 0;
audio_sample_format_t sample_format_ __TA_GUARDED(domain_token()) = 0;
uint32_t num_channels_ __TA_GUARDED(domain_token()) = 0;
affine::Transform ref_time_to_running_frame_ __TA_GUARDED(domain_token());
zx::clock reference_clock_ __TA_GUARDED(domain_token());
int32_t clock_rate_adjustment_ __TA_GUARDED(domain_token());
VirtualAudioDeviceImpl* parent_ __TA_GUARDED(domain_token());
fbl::Mutex wakeup_queue_lock_ __TA_ACQUIRED_AFTER(domain_token());
// TODO(mpuryear): Refactor to a single queue of lambdas to dedupe this code.
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::HandlePlugChanges>
plug_change_wakeup_{this};
std::deque<PlugType> plug_queue_ __TA_GUARDED(wakeup_queue_lock_);
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::HandleGainRequests>
gain_request_wakeup_{this};
std::deque<fuchsia::virtualaudio::Device::GetGainCallback> gain_queue_
__TA_GUARDED(wakeup_queue_lock_);
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::HandleFormatRequests>
format_request_wakeup_{this};
std::deque<fuchsia::virtualaudio::Device::GetFormatCallback> format_queue_
__TA_GUARDED(wakeup_queue_lock_);
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::HandleBufferRequests>
buffer_request_wakeup_{this};
std::deque<fuchsia::virtualaudio::Device::GetBufferCallback> buffer_queue_
__TA_GUARDED(wakeup_queue_lock_);
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::HandlePositionRequests>
position_request_wakeup_{this};
std::deque<fuchsia::virtualaudio::Device::GetPositionCallback> position_queue_
__TA_GUARDED(wakeup_queue_lock_);
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::HandleSetNotifications>
set_notifications_wakeup_{this};
std::deque<uint32_t> notifs_queue_ __TA_GUARDED(wakeup_queue_lock_);
async::TaskClosureMethod<VirtualAudioStream, &VirtualAudioStream::HandleClockRateAdjustments>
set_clock_rate_wakeup_{this};
std::deque<uint32_t> clock_rate_queue_ __TA_GUARDED(wakeup_queue_lock_);
};
} // namespace virtual_audio
#endif // SRC_MEDIA_AUDIO_DRIVERS_VIRTUAL_AUDIO_VIRTUAL_AUDIO_STREAM_H_