/* Copyright (c) 2012 The Chromium OS 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 <cutils/log.h> #include <semaphore.h> #include "cras_expr.h" #include "cras_dsp_ini.h" #include "cras_dsp_pipeline.h" #include "dsp_util.h" #include "utlist.h" #define LOG_TAG "audio_cras_dsp" /* We have a dsp_context for each pipeline. The context records the * parameters used to create a pipeline, so the pipeline can be * (re-)loaded later. The pipeline is (re-)loaded in the following * cases: * * (1) The client asks to (re-)load it with cras_load_pipeline(). * (2) The client asks to reload the ini with cras_reload_ini(). * */ struct cras_dsp_context { struct pipeline *pipeline; struct cras_expr_env env; int sample_rate; const char *purpose; struct cras_dsp_context *prev, *next; }; static const char *ini_filename; static struct ini *ini; static struct cras_dsp_context *context_list; static void initialize_environment(struct cras_expr_env *env) { cras_expr_env_install_builtins(env); cras_expr_env_set_variable_boolean(env, "disable_eq", 0); cras_expr_env_set_variable_boolean(env, "disable_drc", 0); cras_expr_env_set_variable_string(env, "dsp_name", ""); } static struct pipeline *prepare_pipeline(struct cras_dsp_context *ctx) { struct pipeline *pipeline; const char *purpose = ctx->purpose; if (!ini) return NULL; pipeline = cras_dsp_pipeline_create(ini, &ctx->env, purpose); if (pipeline) { ALOGI("pipeline created"); } else { ALOGI("cannot create pipeline"); goto bail; } if (cras_dsp_pipeline_load(pipeline) != 0) { ALOGE("cannot load pipeline"); goto bail; } if (cras_dsp_pipeline_instantiate(pipeline, ctx->sample_rate) != 0) { ALOGE("cannot instantiate pipeline"); goto bail; } if (cras_dsp_pipeline_get_sample_rate(pipeline) != ctx->sample_rate) { ALOGE("pipeline sample rate mismatch (%d vs %d)", cras_dsp_pipeline_get_sample_rate(pipeline), ctx->sample_rate); goto bail; } return pipeline; bail: if (pipeline) cras_dsp_pipeline_free(pipeline); return NULL; } /* Exported functions */ void cras_dsp_set_variable(struct cras_dsp_context *ctx, const char *key, const char *value) { cras_expr_env_set_variable_string(&ctx->env, key, value); } void cras_dsp_load_pipeline(struct cras_dsp_context *ctx) { struct pipeline *pipeline, *old_pipeline; pipeline = prepare_pipeline(ctx); old_pipeline = ctx->pipeline; ctx->pipeline = pipeline; if (old_pipeline) cras_dsp_pipeline_free(old_pipeline); } void cras_dsp_reload_ini() { struct ini *old_ini = ini; struct cras_dsp_context *ctx; ini = cras_dsp_ini_create(ini_filename); if (!ini) ALOGE("cannot create dsp ini"); DL_FOREACH(context_list, ctx) { cras_dsp_load_pipeline(ctx); } if (old_ini) cras_dsp_ini_free(old_ini); } void cras_dsp_init(const char *filename) { dsp_enable_flush_denormal_to_zero(); ini_filename = strdup(filename); cras_dsp_reload_ini(); } void cras_dsp_stop() { free((char *)ini_filename); if (ini) { cras_dsp_ini_free(ini); ini = NULL; } } struct cras_dsp_context *cras_dsp_context_new(int sample_rate, const char *purpose) { struct cras_dsp_context *ctx = calloc(1, sizeof(*ctx)); initialize_environment(&ctx->env); ctx->sample_rate = sample_rate; ctx->purpose = strdup(purpose); DL_APPEND(context_list, ctx); return ctx; } void cras_dsp_context_free(struct cras_dsp_context *ctx) { DL_DELETE(context_list, ctx); if (ctx->pipeline) { cras_dsp_pipeline_free(ctx->pipeline); ctx->pipeline = NULL; } cras_expr_env_free(&ctx->env); free((char *)ctx->purpose); free(ctx); } struct pipeline *cras_dsp_get_pipeline(struct cras_dsp_context *ctx) { return ctx->pipeline; } void cras_dsp_put_pipeline(struct cras_dsp_context *ctx) { } unsigned int cras_dsp_num_output_channels(const struct cras_dsp_context *ctx) { return cras_dsp_pipeline_get_num_output_channels(ctx->pipeline); } unsigned int cras_dsp_num_input_channels(const struct cras_dsp_context *ctx) { return cras_dsp_pipeline_get_num_input_channels(ctx->pipeline); } void cras_dsp_sync() { }