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
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
prepare_pipeline(struct cras_dsp_context * ctx)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
cmd_load_pipeline(struct cras_dsp_context * ctx)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
cmd_reload_ini()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
cras_dsp_init(const char * filename)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
cras_dsp_stop()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
cras_dsp_context_new(int sample_rate,const char * purpose)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
cras_dsp_context_free(struct cras_dsp_context * ctx)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
cras_dsp_set_variable_string(struct cras_dsp_context * ctx,const char * key,const char * value)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
cras_dsp_set_variable_boolean(struct cras_dsp_context * ctx,const char * key,char value)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
cras_dsp_load_pipeline(struct cras_dsp_context * ctx)187 void cras_dsp_load_pipeline(struct cras_dsp_context *ctx)
188 {
189 cmd_load_pipeline(ctx);
190 }
191
cras_dsp_get_pipeline(struct cras_dsp_context * ctx)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
cras_dsp_put_pipeline(struct cras_dsp_context * ctx)202 void cras_dsp_put_pipeline(struct cras_dsp_context *ctx)
203 {
204 pthread_mutex_unlock(&ctx->mutex);
205 }
206
cras_dsp_reload_ini()207 void cras_dsp_reload_ini()
208 {
209 cmd_reload_ini();
210 }
211
cras_dsp_dump_info()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
cras_dsp_num_output_channels(const struct cras_dsp_context * ctx)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
cras_dsp_num_input_channels(const struct cras_dsp_context * ctx)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