blob: 7836ffcd23c1eee8cf99eff4b22d02ab944d18ad [file] [log] [blame]
// Copyright 2022 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_LIB_PROCESSING_POSITION_MANAGER_H_
#define SRC_MEDIA_AUDIO_LIB_PROCESSING_POSITION_MANAGER_H_
#include <lib/syslog/cpp/macros.h>
#include "src/media/audio/lib/format2/fixed.h"
namespace media_audio {
// Enable to emit trace events containing the position state.
// TODO(fxbug.dev/87651): Move this constant to a common location if needed during audio core
// `media::audio::Mixer` migration.
inline constexpr bool kTracePositionEvents = false;
// Class that handles the updating of source and destination positions, as a resampler steps through
// source buffers with a specific step size (based on the resampling ratio). This class extracts a
// significant amount of duplicate code across the samplers.
class PositionManager {
public:
PositionManager(int32_t source_channel_count, int32_t dest_channel_count, int64_t positive_length,
int64_t negative_length);
~PositionManager() = default;
// Non-copyable and non-movable.
PositionManager(const PositionManager& other) = delete;
PositionManager& operator=(const PositionManager& other) = delete;
PositionManager(PositionManager&& other) = delete;
PositionManager& operator=(PositionManager&& other) = delete;
// Validates source and destination frame positions.
static void CheckPositions(int64_t dest_frame_count, int64_t* dest_offset_ptr,
int64_t source_frame_count, int64_t source_offset,
int64_t frac_pos_filter_length, int64_t frac_step_size,
uint64_t rate_modulo, uint64_t denominator,
uint64_t source_position_modulo_ptr);
// Used for debugging purposes only.
void Display() const;
void DisplayUpdate() const;
// Establishes the parameters for this source and dest
void SetSourceValues(const void* source_void_ptr, int64_t source_frame_count,
Fixed* source_offset_ptr);
void SetDestValues(float* dest_ptr, int64_t dest_frame_count, int64_t* dest_offset_ptr);
// Specifies the rate parameters. If not called, a unity rate (1:1) is assumed.
void SetRateValues(int64_t step_size, uint64_t rate_modulo, uint64_t denominator,
uint64_t* source_pos_mod);
// Retrieves the pointer to the current source frame (based on source offset).
template <typename SourceSampleType>
SourceSampleType* CurrentSourceFrame() const {
FX_CHECK(frac_source_offset_ >= 0);
auto source_ptr = static_cast<SourceSampleType*>(source_void_ptr_);
return source_ptr +
(frac_source_offset_ >> Fixed::Format::FractionalBits) * source_channel_count_;
}
// Retrieves the pointer to the current destination frame (based on destination offset).
float* CurrentDestFrame() const { return dest_ptr_ + (dest_offset_ * dest_channel_count_); }
// Returns true if there is enough remaining source data and destination space to produce another
// frame.
bool CanFrameBeMixed() const {
return (dest_offset_ < dest_frame_count_) && (frac_source_offset_ < frac_source_end_);
}
// Returns true if there is NOT enough remaining source data to produce another output frame.
bool IsSourceConsumed() const { return (frac_source_offset_ >= frac_source_end_); }
// Advances one dest frame (and related source, incl modulo); return the new source_offset.
int64_t AdvanceFrame() {
++dest_offset_;
frac_source_offset_ += frac_step_size_;
source_pos_modulo_ += rate_modulo_;
if (source_pos_modulo_ >= denominator_) {
++frac_source_offset_;
source_pos_modulo_ -= denominator_;
}
return frac_source_offset_;
}
// Advances to the end of this source and destination combo, returning the integer source frames
// advanced. Skips as much source and destination frames as possible, returning the number of
// whole source frames skipped.
int64_t AdvanceToEnd();
// Writes back the final offset values.
void UpdateOffsets();
// Returns source frame offset.
Fixed source_offset() const { return Fixed::FromRaw(frac_source_offset_); }
// Returns destination frame offset.
int64_t dest_offset() const { return dest_offset_; }
private:
static void CheckDestPositions(int64_t dest_frame_count, int64_t dest_offset);
static void CheckSourcePositions(int64_t source_frame_count, int64_t frac_source_offset,
int64_t frac_pos_filter_length);
static void CheckRateValues(int64_t frac_step_size, uint64_t rate_modulo, uint64_t denominator,
uint64_t source_position_modulo);
int32_t source_channel_count_ = 1;
int32_t dest_channel_count_ = 1;
int64_t frac_positive_length_ = 1;
int64_t frac_negative_length_ = kFracOneFrame;
void* source_void_ptr_ = nullptr;
int64_t source_frame_count_ = 0;
Fixed* source_offset_ptr_ = nullptr;
int64_t frac_source_offset_ = 0;
int64_t frac_source_end_ = 0;
float* dest_ptr_ = nullptr;
int64_t dest_frame_count_ = 0;
int64_t* dest_offset_ptr_ = nullptr;
int64_t dest_offset_ = 0;
// If `SetRateValues` is never called, we successfully operate at 1:1 (without rate change).
int64_t frac_step_size_ = kFracOneFrame;
uint64_t rate_modulo_ = 0;
uint64_t denominator_ = 1;
uint64_t source_pos_modulo_ = 0; // This should always be less than `rate_modulo_` (or both 0).
uint64_t* source_pos_modulo_ptr_ = &source_pos_modulo_;
};
} // namespace media_audio
#endif // SRC_MEDIA_AUDIO_LIB_PROCESSING_POSITION_MANAGER_H_