• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 != 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 = ini;
127 	struct cras_dsp_context *ctx;
128 
129 	ini = cras_dsp_ini_create(ini_filename);
130 	if (!ini) {
131 		syslog(LOG_DEBUG, "cannot create dsp ini");
132 		return;
133 	}
134 
135 	DL_FOREACH (context_list, ctx) {
136 		cmd_load_pipeline(ctx, ini);
137 	}
138 
139 	if (old_ini)
140 		cras_dsp_ini_free(old_ini);
141 }
142 
143 /* Exported functions */
144 
cras_dsp_init(const char * filename)145 void cras_dsp_init(const char *filename)
146 {
147 	dsp_enable_flush_denormal_to_zero();
148 	ini_filename = strdup(filename);
149 	syslog_dumper = syslog_dumper_create(LOG_ERR);
150 	cmd_reload_ini();
151 }
152 
cras_dsp_stop()153 void cras_dsp_stop()
154 {
155 	syslog_dumper_free(syslog_dumper);
156 	free((char *)ini_filename);
157 	if (ini) {
158 		cras_dsp_ini_free(ini);
159 		ini = NULL;
160 	}
161 }
162 
cras_dsp_context_new(int sample_rate,const char * purpose)163 struct cras_dsp_context *cras_dsp_context_new(int sample_rate,
164 					      const char *purpose)
165 {
166 	struct cras_dsp_context *ctx = calloc(1, sizeof(*ctx));
167 
168 	pthread_mutex_init(&ctx->mutex, NULL);
169 	initialize_environment(&ctx->env);
170 	ctx->sample_rate = sample_rate;
171 	ctx->purpose = strdup(purpose);
172 
173 	DL_APPEND(context_list, ctx);
174 	return ctx;
175 }
176 
cras_dsp_context_free(struct cras_dsp_context * ctx)177 void cras_dsp_context_free(struct cras_dsp_context *ctx)
178 {
179 	DL_DELETE(context_list, ctx);
180 
181 	pthread_mutex_destroy(&ctx->mutex);
182 	if (ctx->pipeline) {
183 		destroy_pipeline(ctx->pipeline);
184 		ctx->pipeline = NULL;
185 	}
186 	cras_expr_env_free(&ctx->env);
187 	free((char *)ctx->purpose);
188 	free(ctx);
189 }
190 
cras_dsp_set_variable_string(struct cras_dsp_context * ctx,const char * key,const char * value)191 void cras_dsp_set_variable_string(struct cras_dsp_context *ctx, const char *key,
192 				  const char *value)
193 {
194 	cras_expr_env_set_variable_string(&ctx->env, key, value);
195 }
196 
cras_dsp_set_variable_boolean(struct cras_dsp_context * ctx,const char * key,char value)197 void cras_dsp_set_variable_boolean(struct cras_dsp_context *ctx,
198 				   const char *key, char value)
199 {
200 	cras_expr_env_set_variable_boolean(&ctx->env, key, value);
201 }
202 
cras_dsp_load_pipeline(struct cras_dsp_context * ctx)203 void cras_dsp_load_pipeline(struct cras_dsp_context *ctx)
204 {
205 	cmd_load_pipeline(ctx, ini);
206 }
207 
cras_dsp_load_dummy_pipeline(struct cras_dsp_context * ctx,unsigned int num_channels)208 void cras_dsp_load_dummy_pipeline(struct cras_dsp_context *ctx,
209 				  unsigned int num_channels)
210 {
211 	struct ini *dummy_ini;
212 	dummy_ini = create_dummy_ini(ctx->purpose, num_channels);
213 	if (dummy_ini == NULL)
214 		syslog(LOG_ERR, "Failed to create dummy ini");
215 	else
216 		cmd_load_pipeline(ctx, dummy_ini);
217 }
218 
cras_dsp_get_pipeline(struct cras_dsp_context * ctx)219 struct pipeline *cras_dsp_get_pipeline(struct cras_dsp_context *ctx)
220 {
221 	pthread_mutex_lock(&ctx->mutex);
222 	if (!ctx->pipeline) {
223 		pthread_mutex_unlock(&ctx->mutex);
224 		return NULL;
225 	}
226 	return ctx->pipeline;
227 }
228 
cras_dsp_put_pipeline(struct cras_dsp_context * ctx)229 void cras_dsp_put_pipeline(struct cras_dsp_context *ctx)
230 {
231 	pthread_mutex_unlock(&ctx->mutex);
232 }
233 
cras_dsp_reload_ini()234 void cras_dsp_reload_ini()
235 {
236 	cmd_reload_ini();
237 }
238 
cras_dsp_dump_info()239 void cras_dsp_dump_info()
240 {
241 	struct pipeline *pipeline;
242 	struct cras_dsp_context *ctx;
243 
244 	if (ini)
245 		cras_dsp_ini_dump(syslog_dumper, ini);
246 	DL_FOREACH (context_list, ctx) {
247 		cras_expr_env_dump(syslog_dumper, &ctx->env);
248 		pipeline = ctx->pipeline;
249 		if (pipeline)
250 			cras_dsp_pipeline_dump(syslog_dumper, pipeline);
251 	}
252 }
253 
cras_dsp_num_output_channels(const struct cras_dsp_context * ctx)254 unsigned int cras_dsp_num_output_channels(const struct cras_dsp_context *ctx)
255 {
256 	return cras_dsp_pipeline_get_num_output_channels(ctx->pipeline);
257 }
258 
cras_dsp_num_input_channels(const struct cras_dsp_context * ctx)259 unsigned int cras_dsp_num_input_channels(const struct cras_dsp_context *ctx)
260 {
261 	return cras_dsp_pipeline_get_num_input_channels(ctx->pipeline);
262 }
263