blob: 4e981c2245d8bc74a5843622440d6402e822ce2b [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.
#include "src/media/audio/audio_core/mixer/sinc_sampler.h"
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include <algorithm>
#include <memory>
#include "fidl/fuchsia.mediastreams/cpp/wire_types.h"
#include "src/media/audio/lib/processing/position_manager.h"
#include "src/media/audio/lib/processing/sampler.h"
#include "src/media/audio/lib/processing/sinc_sampler.h"
namespace media::audio::mixer {
namespace {
using ::media_audio::PositionManager;
using ::media_audio::Sampler;
fuchsia_mediastreams::wire::AudioSampleFormat ToNewSampleFormat(
fuchsia::media::AudioSampleFormat sample_format) {
switch (sample_format) {
case fuchsia::media::AudioSampleFormat::UNSIGNED_8:
return fuchsia_mediastreams::wire::AudioSampleFormat::kUnsigned8;
case fuchsia::media::AudioSampleFormat::SIGNED_16:
return fuchsia_mediastreams::wire::AudioSampleFormat::kSigned16;
case fuchsia::media::AudioSampleFormat::SIGNED_24_IN_32:
return fuchsia_mediastreams::wire::AudioSampleFormat::kSigned24In32;
case fuchsia::media::AudioSampleFormat::FLOAT:
default:
return fuchsia_mediastreams::wire::AudioSampleFormat::kFloat;
}
}
media_audio::Format ToNewFormat(const fuchsia::media::AudioStreamType& format) {
return media_audio::Format::CreateOrDie(
{ToNewSampleFormat(format.sample_format), format.channels, format.frames_per_second});
}
} // namespace
std::unique_ptr<Mixer> SincSampler::Select(const fuchsia::media::AudioStreamType& source_format,
const fuchsia::media::AudioStreamType& dest_format,
Gain::Limits gain_limits) {
TRACE_DURATION("audio", "SincSampler::Select");
auto sinc_sampler =
media_audio::SincSampler::Create(ToNewFormat(source_format), ToNewFormat(dest_format));
if (!sinc_sampler) {
return nullptr;
}
struct MakePublicCtor : SincSampler {
MakePublicCtor(Gain::Limits gain_limits, std::shared_ptr<Sampler> sinc_sampler)
: SincSampler(gain_limits, std::move(sinc_sampler)) {}
};
return std::make_unique<MakePublicCtor>(gain_limits, std::move(sinc_sampler));
}
void SincSampler::EagerlyPrepare() { sinc_sampler_->EagerlyPrepare(); }
void SincSampler::Mix(float* dest_ptr, int64_t dest_frames, int64_t* dest_offset_ptr,
const void* source_void_ptr, int64_t source_frames, Fixed* source_offset_ptr,
bool accumulate) {
TRACE_DURATION("audio", "SincSampler::Mix");
auto info = &bookkeeping();
PositionManager::CheckPositions(
dest_frames, dest_offset_ptr, source_frames, source_offset_ptr->raw_value(),
sinc_sampler_->pos_filter_length().raw_value(), info->step_size.raw_value(),
info->rate_modulo(), info->denominator(), info->source_pos_modulo);
static_cast<media_audio::SincSampler*>(sinc_sampler_.get())
->SetRateValues(info->step_size.raw_value(), info->rate_modulo(), info->denominator(),
&info->source_pos_modulo);
Sampler::Source source{source_void_ptr, source_offset_ptr, source_frames};
Sampler::Dest dest{dest_ptr, dest_offset_ptr, dest_frames};
if (info->gain.IsSilent()) {
// If the gain is silent, the mixer simply skips over the appropriate range in the destination
// buffer, leaving whatever data is already there. We do not take further effort to clear the
// buffer if `accumulate` is false. In fact, we IGNORE `accumulate` if silent. The caller is
// responsible for clearing the destination buffer before Mix is initially called.
sinc_sampler_->Process(source, dest, Sampler::Gain{.type = media_audio::GainType::kSilent},
true);
} else if (info->gain.IsUnity()) {
sinc_sampler_->Process(source, dest, Sampler::Gain{.type = media_audio::GainType::kUnity},
accumulate);
} else if (info->gain.IsRamping()) {
sinc_sampler_->Process(
source, dest,
Sampler::Gain{.type = media_audio::GainType::kRamping, .scale_ramp = info->scale_arr.get()},
accumulate);
} else {
sinc_sampler_->Process(
source, dest,
Sampler::Gain{.type = media_audio::GainType::kNonUnity, .scale = info->gain.GetGainScale()},
accumulate);
}
}
} // namespace media::audio::mixer