blob: dc84040fabef4b74e6f7dea6e7093b42f9aed974 [file] [log] [blame]
// Copyright 2018 The Chromium 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 <string>
#include "volume_control.h"
// Plugin interface for audio DSP modules.
// This is applicable only to audio CMA backends (Alsa, Fuscia).
// Please refer to
// chromecast/media/cma/backend/post_processors/
// as an example for new code, but OEM's implementations should not have any
// Chromium dependencies.
// Please refer to
// chromecast/media/cma/backend/post_processors/post_processor_wrapper.h for an
// example of how to port an existing AudioPostProcessor to AudioPostProcessor2
// Notes on PostProcessors that have a different number of in/out channels:
// * PostProcessor authors are free to define their channel order; Cast will
// simply pass this data to subsequent PostProcessors and MixerOutputStream.
// * Channel selection for stereo pairs will occur after the "mix" group, so
// devices that support stereo pairs should only change the number of
// in the "linearize" group of cast_audio.json.
namespace chromecast {
namespace media {
// Interface for AudioPostProcessors used for applying DSP in StreamMixer.
class AudioPostProcessor2 {
struct Config {
int output_sample_rate;
struct Status {
int input_sample_rate = -1;
int output_channels = -1;
// The group delay, measured in frames at the input sample rate. See
// chromecast/media/cma/backend/post_processors/
// for how this is tested.
int rendering_delay_frames = 0;
// The number of input frames of silence it will take for the processor to
// come to rest after playing out audio.
// In the case of an FIR filter, this is the length of the FIR kernel.
// In the case of IIR filters, this should be calculated as the number of
// frames for the output to decay to 10% (5 time constants).
// When inputs are paused, at least |GetRingingTimeInFrames()| of
// silence will be passed through the processor.
int ringing_time_frames = 0;
// The data buffer in which the last output from ProcessFrames() was stored.
// This will never be called before ProcessFrames().
// This data location should be valid until ProcessFrames() is called
// again.
// The data returned by GetOutputBuffer() should not be modified by this
// instance until the next call to ProcessFrames().
// If |channels_in| >= |channels_out|, this may be |data| from the
// last call to ProcessFrames().
// If |channels_in| < |channels_out|, this PostProcessor is responsible for
// allocating an output buffer.
// If PostProcessor owns |output_buffer|, it must ensure that the memory
// is valid until the next call to ProcessFrames() or destruction.
float* output_buffer = nullptr;
// The maximum amount of data that will ever be processed in one call.
static constexpr int kMaxAudioWriteTimeMilliseconds = 20;
virtual ~AudioPostProcessor2() = default;
// Sets the Config of the processor.
// Returns |false| if the processor cannot support |config|
virtual bool SetConfig(const Config& config) = 0;
// Returns the processor's generated settings. Post processors should keep
// an up-to-date Status as a member variable.
virtual const Status& GetStatus() = 0;
// Processes audio frames from |data|.
// This will never be called before SetOutputSampleRate().
// ProcessFrames may overwrite |data|, in which case GetOutputBuffer() should
// return |data|.
// |data| will be 32-bit interleaved float with |channels_in| channels.
// ProcessFrames must produce an equal duration of audio as was input,
// allowing for sample rate / channel count changes. If the output data
// will take up equal or less space than the input data, ProcessFrames()
// should overwrite the input data and store a pointer to |data| in |Status|.
// Otherwise, the Processor should allocate and own its own output buffer.
// |system_volume| is the Cast Volume applied to the stream
// (normalized to 0-1). It is the same as the cast volume set via alsa.
// |volume_dbfs| is the actual attenuation in dBFS (-inf to 0), equivalent to
// VolumeMap::VolumeToDbFS(|volume|).
// AudioPostProcessor should assume that volume has already been applied.
virtual void ProcessFrames(float* data,
int frames,
float system_volume,
float volume_dbfs) = 0;
// Sends a message to the PostProcessor. Implementations are responsible
// for the format and parsing of messages.
// Returns |true| if the message was accepted or |false| if the message could
// not be applied (i.e. invalid parameter, format error, parameter out of
// range, etc).
// If the PostProcessor can/will not be updated at runtime, this can be
// implemented as "return false;"
virtual bool UpdateParameters(const std::string& message) = 0;
// Sets content type to the PostProcessor so it could change processing
// settings accordingly.
virtual void SetContentType(AudioContentType content_type) {}
// Called when device is playing as part of a stereo pair.
// |channel| is the playout channel on this device (0 for left, 1 for right).
// or -1 if the device is not part of a stereo pair.
virtual void SetPlayoutChannel(int channel) {}
} // namespace media
} // namespace chromecast