blob: 52be91ce26a2517af78da41d859e0af90c4dbc37 [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_MIX_STAGE_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_MIX_STAGE_H_
#include <lib/async/cpp/task.h>
#include <lib/async/cpp/time.h>
#include <lib/zx/time.h>
#include <optional>
#include <gtest/gtest_prod.h>
#include "src/lib/fxl/synchronization/thread_annotations.h"
#include "src/media/audio/audio_core/mixer/mixer.h"
#include "src/media/audio/audio_core/stream.h"
#include "src/media/audio/audio_core/versioned_timeline_function.h"
#include "src/media/audio/lib/clock/audio_clock.h"
#include "src/media/audio/lib/format/format.h"
#include "src/media/audio/lib/timeline/timeline_function.h"
namespace media::audio {
class MixStage : public ReadableStream {
public:
MixStage(const Format& output_format, uint32_t block_size,
TimelineFunction ref_time_to_frac_presentation_frame, AudioClock& ref_clock,
std::optional<float> min_gain_db = std::nullopt,
std::optional<float> max_gain_db = std::nullopt);
MixStage(const Format& output_format, uint32_t block_size,
fbl::RefPtr<VersionedTimelineFunction> ref_time_to_frac_presentation_frame,
AudioClock& ref_clock, std::optional<float> min_gain_db = std::nullopt,
std::optional<float> max_gain_db = std::nullopt);
// |media::audio::ReadableStream|
TimelineFunctionSnapshot ref_time_to_frac_presentation_frame() const override;
AudioClock& reference_clock() override { return output_ref_clock_; }
void SetPresentationDelay(zx::duration external_delay) override;
std::shared_ptr<Mixer> AddInput(std::shared_ptr<ReadableStream> stream,
std::optional<float> initial_dest_gain_db = std::nullopt,
Mixer::Resampler sampler_hint = Mixer::Resampler::Default);
void RemoveInput(const ReadableStream& stream);
private:
FRIEND_TEST(MixStageTest, DontCrashOnDestOffsetRoundingError);
std::optional<ReadableStream::Buffer> ReadLockImpl(ReadLockContext& ctx, Fixed dest_frame,
int64_t frame_count) override;
void TrimImpl(Fixed dest_frame) override;
void SetupMixBuffer(uint32_t max_mix_frames);
struct MixJob {
// Job state set up once by an output implementation, used by all renderers.
// TODO(fxbug.dev/13415): Integrate it into the Mixer class itself.
ReadLockContext* read_lock_ctx;
float* buf;
int64_t buf_frames;
int64_t dest_start_frame;
TimelineFunction dest_ref_clock_to_frac_dest_frame;
bool accumulate;
StreamUsageMask usages_mixed;
float total_applied_gain_db;
};
struct StreamHolder {
std::shared_ptr<ReadableStream> stream;
std::shared_ptr<ReadableStream> original_stream;
std::shared_ptr<Mixer> mixer;
};
enum class TaskType { Mix, Trim };
void ForEachSource(TaskType task_type, Fixed dest_frame);
void ReconcileClocksAndSetStepSize(Mixer::SourceInfo& info, Mixer::Bookkeeping& bookkeeping,
ReadableStream& stream);
void SyncSourcePositionFromClocks(AudioClock& source_clock, AudioClock& dest_clock,
Mixer::SourceInfo& info, Mixer::Bookkeeping& bookkeeping,
int64_t dest_frame, zx::time mono_now_from_dest,
bool timeline_changed);
void SetStepSize(Mixer::SourceInfo& info, Mixer::Bookkeeping& bookkeeping,
const TimelineRate& frac_source_frames_per_dest_frame);
void MixStream(Mixer& mixer, ReadableStream& stream);
std::optional<Buffer> NextSourceBuffer(Mixer& mixer, ReadableStream& stream, int64_t dest_frames);
std::mutex stream_lock_;
std::vector<StreamHolder> streams_ FXL_GUARDED_BY(stream_lock_);
// State used by the mix task.
MixJob cur_mix_job_;
const int64_t output_buffer_frames_;
std::vector<float> output_buffer_;
AudioClock& output_ref_clock_;
fbl::RefPtr<VersionedTimelineFunction> output_ref_clock_to_fractional_frame_;
const Gain::Limits gain_limits_;
// Used to variably throttle the amount of jam-sync-related logging we produce
uint32_t jam_sync_count_ = 0;
};
} // namespace media::audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_MIX_STAGE_H_