blob: 548b90a15da9ee991ba5fa5fc736a362c6aa11fb [file] [log] [blame]
// Copyright 2018 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 "garnet/bin/media/audio_core/mixer/fx_processor.h"
#include "garnet/bin/media/audio_core/mixer/fx_loader.h"
#include "lib/fxl/logging.h"
namespace media::audio {
// If any instances remain, remove and delete them before we leave.
FxProcessor::~FxProcessor() {
while (!fx_chain_.empty()) {
DeleteFx(GetFxAt(0));
}
// release any reference on fx_loader_
}
// Create and insert an effect instance, at the specified position.
// If position is out-of-range, return an error (don't clamp).
fx_token_t FxProcessor::CreateFx(uint32_t effect_id, uint16_t channels_in,
uint16_t channels_out, uint8_t position) {
fx_token_t fx_token =
fx_loader_->CreateFx(effect_id, frame_rate_, channels_in, channels_out);
if (fx_token == FUCHSIA_AUDIO_DFX_INVALID_TOKEN) {
return fx_token;
}
// If we successfully create but can't insert, delete before returning error.
if (InsertFx(fx_token, position) != ZX_OK) {
fx_loader_->DeleteFx(fx_token);
return FUCHSIA_AUDIO_DFX_INVALID_TOKEN;
}
return fx_token;
}
// Return the number of active instances in this chain.
uint16_t FxProcessor::GetNumFx() { return fx_chain_.size(); }
// If position is out-of-range, return an error (don't clamp).
fx_token_t FxProcessor::GetFxAt(uint16_t position) {
if (position >= fx_chain_.size()) {
return FUCHSIA_AUDIO_DFX_INVALID_TOKEN;
}
return fx_chain_[position];
}
// Move the specified instance to a new position in the FX chain.
// If position is out-of-range, return an error (don't clamp).
zx_status_t FxProcessor::ReorderFx(fx_token_t fx_token, uint8_t new_position) {
if (new_position >= fx_chain_.size()) {
return ZX_ERR_OUT_OF_RANGE;
}
if (RemoveFx(fx_token) != ZX_OK) {
return ZX_ERR_NOT_FOUND;
}
return InsertFx(fx_token, new_position);
}
// Remove and delete the specified instance.
zx_status_t FxProcessor::DeleteFx(fx_token_t fx_token) {
if (fx_loader_ == nullptr) {
return ZX_ERR_NOT_FOUND;
}
if (fx_token == FUCHSIA_AUDIO_DFX_INVALID_TOKEN) {
return ZX_ERR_INVALID_ARGS;
}
zx_status_t ret_val = RemoveFx(fx_token);
if (ret_val == ZX_OK) {
ret_val = fx_loader_->DeleteFx(fx_token);
}
return ret_val;
}
// For this FX chain, call each instance's FxProcessInPlace() in sequence.
// Per spec, fail if audio_buff_in_out is nullptr (even if num_frames is 0).
// Also, if any instance fails Process, exit without calling the others.
// TODO(mpuryear): Should we still call the other instances, if one fails?
zx_status_t FxProcessor::ProcessInPlace(uint32_t num_frames,
float* audio_buff_in_out) {
if (audio_buff_in_out == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
if (num_frames == 0) {
return ZX_OK;
}
for (auto fx_token : fx_chain_) {
if (fx_token == FUCHSIA_AUDIO_DFX_INVALID_TOKEN) {
return ZX_ERR_INTERNAL;
}
zx_status_t ret_val =
fx_loader_->FxProcessInPlace(fx_token, num_frames, audio_buff_in_out);
if (ret_val != ZX_OK) {
return ret_val;
}
}
return ZX_OK;
}
// For this FX chain, call each instance's FxFlush() in sequence.
// If any instance fails, exit without calling the others.
// TODO(mpuryear): Because Flush is a cleanup, do we Flush ALL even on error?
zx_status_t FxProcessor::Flush() {
for (auto fx_token : fx_chain_) {
if (fx_token == FUCHSIA_AUDIO_DFX_INVALID_TOKEN) {
return ZX_ERR_INTERNAL;
}
zx_status_t ret_val = fx_loader_->FxFlush(fx_token);
if (ret_val != ZX_OK) {
return ret_val;
}
}
return ZX_OK;
}
//
// Private internal methods
//
// Insert an already-created effect instance at the specified position.
// If position is out-of-range, return an error (don't clamp).
zx_status_t FxProcessor::InsertFx(fx_token_t fx_token, uint8_t position) {
if (fx_token == FUCHSIA_AUDIO_DFX_INVALID_TOKEN) {
return ZX_ERR_INVALID_ARGS;
}
if (position > fx_chain_.size()) {
return ZX_ERR_OUT_OF_RANGE;
}
fx_chain_.insert(fx_chain_.begin() + position, fx_token);
return ZX_OK;
}
// Remove an existing effect instance from the FX chain.
zx_status_t FxProcessor::RemoveFx(fx_token_t fx_token) {
auto iter = std::find(fx_chain_.begin(), fx_chain_.end(), fx_token);
if (iter == fx_chain_.end()) {
return ZX_ERR_NOT_FOUND;
}
fx_chain_.erase(iter);
return ZX_OK;
}
} // namespace media::audio