blob: 1da6507e4106d68b54be62382011fe20b8b4e118 [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.
#include "src/media/audio/audio_core/mixer/output_producer.h"
#include <lib/fidl/cpp/clone.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include <algorithm>
#include <cmath>
#include <limits>
#include <type_traits>
#include "src/media/audio/lib/format2/sample_converter.h"
namespace media::audio {
// Template to fill samples with silence based on sample type.
template <typename DType, typename Enable = void>
class SilenceMaker;
template <typename DType>
class SilenceMaker<DType, typename std::enable_if_t<std::is_same_v<DType, int16_t> ||
std::is_same_v<DType, int32_t> ||
std::is_same_v<DType, float>>> {
public:
static inline void Fill(void* dest_void_ptr, size_t samples) {
// This works even if DType is float/double: per IEEE-754, all 0s == +0.0.
memset(dest_void_ptr, 0, samples * sizeof(DType));
}
};
template <typename DType>
class SilenceMaker<DType, typename std::enable_if_t<std::is_same_v<DType, uint8_t>>> {
public:
static inline void Fill(void* dest_void_ptr, size_t samples) {
memset(dest_void_ptr, media_audio::kInt8ToUint8, samples * sizeof(DType));
}
};
// Templated class that implements ProduceOutput and FillWithSilence methods for OutputProducer
template <typename DType>
class OutputProducerImpl : public OutputProducer {
public:
explicit OutputProducerImpl(const fuchsia::media::AudioStreamType& format)
: OutputProducer(format, sizeof(DType)) {}
void ProduceOutput(const float* source_ptr, void* dest_void_ptr, int64_t frames) const override {
TRACE_DURATION("audio", "OutputProducerImpl::ProduceOutput");
auto* dest_ptr = static_cast<DType*>(dest_void_ptr);
// Previously we clamped here; because of rounding, this is different for
// each output type, so it is now handled in Convert() specializations.
const size_t kNumSamples = frames * channels_;
for (size_t i = 0; i < kNumSamples; ++i) {
dest_ptr[i] = media_audio::SampleConverter<DType>::FromFloat(source_ptr[i]);
}
}
void FillWithSilence(void* dest_void_ptr, int64_t frames) const override {
TRACE_DURATION("audio", "OutputProducerImpl::FillWithSilence");
SilenceMaker<DType>::Fill(dest_void_ptr, frames * channels_);
}
};
// Constructor/destructor for the common OutputProducer base class.
OutputProducer::OutputProducer(const fuchsia::media::AudioStreamType& format,
int32_t bytes_per_sample)
: channels_(format.channels),
bytes_per_sample_(bytes_per_sample),
bytes_per_frame_(bytes_per_sample * format.channels) {
fidl::Clone(format, &format_);
}
// Selection routine which will instantiate a particular templatized version of the output producer.
std::unique_ptr<OutputProducer> OutputProducer::Select(
const fuchsia::media::AudioStreamType& format) {
TRACE_DURATION("audio", "OutputProducer::Select");
if (format.channels == 0u) {
FX_LOGS(ERROR) << "Invalid output format";
return nullptr;
}
switch (format.sample_format) {
case fuchsia::media::AudioSampleFormat::UNSIGNED_8:
return std::make_unique<OutputProducerImpl<uint8_t>>(format);
case fuchsia::media::AudioSampleFormat::SIGNED_16:
return std::make_unique<OutputProducerImpl<int16_t>>(format);
case fuchsia::media::AudioSampleFormat::SIGNED_24_IN_32:
return std::make_unique<OutputProducerImpl<int32_t>>(format);
case fuchsia::media::AudioSampleFormat::FLOAT:
return std::make_unique<OutputProducerImpl<float>>(format);
default:
FX_LOGS(ERROR) << "Unsupported output format " << (int64_t)format.sample_format;
return nullptr;
}
}
} // namespace media::audio