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 *global_ini;
40 static struct cras_dsp_context *context_list;
41
initialize_environment(struct cras_expr_env * env)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
destroy_pipeline(struct pipeline * pipeline)51 static void destroy_pipeline(struct pipeline *pipeline)
52 {
53 struct ini *private_ini;
54
55 private_ini = cras_dsp_pipeline_get_ini(pipeline);
56 cras_dsp_pipeline_free(pipeline);
57
58 /*
59 * If pipeline is using an dsp ini other than the global one, free
60 * this ini so its life cycle is aligned with the associated dsp
61 * pipeline.
62 */
63 if (private_ini && (private_ini != global_ini))
64 cras_dsp_ini_free(private_ini);
65 }
66
prepare_pipeline(struct cras_dsp_context * ctx,struct ini * target_ini)67 static struct pipeline *prepare_pipeline(struct cras_dsp_context *ctx,
68 struct ini *target_ini)
69 {
70 struct pipeline *pipeline;
71 const char *purpose = ctx->purpose;
72
73 pipeline = cras_dsp_pipeline_create(target_ini, &ctx->env, purpose);
74
75 if (pipeline) {
76 syslog(LOG_DEBUG, "pipeline created");
77 } else {
78 syslog(LOG_DEBUG, "cannot create pipeline");
79 goto bail;
80 }
81
82 if (cras_dsp_pipeline_load(pipeline) != 0) {
83 syslog(LOG_ERR, "cannot load pipeline");
84 goto bail;
85 }
86
87 if (cras_dsp_pipeline_instantiate(pipeline, ctx->sample_rate) != 0) {
88 syslog(LOG_ERR, "cannot instantiate pipeline");
89 goto bail;
90 }
91
92 if (cras_dsp_pipeline_get_sample_rate(pipeline) != ctx->sample_rate) {
93 syslog(LOG_ERR, "pipeline sample rate mismatch (%d vs %d)",
94 cras_dsp_pipeline_get_sample_rate(pipeline),
95 ctx->sample_rate);
96 goto bail;
97 }
98
99 return pipeline;
100
101 bail:
102 if (pipeline)
103 destroy_pipeline(pipeline);
104 return NULL;
105 }
106
cmd_load_pipeline(struct cras_dsp_context * ctx,struct ini * target_ini)107 static void cmd_load_pipeline(struct cras_dsp_context *ctx,
108 struct ini *target_ini)
109 {
110 struct pipeline *pipeline, *old_pipeline;
111
112 pipeline = target_ini ? prepare_pipeline(ctx, target_ini) : NULL;
113
114 /* This locking is short to avoild blocking audio thread. */
115 pthread_mutex_lock(&ctx->mutex);
116 old_pipeline = ctx->pipeline;
117 ctx->pipeline = pipeline;
118 pthread_mutex_unlock(&ctx->mutex);
119
120 if (old_pipeline)
121 destroy_pipeline(old_pipeline);
122 }
123
cmd_reload_ini()124 static void cmd_reload_ini()
125 {
126 struct ini *old_ini = global_ini;
127 struct cras_dsp_context *ctx;
128
129 struct ini *new_ini = cras_dsp_ini_create(ini_filename);
130 if (!new_ini) {
131 syslog(LOG_DEBUG, "cannot create dsp ini");
132 return;
133 }
134
135 DL_FOREACH (context_list, ctx) {
136 cmd_load_pipeline(ctx, new_ini);
137 }
138
139 global_ini = new_ini;
140
141 if (old_ini)
142 cras_dsp_ini_free(old_ini);
143 }
144
145 /* Exported functions */
146
cras_dsp_init(const char * filename)147 void cras_dsp_init(const char *filename)
148 {
149 dsp_enable_flush_denormal_to_zero();
150 ini_filename = strdup(filename);
151 syslog_dumper = syslog_dumper_create(LOG_ERR);
152 cmd_reload_ini();
153 }
154
cras_dsp_stop()155 void cras_dsp_stop()
156 {
157 syslog_dumper_free(syslog_dumper);
158 if (ini_filename)
159 free((char *)ini_filename);
160 if (global_ini) {
161 cras_dsp_ini_free(global_ini);
162 global_ini = NULL;
163 }
164 }
165
cras_dsp_context_new(int sample_rate,const char * purpose)166 struct cras_dsp_context *cras_dsp_context_new(int sample_rate,
167 const char *purpose)
168 {
169 struct cras_dsp_context *ctx = calloc(1, sizeof(*ctx));
170
171 pthread_mutex_init(&ctx->mutex, NULL);
172 initialize_environment(&ctx->env);
173 ctx->sample_rate = sample_rate;
174 ctx->purpose = strdup(purpose);
175
176 DL_APPEND(context_list, ctx);
177 return ctx;
178 }
179
cras_dsp_context_free(struct cras_dsp_context * ctx)180 void cras_dsp_context_free(struct cras_dsp_context *ctx)
181 {
182 DL_DELETE(context_list, ctx);
183
184 pthread_mutex_destroy(&ctx->mutex);
185 if (ctx->pipeline) {
186 destroy_pipeline(ctx->pipeline);
187 ctx->pipeline = NULL;
188 }
189 cras_expr_env_free(&ctx->env);
190 free((char *)ctx->purpose);
191 free(ctx);
192 }
193
cras_dsp_set_variable_string(struct cras_dsp_context * ctx,const char * key,const char * value)194 void cras_dsp_set_variable_string(struct cras_dsp_context *ctx, const char *key,
195 const char *value)
196 {
197 cras_expr_env_set_variable_string(&ctx->env, key, value);
198 }
199
cras_dsp_set_variable_boolean(struct cras_dsp_context * ctx,const char * key,char value)200 void cras_dsp_set_variable_boolean(struct cras_dsp_context *ctx,
201 const char *key, char value)
202 {
203 cras_expr_env_set_variable_boolean(&ctx->env, key, value);
204 }
205
cras_dsp_load_pipeline(struct cras_dsp_context * ctx)206 void cras_dsp_load_pipeline(struct cras_dsp_context *ctx)
207 {
208 cmd_load_pipeline(ctx, global_ini);
209 }
210
cras_dsp_load_mock_pipeline(struct cras_dsp_context * ctx,unsigned int num_channels)211 void cras_dsp_load_mock_pipeline(struct cras_dsp_context *ctx,
212 unsigned int num_channels)
213 {
214 struct ini *mock_ini;
215 mock_ini = create_mock_ini(ctx->purpose, num_channels);
216 if (mock_ini == NULL)
217 syslog(LOG_ERR, "Failed to create mock ini");
218 else
219 cmd_load_pipeline(ctx, mock_ini);
220 }
221
cras_dsp_get_pipeline(struct cras_dsp_context * ctx)222 struct pipeline *cras_dsp_get_pipeline(struct cras_dsp_context *ctx)
223 {
224 pthread_mutex_lock(&ctx->mutex);
225 if (!ctx->pipeline) {
226 pthread_mutex_unlock(&ctx->mutex);
227 return NULL;
228 }
229 return ctx->pipeline;
230 }
231
cras_dsp_put_pipeline(struct cras_dsp_context * ctx)232 void cras_dsp_put_pipeline(struct cras_dsp_context *ctx)
233 {
234 pthread_mutex_unlock(&ctx->mutex);
235 }
236
cras_dsp_reload_ini()237 void cras_dsp_reload_ini()
238 {
239 cmd_reload_ini();
240 }
241
cras_dsp_dump_info()242 void cras_dsp_dump_info()
243 {
244 struct pipeline *pipeline;
245 struct cras_dsp_context *ctx;
246
247 if (global_ini)
248 cras_dsp_ini_dump(syslog_dumper, global_ini);
249 DL_FOREACH (context_list, ctx) {
250 cras_expr_env_dump(syslog_dumper, &ctx->env);
251 pipeline = ctx->pipeline;
252 if (pipeline)
253 cras_dsp_pipeline_dump(syslog_dumper, pipeline);
254 }
255 }
256
cras_dsp_num_output_channels(const struct cras_dsp_context * ctx)257 unsigned int cras_dsp_num_output_channels(const struct cras_dsp_context *ctx)
258 {
259 return cras_dsp_pipeline_get_num_output_channels(ctx->pipeline);
260 }
261
cras_dsp_num_input_channels(const struct cras_dsp_context * ctx)262 unsigned int cras_dsp_num_input_channels(const struct cras_dsp_context *ctx)
263 {
264 return cras_dsp_pipeline_get_num_input_channels(ctx->pipeline);
265 }
266