Home | History | Annotate | Download | only in server
      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