blob: e3d3c6800f9734de979187356df7747508e3da5e [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_AUDIO_CORE_OUTPUT_PIPELINE_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_OUTPUT_PIPELINE_H_
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include <vector>
#include <fbl/ref_ptr.h>
#include "src/media/audio/audio_core/audio_clock.h"
#include "src/media/audio/audio_core/effects_stage.h"
#include "src/media/audio/audio_core/mix_stage.h"
#include "src/media/audio/audio_core/pipeline_config.h"
#include "src/media/audio/audio_core/stream.h"
#include "src/media/audio/audio_core/stream_usage.h"
#include "src/media/audio/audio_core/volume_curve.h"
#include "src/media/audio/lib/timeline/timeline_function.h"
namespace media::audio {
class OutputPipeline : public ReadableStream {
public:
explicit OutputPipeline(Format format) : ReadableStream(format) {}
~OutputPipeline() override = default;
// Returns the loopback |ReadableStream| for this pipeline.
virtual std::shared_ptr<ReadableStream> loopback() const = 0;
// Adds |stream| as an input to be mixed. The given |usage| will indicate where in the pipeline
// this stream will be routed.
virtual std::shared_ptr<Mixer> AddInput(
std::shared_ptr<ReadableStream> stream, const StreamUsage& usage,
std::optional<float> initial_dest_gain_db = std::nullopt,
Mixer::Resampler sampler_hint = Mixer::Resampler::Default) = 0;
// Removes |stream| from the pipeline.
//
// It is an error to call |RemoveInput| without exactly one preceeding call to |AddInput| with the
// same |stream|.
virtual void RemoveInput(const ReadableStream& stream) = 0;
// Sets the configuration of all effects with the given instance name.
virtual fit::result<void, fuchsia::media::audio::UpdateEffectError> UpdateEffect(
const std::string& instance_name, const std::string& config) = 0;
};
class OutputPipelineImpl : public OutputPipeline {
public:
// Creates an |OutputPipeline| based on the specification in |config|. The pipeline will
// ultimately produce output frames via |ReadLock| in the |output_format| requested.
//
// |max_block_size_frames| is the largest contiguous region that may be returned from
// |ReadLock|. If a caller requests a frame region of more that |max_block_size_frames|, then
// the pipeline will truncate this to only |max_block_size_frames| and the caller will have to
// call |ReadLock| again to mix the subsequent frames.
//
// |ref_clock_to_fractional_frame| is a timeline function that will compute the output frame
// number (in fixed point format with 13 bits of fractional precision) based on a reference
// timestamp.
//
// The |sampler| is optionally used to select the type of sampler to be used when joining
// mix stages together.
OutputPipelineImpl(const PipelineConfig& config, const VolumeCurve& volume_curve,
uint32_t max_block_size_frames,
TimelineFunction ref_time_to_frac_presentation_frame, AudioClock& audio_clock,
Mixer::Resampler sampler = Mixer::Resampler::Default);
~OutputPipelineImpl() override = default;
// |media::audio::OutputPipeline|
std::shared_ptr<ReadableStream> loopback() const override { return state_.loopback; }
std::shared_ptr<Mixer> AddInput(
std::shared_ptr<ReadableStream> stream, const StreamUsage& usage,
std::optional<float> initial_dest_gain_db = std::nullopt,
Mixer::Resampler sampler_hint = Mixer::Resampler::Default) override;
void RemoveInput(const ReadableStream& stream) override;
fit::result<void, fuchsia::media::audio::UpdateEffectError> UpdateEffect(
const std::string& instance_name, const std::string& config) override;
// |media::audio::ReadableStream|
std::optional<ReadableStream::Buffer> ReadLock(Fixed dest_frame, size_t frame_count) override {
TRACE_DURATION("audio", "OutputPipeline::ReadLock");
FX_DCHECK(state_.stream);
return state_.stream->ReadLock(dest_frame, frame_count);
}
void Trim(Fixed dest_frame) override {
TRACE_DURATION("audio", "OutputPipeline::Trim");
FX_CHECK(state_.stream);
state_.stream->Trim(dest_frame);
}
TimelineFunctionSnapshot ref_time_to_frac_presentation_frame() const override {
TRACE_DURATION("audio", "OutputPipeline::ref_time_to_frac_presentation_frame");
FX_DCHECK(state_.stream);
return state_.stream->ref_time_to_frac_presentation_frame();
}
void SetPresentationDelay(zx::duration external_delay) override {
ReadableStream::SetPresentationDelay(external_delay);
state_.stream->SetPresentationDelay(external_delay);
}
AudioClock& reference_clock() override { return state_.audio_clock; }
private:
struct State {
State(const PipelineConfig& config, const VolumeCurve& curve, uint32_t max_block_size_frames,
TimelineFunction ref_clock_to_fractional_frame, AudioClock& clock,
Mixer::Resampler sampler);
std::shared_ptr<ReadableStream> CreateMixStage(
const PipelineConfig::MixGroup& spec, const VolumeCurve& volume_curve, uint32_t block_size,
fbl::RefPtr<VersionedTimelineFunction> ref_clock_to_output_frame, AudioClock& clock,
uint32_t* usage_mask, Mixer::Resampler sampler);
std::vector<std::pair<std::shared_ptr<MixStage>, std::vector<StreamUsage>>> mix_stages;
std::vector<std::shared_ptr<EffectsStage>> effects_stages;
std::vector<std::pair<std::shared_ptr<ReadableStream>, StreamUsage>> streams;
// This is the root of the mix graph. The other mix stages must be reachable from this node
// to actually get mixed.
std::shared_ptr<ReadableStream> stream;
std::shared_ptr<ReadableStream> loopback;
AudioClock& audio_clock;
};
OutputPipelineImpl(State state);
MixStage& LookupStageForUsage(const StreamUsage& usage);
State state_;
};
} // namespace media::audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_OUTPUT_PIPELINE_H_