1/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6#include <pthread.h> 7#include <syslog.h> 8#include "dumper.h" 9#include "cras_expr.h" 10#include "cras_dsp_ini.h" 11#include "cras_dsp_pipeline.h" 12#include "dsp_util.h" 13#include "utlist.h" 14 15/* We have a dsp_context for each pipeline. The context records the 16 * parameters used to create a pipeline, so the pipeline can be 17 * (re-)loaded later. The pipeline is (re-)loaded in the following 18 * cases: 19 * 20 * (1) The client asks to (re-)load it with cras_load_pipeline(). 21 * (2) The client asks to reload the ini with cras_reload_ini(). 22 * 23 * The pipeline is (re-)loaded asynchronously in an internal thread, 24 * so the client needs to use cras_dsp_get_pipeline() and 25 * cras_dsp_put_pipeline() to safely access the pipeline. 26 */ 27struct cras_dsp_context { 28 pthread_mutex_t mutex; 29 struct pipeline *pipeline; 30 31 struct cras_expr_env env; 32 int sample_rate; 33 const char *purpose; 34 struct cras_dsp_context *prev, *next; 35}; 36 37static struct dumper *syslog_dumper; 38static const char *ini_filename; 39static struct ini *ini; 40static struct cras_dsp_context *context_list; 41 42static void initialize_environment(struct cras_expr_env *env) 43{ 44 cras_expr_env_install_builtins(env); 45 cras_expr_env_set_variable_boolean(env, "disable_eq", 0); 46 cras_expr_env_set_variable_boolean(env, "disable_drc", 0); 47 cras_expr_env_set_variable_string(env, "dsp_name", ""); 48 cras_expr_env_set_variable_boolean(env, "swap_lr_disabled", 1); 49} 50 51static struct pipeline *prepare_pipeline(struct cras_dsp_context *ctx) 52{ 53 struct pipeline *pipeline; 54 const char *purpose = ctx->purpose; 55 56 if (!ini) 57 return NULL; 58 59 pipeline = cras_dsp_pipeline_create(ini, &ctx->env, purpose); 60 61 if (pipeline) { 62 syslog(LOG_DEBUG, "pipeline created"); 63 } else { 64 syslog(LOG_DEBUG, "cannot create pipeline"); 65 goto bail; 66 } 67 68 if (cras_dsp_pipeline_load(pipeline) != 0) { 69 syslog(LOG_ERR, "cannot load pipeline"); 70 goto bail; 71 } 72 73 if (cras_dsp_pipeline_instantiate(pipeline, ctx->sample_rate) != 0) { 74 syslog(LOG_ERR, "cannot instantiate pipeline"); 75 goto bail; 76 } 77 78 if (cras_dsp_pipeline_get_sample_rate(pipeline) != ctx->sample_rate) { 79 syslog(LOG_ERR, "pipeline sample rate mismatch (%d vs %d)", 80 cras_dsp_pipeline_get_sample_rate(pipeline), 81 ctx->sample_rate); 82 goto bail; 83 } 84 85 return pipeline; 86 87bail: 88 if (pipeline) 89 cras_dsp_pipeline_free(pipeline); 90 return NULL; 91} 92 93static void cmd_load_pipeline(struct cras_dsp_context *ctx) 94{ 95 struct pipeline *pipeline, *old_pipeline; 96 97 pipeline = prepare_pipeline(ctx); 98 99 /* This locking is short to avoild blocking audio thread. */ 100 pthread_mutex_lock(&ctx->mutex); 101 old_pipeline = ctx->pipeline; 102 ctx->pipeline = pipeline; 103 pthread_mutex_unlock(&ctx->mutex); 104 105 if (old_pipeline) 106 cras_dsp_pipeline_free(old_pipeline); 107} 108 109static void cmd_reload_ini() 110{ 111 struct ini *old_ini = ini; 112 struct cras_dsp_context *ctx; 113 114 ini = cras_dsp_ini_create(ini_filename); 115 if (!ini) 116 syslog(LOG_ERR, "cannot create dsp ini"); 117 118 DL_FOREACH(context_list, ctx) { 119 cmd_load_pipeline(ctx); 120 } 121 122 if (old_ini) 123 cras_dsp_ini_free(old_ini); 124} 125 126/* Exported functions */ 127 128void cras_dsp_init(const char *filename) 129{ 130 dsp_enable_flush_denormal_to_zero(); 131 ini_filename = strdup(filename); 132 syslog_dumper = syslog_dumper_create(LOG_ERR); 133 cmd_reload_ini(); 134} 135 136void cras_dsp_stop() 137{ 138 syslog_dumper_free(syslog_dumper); 139 free((char *)ini_filename); 140 if (ini) { 141 cras_dsp_ini_free(ini); 142 ini = NULL; 143 } 144} 145 146struct cras_dsp_context *cras_dsp_context_new(int sample_rate, 147 const char *purpose) 148{ 149 struct cras_dsp_context *ctx = calloc(1, sizeof(*ctx)); 150 151 pthread_mutex_init(&ctx->mutex, NULL); 152 initialize_environment(&ctx->env); 153 ctx->sample_rate = sample_rate; 154 ctx->purpose = strdup(purpose); 155 156 DL_APPEND(context_list, ctx); 157 return ctx; 158} 159 160void cras_dsp_context_free(struct cras_dsp_context *ctx) 161{ 162 DL_DELETE(context_list, ctx); 163 164 pthread_mutex_destroy(&ctx->mutex); 165 if (ctx->pipeline) { 166 cras_dsp_pipeline_free(ctx->pipeline); 167 ctx->pipeline = NULL; 168 } 169 cras_expr_env_free(&ctx->env); 170 free((char *)ctx->purpose); 171 free(ctx); 172} 173 174void cras_dsp_set_variable_string(struct cras_dsp_context *ctx, const char *key, 175 const char *value) 176{ 177 cras_expr_env_set_variable_string(&ctx->env, key, value); 178} 179 180void cras_dsp_set_variable_boolean(struct cras_dsp_context *ctx, 181 const char *key, 182 char value) 183{ 184 cras_expr_env_set_variable_boolean(&ctx->env, key, value); 185} 186 187void cras_dsp_load_pipeline(struct cras_dsp_context *ctx) 188{ 189 cmd_load_pipeline(ctx); 190} 191 192struct pipeline *cras_dsp_get_pipeline(struct cras_dsp_context *ctx) 193{ 194 pthread_mutex_lock(&ctx->mutex); 195 if (!ctx->pipeline) { 196 pthread_mutex_unlock(&ctx->mutex); 197 return NULL; 198 } 199 return ctx->pipeline; 200} 201 202void cras_dsp_put_pipeline(struct cras_dsp_context *ctx) 203{ 204 pthread_mutex_unlock(&ctx->mutex); 205} 206 207void cras_dsp_reload_ini() 208{ 209 cmd_reload_ini(); 210} 211 212void cras_dsp_dump_info() 213{ 214 struct pipeline *pipeline; 215 struct cras_dsp_context *ctx; 216 217 if (ini) 218 cras_dsp_ini_dump(syslog_dumper, ini); 219 DL_FOREACH(context_list, ctx) { 220 cras_expr_env_dump(syslog_dumper, &ctx->env); 221 pipeline = ctx->pipeline; 222 if (pipeline) 223 cras_dsp_pipeline_dump(syslog_dumper, pipeline); 224 } 225} 226 227unsigned int cras_dsp_num_output_channels(const struct cras_dsp_context *ctx) 228{ 229 return cras_dsp_pipeline_get_num_output_channels(ctx->pipeline); 230} 231 232unsigned int cras_dsp_num_input_channels(const struct cras_dsp_context *ctx) 233{ 234 return cras_dsp_pipeline_get_num_input_channels(ctx->pipeline); 235} 236