• 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 
prepare_pipeline(struct cras_dsp_context * ctx,struct ini * target_ini)51 static struct pipeline *prepare_pipeline(
52 		struct cras_dsp_context *ctx,
53 		struct ini *target_ini)
54 {
55 	struct pipeline *pipeline;
56 	const char *purpose = ctx->purpose;
57 
58 	pipeline = cras_dsp_pipeline_create(target_ini, &ctx->env, purpose);
59 
60 	if (pipeline) {
61 		syslog(LOG_DEBUG, "pipeline created");
62 	} else {
63 		syslog(LOG_DEBUG, "cannot create pipeline");
64 		goto bail;
65 	}
66 
67 	if (cras_dsp_pipeline_load(pipeline) != 0) {
68 		syslog(LOG_ERR, "cannot load pipeline");
69 		goto bail;
70 	}
71 
72 	if (cras_dsp_pipeline_instantiate(pipeline, ctx->sample_rate) != 0) {
73 		syslog(LOG_ERR, "cannot instantiate pipeline");
74 		goto bail;
75 	}
76 
77 	if (cras_dsp_pipeline_get_sample_rate(pipeline) != ctx->sample_rate) {
78 		syslog(LOG_ERR, "pipeline sample rate mismatch (%d vs %d)",
79 		       cras_dsp_pipeline_get_sample_rate(pipeline),
80 		       ctx->sample_rate);
81 		goto bail;
82 	}
83 
84 	return pipeline;
85 
86 bail:
87 	if (pipeline)
88 		cras_dsp_pipeline_free(pipeline);
89 	return NULL;
90 }
91 
cmd_load_pipeline(struct cras_dsp_context * ctx,struct ini * target_ini)92 static void cmd_load_pipeline(struct cras_dsp_context *ctx,
93 			      struct ini *target_ini)
94 {
95 	struct pipeline *pipeline, *old_pipeline;
96 
97 	pipeline = target_ini ? prepare_pipeline(ctx, target_ini) : NULL;
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 		return;
118 	}
119 
120 
121 	DL_FOREACH(context_list, ctx) {
122 		cmd_load_pipeline(ctx, ini);
123 	}
124 
125 	if (old_ini)
126 		cras_dsp_ini_free(old_ini);
127 }
128 
129 /* Exported functions */
130 
cras_dsp_init(const char * filename)131 void cras_dsp_init(const char *filename)
132 {
133 	dsp_enable_flush_denormal_to_zero();
134 	ini_filename = strdup(filename);
135 	syslog_dumper = syslog_dumper_create(LOG_ERR);
136 	cmd_reload_ini();
137 }
138 
cras_dsp_stop()139 void cras_dsp_stop()
140 {
141 	syslog_dumper_free(syslog_dumper);
142 	free((char *)ini_filename);
143 	if (ini) {
144 		cras_dsp_ini_free(ini);
145 		ini = NULL;
146 	}
147 }
148 
cras_dsp_context_new(int sample_rate,const char * purpose)149 struct cras_dsp_context *cras_dsp_context_new(int sample_rate,
150 					      const char *purpose)
151 {
152 	struct cras_dsp_context *ctx = calloc(1, sizeof(*ctx));
153 
154 	pthread_mutex_init(&ctx->mutex, NULL);
155 	initialize_environment(&ctx->env);
156 	ctx->sample_rate = sample_rate;
157 	ctx->purpose = strdup(purpose);
158 
159 	DL_APPEND(context_list, ctx);
160 	return ctx;
161 }
162 
cras_dsp_context_free(struct cras_dsp_context * ctx)163 void cras_dsp_context_free(struct cras_dsp_context *ctx)
164 {
165 	DL_DELETE(context_list, ctx);
166 
167 	pthread_mutex_destroy(&ctx->mutex);
168 	if (ctx->pipeline) {
169 		cras_dsp_pipeline_free(ctx->pipeline);
170 		ctx->pipeline = NULL;
171 	}
172 	cras_expr_env_free(&ctx->env);
173 	free((char *)ctx->purpose);
174 	free(ctx);
175 }
176 
cras_dsp_set_variable_string(struct cras_dsp_context * ctx,const char * key,const char * value)177 void cras_dsp_set_variable_string(struct cras_dsp_context *ctx, const char *key,
178 			   const char *value)
179 {
180 	cras_expr_env_set_variable_string(&ctx->env, key, value);
181 }
182 
cras_dsp_set_variable_boolean(struct cras_dsp_context * ctx,const char * key,char value)183 void cras_dsp_set_variable_boolean(struct cras_dsp_context *ctx,
184 				   const char *key,
185 				   char value)
186 {
187 	cras_expr_env_set_variable_boolean(&ctx->env, key, value);
188 }
189 
cras_dsp_load_pipeline(struct cras_dsp_context * ctx)190 void cras_dsp_load_pipeline(struct cras_dsp_context *ctx)
191 {
192 	cmd_load_pipeline(ctx, ini);
193 }
194 
cras_dsp_load_dummy_pipeline(struct cras_dsp_context * ctx,unsigned int num_channels)195 void cras_dsp_load_dummy_pipeline(struct cras_dsp_context *ctx,
196 				  unsigned int num_channels)
197 {
198 	struct ini *dummy_ini;
199 	dummy_ini = create_dummy_ini(ctx->purpose, num_channels);
200 	cmd_load_pipeline(ctx, dummy_ini);
201 	cras_dsp_ini_free((dummy_ini));
202 }
203 
cras_dsp_get_pipeline(struct cras_dsp_context * ctx)204 struct pipeline *cras_dsp_get_pipeline(struct cras_dsp_context *ctx)
205 {
206 	pthread_mutex_lock(&ctx->mutex);
207 	if (!ctx->pipeline) {
208 		pthread_mutex_unlock(&ctx->mutex);
209 		return NULL;
210 	}
211 	return ctx->pipeline;
212 }
213 
cras_dsp_put_pipeline(struct cras_dsp_context * ctx)214 void cras_dsp_put_pipeline(struct cras_dsp_context *ctx)
215 {
216 	pthread_mutex_unlock(&ctx->mutex);
217 }
218 
cras_dsp_reload_ini()219 void cras_dsp_reload_ini()
220 {
221 	cmd_reload_ini();
222 }
223 
cras_dsp_dump_info()224 void cras_dsp_dump_info()
225 {
226 	struct pipeline *pipeline;
227 	struct cras_dsp_context *ctx;
228 
229 	if (ini)
230 		cras_dsp_ini_dump(syslog_dumper, ini);
231 	DL_FOREACH(context_list, ctx) {
232 		cras_expr_env_dump(syslog_dumper, &ctx->env);
233 		pipeline = ctx->pipeline;
234 		if (pipeline)
235 			cras_dsp_pipeline_dump(syslog_dumper, pipeline);
236 	}
237 }
238 
cras_dsp_num_output_channels(const struct cras_dsp_context * ctx)239 unsigned int cras_dsp_num_output_channels(const struct cras_dsp_context *ctx)
240 {
241 	return cras_dsp_pipeline_get_num_output_channels(ctx->pipeline);
242 }
243 
cras_dsp_num_input_channels(const struct cras_dsp_context * ctx)244 unsigned int cras_dsp_num_input_channels(const struct cras_dsp_context *ctx)
245 {
246 	return cras_dsp_pipeline_get_num_input_channels(ctx->pipeline);
247 }
248