blob: 8ab5214d830d8996fc9d50388a21b4c33ea90b4d [file] [log] [blame]
// Copyright 2016 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_AUDIO_CORE_AUDIO_RENDERER_IMPL_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_AUDIO_RENDERER_IMPL_H_
#include <fuchsia/media/cpp/fidl.h>
#include <lib/fit/function.h>
#include <memory>
#include <unordered_map>
#include "lib/fidl/cpp/binding.h"
#include "lib/fidl/cpp/binding_set.h"
#include "lib/media/cpp/timeline_function.h"
#include "src/media/audio/audio_core/audio_link_packet_source.h"
#include "src/media/audio/audio_core/audio_object.h"
#include "src/media/audio/audio_core/audio_renderer_format_info.h"
#include "src/media/audio/audio_core/utils.h"
#include "src/media/audio/lib/wav_writer/wav_writer.h"
namespace media::audio {
constexpr bool kEnableRendererWavWriters = false;
class AudioCoreImpl;
class AudioRendererImpl : public AudioObject,
public fbl::DoublyLinkedListable<fbl::RefPtr<AudioRendererImpl>>,
public fuchsia::media::AudioRenderer,
public fuchsia::media::audio::GainControl {
public:
static fbl::RefPtr<AudioRendererImpl> Create(
fidl::InterfaceRequest<fuchsia::media::AudioRenderer> audio_renderer_request,
AudioCoreImpl* owner);
void Shutdown();
void OnRenderRange(int64_t presentation_time, uint32_t duration){};
void SnapshotCurrentTimelineFunction(int64_t reference_time, TimelineFunction* out,
uint32_t* generation);
void SetThrottleOutput(fbl::RefPtr<AudioLinkPacketSource> throttle_output_link);
// Recompute the minimum clock lead time based on the current set of outputs
// we are linked to. If this requirement is different from the previous
// requirement, report it to our users (if they care).
void RecomputeMinClockLeadTime();
// Note: format_info() is subject to change and must only be accessed from the
// main message loop thread. Outputs which are running on mixer threads
// should never access format_info() directly from an AudioRenderer. Instead,
// they should use the format_info which was assigned to the AudioLink at the
// time the link was created.
const fbl::RefPtr<AudioRendererFormatInfo>& format_info() const { return format_info_; }
bool format_info_valid() const { return (format_info_ != nullptr); }
// AudioRenderer interface
void SetPcmStreamType(fuchsia::media::AudioStreamType format) final;
void SetStreamType(fuchsia::media::StreamType format) final;
void AddPayloadBuffer(uint32_t id, zx::vmo payload_buffer) final;
void RemovePayloadBuffer(uint32_t id) final;
void SetPtsUnits(uint32_t tick_per_second_numerator, uint32_t tick_per_second_denominator) final;
void SetPtsContinuityThreshold(float threshold_seconds) final;
void SetReferenceClock(zx::handle ref_clock) final;
void SendPacket(fuchsia::media::StreamPacket packet, SendPacketCallback callback) final;
void SendPacketNoReply(fuchsia::media::StreamPacket packet) final;
void EndOfStream() final;
void DiscardAllPackets(DiscardAllPacketsCallback callback) final;
void DiscardAllPacketsNoReply() final;
void Play(int64_t reference_time, int64_t media_time, PlayCallback callback) final;
void PlayNoReply(int64_t reference_time, int64_t media_time) final;
void Pause(PauseCallback callback) final;
void PauseNoReply() final;
void BindGainControl(fidl::InterfaceRequest<fuchsia::media::audio::GainControl> request) final;
void EnableMinLeadTimeEvents(bool enabled) final;
void GetMinLeadTime(GetMinLeadTimeCallback callback) final;
void SetUsage(fuchsia::media::AudioRenderUsage usage) override;
fuchsia::media::AudioRenderUsage GetUsage() { return usage_; };
// GainControl interface.
void SetGain(float gain_db) final;
void SetGainWithRamp(float gain_db, zx_duration_t duration_ns,
fuchsia::media::audio::RampType ramp_type) final;
void SetMute(bool muted) final;
void NotifyGainMuteChanged();
// TODO(mpuryear): Notify on SetGainWithRamp.
// TODO(mpuryear): consider EnableGainChangeEvents(bool), like MinLeadTime.
protected:
// Hook called when the minimum clock lead time requirement changes.
void ReportNewMinClockLeadTime();
fbl::RefPtr<AudioRendererFormatInfo> format_info_;
std::vector<fuchsia::media::AudioRenderUsage> allowed_usages_;
fuchsia::media::AudioRenderUsage usage_;
float stream_gain_db_ = 0.0;
bool mute_ = false;
fbl::RefPtr<AudioLinkPacketSource> throttle_output_link_;
// Minimum Clock Lead Time state
int64_t min_clock_lead_nsec_ = 0;
private:
class GainControlBinding : public fuchsia::media::audio::GainControl {
public:
static std::unique_ptr<GainControlBinding> Create(AudioRendererImpl* owner) {
return std::unique_ptr<GainControlBinding>(new GainControlBinding(owner));
}
// GainControl interface.
void SetGain(float gain_db) final;
void SetGainWithRamp(float gain_db, zx_duration_t duration_ns,
fuchsia::media::audio::RampType ramp_type) final;
void SetMute(bool muted) final;
private:
friend class std::default_delete<GainControlBinding>;
GainControlBinding(AudioRendererImpl* owner) : owner_(owner) {}
~GainControlBinding() override {}
AudioRendererImpl* owner_;
};
friend class fbl::RefPtr<AudioRendererImpl>;
friend class GainControlBinding;
AudioRendererImpl(fidl::InterfaceRequest<fuchsia::media::AudioRenderer> audio_renderer_request,
AudioCoreImpl* owner);
~AudioRendererImpl() override;
bool IsOperating();
bool ValidateConfig();
void ComputePtsToFracFrames(int64_t first_pts);
void UnlinkThrottle();
AudioCoreImpl* owner_ = nullptr;
fidl::Binding<fuchsia::media::AudioRenderer> audio_renderer_binding_;
fidl::BindingSet<fuchsia::media::audio::GainControl, std::unique_ptr<GainControlBinding>>
gain_control_bindings_;
bool is_shutdown_ = false;
std::unordered_map<uint32_t, fbl::RefPtr<RefCountedVmoMapper>> payload_buffers_;
bool config_validated_ = false;
// PTS interpolation state.
int64_t next_frac_frame_pts_ = 0;
TimelineRate pts_ticks_per_second_;
TimelineRate frac_frames_per_pts_tick_;
TimelineFunction pts_to_frac_frames_;
bool pts_to_frac_frames_valid_ = false;
float pts_continuity_threshold_ = 0.0f;
bool pts_continuity_threshold_set_ = false;
int64_t pts_continuity_threshold_frac_frame_ = 0;
// Play/Pause state
int64_t pause_time_frac_frames_;
bool pause_time_frac_frames_valid_ = false;
TimelineRate frac_frames_per_ref_tick_;
// Minimum Clock Lead Time state
bool min_clock_lead_time_events_enabled_ = false;
fbl::Mutex ref_to_ff_lock_;
TimelineFunction ref_clock_to_frac_frames_ FXL_GUARDED_BY(ref_to_ff_lock_);
GenerationId ref_clock_to_frac_frames_gen_ FXL_GUARDED_BY(ref_to_ff_lock_);
WavWriter<kEnableRendererWavWriters> wav_writer_;
};
} // namespace media::audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_AUDIO_RENDERER_IMPL_H_