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 */ 27 struct 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 37 static struct dumper *syslog_dumper; 38 static const char *ini_filename; 39 static struct ini *ini; 40 static struct cras_dsp_context *context_list; 41 42 static 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 51 static 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 87 bail: 88 if (pipeline) 89 cras_dsp_pipeline_free(pipeline); 90 return NULL; 91 } 92 93 static 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 109 static 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 128 void 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 136 void 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 146 struct 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 160 void 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 174 void 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 180 void 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 187 void cras_dsp_load_pipeline(struct cras_dsp_context *ctx) 188 { 189 cmd_load_pipeline(ctx); 190 } 191 192 struct 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 202 void cras_dsp_put_pipeline(struct cras_dsp_context *ctx) 203 { 204 pthread_mutex_unlock(&ctx->mutex); 205 } 206 207 void cras_dsp_reload_ini() 208 { 209 cmd_reload_ini(); 210 } 211 212 void 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 227 unsigned 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 232 unsigned 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