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 <fcntl.h>
      7 #include <pthread.h>
      8 #include <string.h>
      9 #include <stdlib.h>
     10 #include <sys/mman.h>
     11 #include <sys/param.h>
     12 #include <sys/stat.h>
     13 #include <syslog.h>
     14 
     15 #include "cras_alsa_card.h"
     16 #include "cras_config.h"
     17 #include "cras_device_blacklist.h"
     18 #include "cras_observer.h"
     19 #include "cras_shm.h"
     20 #include "cras_system_state.h"
     21 #include "cras_tm.h"
     22 #include "cras_types.h"
     23 #include "cras_util.h"
     24 #include "utlist.h"
     25 
     26 struct card_list {
     27 	struct cras_alsa_card *card;
     28 	struct card_list *prev, *next;
     29 };
     30 
     31 /* The system state.
     32  * Members:
     33  *    exp_state - The exported system state shared with clients.
     34  *    shm_name - Name of posix shm region for exported state.
     35  *    shm_fd - fd for shm area of system_state struct.
     36  *    shm_fd_ro - fd for shm area of system_state struct, opened read-only.
     37  *    shm_size - Size of the shm area.
     38  *    device_config_dir - Directory of device configs where volume curves live.
     39  *    internal_ucm_suffix - The suffix to append to internal card name to
     40  *        control which ucm config file to load.
     41  *    device_blacklist - Blacklist of device the server will ignore.
     42  *    cards - A list of active sound cards in the system.
     43  *    update_lock - Protects the update_count, as audio threads can update the
     44  *      stream count.
     45  *    tm - The system-wide timer manager.
     46  */
     47 static struct {
     48 	struct cras_server_state *exp_state;
     49 	char shm_name[NAME_MAX];
     50 	int shm_fd;
     51 	int shm_fd_ro;
     52 	size_t shm_size;
     53 	const char *device_config_dir;
     54 	const char *internal_ucm_suffix;
     55 	struct cras_device_blacklist *device_blacklist;
     56 	struct card_list *cards;
     57 	pthread_mutex_t update_lock;
     58 	struct cras_tm *tm;
     59 	/* Select loop callback registration. */
     60 	int (*fd_add)(int fd, void (*cb)(void *data),
     61 		      void *cb_data, void *select_data);
     62 	void (*fd_rm)(int fd, void *select_data);
     63 	void *select_data;
     64 } state;
     65 
     66 /*
     67  * Exported Interface.
     68  */
     69 
     70 void cras_system_state_init(const char *device_config_dir)
     71 {
     72 	struct cras_server_state *exp_state;
     73 	int rc;
     74 
     75 	state.shm_size = sizeof(*exp_state);
     76 
     77 	snprintf(state.shm_name, sizeof(state.shm_name), "/cras-%d", getpid());
     78 	state.shm_fd = cras_shm_open_rw(state.shm_name, state.shm_size);
     79 	if (state.shm_fd < 0)
     80 		exit(state.shm_fd);
     81 
     82 	/* mmap shm. */
     83 	exp_state = mmap(NULL, state.shm_size,
     84 			 PROT_READ | PROT_WRITE, MAP_SHARED,
     85 			 state.shm_fd, 0);
     86 	if (exp_state == (struct cras_server_state *)-1)
     87 		exit(-ENOMEM);
     88 
     89 	/* Open a read-only copy to dup and pass to clients. */
     90 	state.shm_fd_ro = cras_shm_reopen_ro(state.shm_name, state.shm_fd);
     91 	if (state.shm_fd_ro < 0)
     92 		exit(state.shm_fd_ro);
     93 
     94 	/* Initial system state. */
     95 	exp_state->state_version = CRAS_SERVER_STATE_VERSION;
     96 	exp_state->volume = CRAS_MAX_SYSTEM_VOLUME;
     97 	exp_state->mute = 0;
     98 	exp_state->mute_locked = 0;
     99 	exp_state->suspended = 0;
    100 	exp_state->capture_gain = DEFAULT_CAPTURE_GAIN;
    101 	exp_state->capture_gain_target = DEFAULT_CAPTURE_GAIN;
    102 	exp_state->capture_mute = 0;
    103 	exp_state->capture_mute_locked = 0;
    104 	exp_state->min_volume_dBFS = DEFAULT_MIN_VOLUME_DBFS;
    105 	exp_state->max_volume_dBFS = DEFAULT_MAX_VOLUME_DBFS;
    106 	exp_state->min_capture_gain = DEFAULT_MIN_CAPTURE_GAIN;
    107 	exp_state->max_capture_gain = DEFAULT_MAX_CAPTURE_GAIN;
    108 	exp_state->num_streams_attached = 0;
    109 
    110 	if ((rc = pthread_mutex_init(&state.update_lock, 0) != 0)) {
    111 		syslog(LOG_ERR, "Fatal: system state mutex init");
    112 		exit(rc);
    113 	}
    114 
    115 	state.exp_state = exp_state;
    116 
    117 	/* Directory for volume curve configs.
    118 	 * Note that device_config_dir does not affect device blacklist.
    119 	 * Device blacklist is common to all boards so we do not need
    120 	 * to change device blacklist at run time. */
    121 	state.device_config_dir = device_config_dir;
    122 	state.internal_ucm_suffix = NULL;
    123 
    124 	state.tm = cras_tm_init();
    125 	if (!state.tm) {
    126 		syslog(LOG_ERR, "Fatal: system state timer init");
    127 		exit(-ENOMEM);
    128 	}
    129 
    130 	/* Read config file for blacklisted devices. */
    131 	state.device_blacklist =
    132 		cras_device_blacklist_create(CRAS_CONFIG_FILE_DIR);
    133 }
    134 
    135 void cras_system_state_set_internal_ucm_suffix(const char *internal_ucm_suffix)
    136 {
    137 	state.internal_ucm_suffix = internal_ucm_suffix;
    138 }
    139 
    140 void cras_system_state_deinit()
    141 {
    142 	/* Free any resources used.  This prevents unit tests from leaking. */
    143 
    144 	cras_device_blacklist_destroy(state.device_blacklist);
    145 
    146 	cras_tm_deinit(state.tm);
    147 
    148 	if (state.exp_state) {
    149 		munmap(state.exp_state, state.shm_size);
    150 		cras_shm_close_unlink(state.shm_name, state.shm_fd);
    151 		if (state.shm_fd_ro != state.shm_fd)
    152 			close(state.shm_fd_ro);
    153 	}
    154 
    155 	pthread_mutex_destroy(&state.update_lock);
    156 }
    157 
    158 void cras_system_set_volume(size_t volume)
    159 {
    160 	if (volume > CRAS_MAX_SYSTEM_VOLUME)
    161 		syslog(LOG_DEBUG, "system volume set out of range %zu", volume);
    162 
    163 	state.exp_state->volume = MIN(volume, CRAS_MAX_SYSTEM_VOLUME);
    164 	cras_observer_notify_output_volume(state.exp_state->volume);
    165 }
    166 
    167 size_t cras_system_get_volume()
    168 {
    169 	return state.exp_state->volume;
    170 }
    171 
    172 void cras_system_set_capture_gain(long gain)
    173 {
    174 	/* Adjust targeted gain to be in supported range. */
    175 	state.exp_state->capture_gain_target = gain;
    176 	gain = MAX(gain, state.exp_state->min_capture_gain);
    177 	gain = MIN(gain, state.exp_state->max_capture_gain);
    178 	state.exp_state->capture_gain = gain;
    179 	cras_observer_notify_capture_gain(state.exp_state->capture_gain);
    180 }
    181 
    182 long cras_system_get_capture_gain()
    183 {
    184 	return state.exp_state->capture_gain;
    185 }
    186 
    187 void cras_system_notify_mute(void)
    188 {
    189 	cras_observer_notify_output_mute(state.exp_state->mute,
    190 					 state.exp_state->user_mute,
    191 					 state.exp_state->mute_locked);
    192 }
    193 
    194 void cras_system_set_user_mute(int mute)
    195 {
    196 	if (state.exp_state->user_mute == !!mute)
    197 		return;
    198 
    199 	state.exp_state->user_mute = !!mute;
    200 	cras_system_notify_mute();
    201 }
    202 
    203 void cras_system_set_mute(int mute)
    204 {
    205 	if (state.exp_state->mute_locked)
    206 		return;
    207 
    208 	if (state.exp_state->mute == !!mute)
    209 		return;
    210 
    211 	state.exp_state->mute = !!mute;
    212 	cras_system_notify_mute();
    213 }
    214 
    215 void cras_system_set_mute_locked(int locked)
    216 {
    217 	if (state.exp_state->mute_locked == !!locked)
    218 		return;
    219 
    220 	state.exp_state->mute_locked = !!locked;
    221 	cras_system_notify_mute();
    222 }
    223 
    224 int cras_system_get_mute()
    225 {
    226 	return state.exp_state->mute || state.exp_state->user_mute;
    227 }
    228 
    229 int cras_system_get_user_mute()
    230 {
    231 	return state.exp_state->user_mute;
    232 }
    233 
    234 int cras_system_get_system_mute()
    235 {
    236 	return state.exp_state->mute;
    237 }
    238 
    239 int cras_system_get_mute_locked()
    240 {
    241 	return state.exp_state->mute_locked;
    242 }
    243 
    244 void cras_system_notify_capture_mute(void)
    245 {
    246 	cras_observer_notify_capture_mute(state.exp_state->capture_mute,
    247 					  state.exp_state->capture_mute_locked);
    248 }
    249 
    250 void cras_system_set_capture_mute(int mute)
    251 {
    252 	if (state.exp_state->capture_mute_locked)
    253 		return;
    254 
    255 	state.exp_state->capture_mute = !!mute;
    256 	cras_system_notify_capture_mute();
    257 }
    258 
    259 void cras_system_set_capture_mute_locked(int locked)
    260 {
    261 	state.exp_state->capture_mute_locked = !!locked;
    262 	cras_system_notify_capture_mute();
    263 }
    264 
    265 int cras_system_get_capture_mute()
    266 {
    267 	return state.exp_state->capture_mute;
    268 }
    269 
    270 int cras_system_get_capture_mute_locked()
    271 {
    272 	return state.exp_state->capture_mute_locked;
    273 }
    274 
    275 int cras_system_get_suspended()
    276 {
    277 	return state.exp_state->suspended;
    278 }
    279 
    280 void cras_system_set_suspended(int suspended)
    281 {
    282 	state.exp_state->suspended = suspended;
    283 	cras_observer_notify_suspend_changed(suspended);
    284 }
    285 
    286 void cras_system_set_volume_limits(long min, long max)
    287 {
    288 	state.exp_state->min_volume_dBFS = min;
    289 	state.exp_state->max_volume_dBFS = max;
    290 }
    291 
    292 long cras_system_get_min_volume()
    293 {
    294 	return state.exp_state->min_volume_dBFS;
    295 }
    296 
    297 long cras_system_get_max_volume()
    298 {
    299 	return state.exp_state->max_volume_dBFS;
    300 }
    301 
    302 void cras_system_set_capture_gain_limits(long min, long max)
    303 {
    304 	state.exp_state->min_capture_gain = MAX(min, DEFAULT_MIN_CAPTURE_GAIN);
    305 	state.exp_state->max_capture_gain = max;
    306 	/* Re-apply target gain subjected to the new supported range. */
    307 	cras_system_set_capture_gain(state.exp_state->capture_gain_target);
    308 }
    309 
    310 long cras_system_get_min_capture_gain()
    311 {
    312 	return state.exp_state->min_capture_gain;
    313 }
    314 
    315 long cras_system_get_max_capture_gain()
    316 {
    317 	return state.exp_state->max_capture_gain;
    318 }
    319 
    320 int cras_system_add_alsa_card(struct cras_alsa_card_info *alsa_card_info)
    321 {
    322 	struct card_list *card;
    323 	struct cras_alsa_card *alsa_card;
    324 	unsigned card_index;
    325 
    326 	if (alsa_card_info == NULL)
    327 		return -EINVAL;
    328 
    329 	card_index = alsa_card_info->card_index;
    330 
    331 	DL_FOREACH(state.cards, card) {
    332 		if (card_index == cras_alsa_card_get_index(card->card))
    333 			return -EINVAL;
    334 	}
    335 	alsa_card = cras_alsa_card_create(
    336 			alsa_card_info,
    337 			state.device_config_dir,
    338 			state.device_blacklist,
    339 			(alsa_card_info->card_type == ALSA_CARD_TYPE_INTERNAL)
    340 				? state.internal_ucm_suffix
    341 				: NULL);
    342 	if (alsa_card == NULL)
    343 		return -ENOMEM;
    344 	card = calloc(1, sizeof(*card));
    345 	if (card == NULL)
    346 		return -ENOMEM;
    347 	card->card = alsa_card;
    348 	DL_APPEND(state.cards, card);
    349 	return 0;
    350 }
    351 
    352 int cras_system_remove_alsa_card(size_t alsa_card_index)
    353 {
    354 	struct card_list *card;
    355 
    356 	DL_FOREACH(state.cards, card) {
    357 		if (alsa_card_index == cras_alsa_card_get_index(card->card))
    358 			break;
    359 	}
    360 	if (card == NULL)
    361 		return -EINVAL;
    362 	DL_DELETE(state.cards, card);
    363 	cras_alsa_card_destroy(card->card);
    364 	free(card);
    365 	return 0;
    366 }
    367 
    368 int cras_system_alsa_card_exists(unsigned alsa_card_index)
    369 {
    370 	struct card_list *card;
    371 
    372 	DL_FOREACH(state.cards, card)
    373 		if (alsa_card_index == cras_alsa_card_get_index(card->card))
    374 			return 1;
    375 	return 0;
    376 }
    377 
    378 int cras_system_set_select_handler(int (*add)(int fd,
    379 					      void (*callback)(void *data),
    380 					      void *callback_data,
    381 					      void *select_data),
    382 				   void (*rm)(int fd, void *select_data),
    383 				   void *select_data)
    384 {
    385 	if (state.fd_add != NULL || state.fd_rm != NULL)
    386 		return -EEXIST;
    387 	state.fd_add = add;
    388 	state.fd_rm = rm;
    389 	state.select_data = select_data;
    390 	return 0;
    391 }
    392 
    393 int cras_system_add_select_fd(int fd,
    394 			      void (*callback)(void *data),
    395 			      void *callback_data)
    396 {
    397 	if (state.fd_add == NULL)
    398 		return -EINVAL;
    399 	return state.fd_add(fd, callback, callback_data,
    400 			    state.select_data);
    401 }
    402 
    403 void cras_system_rm_select_fd(int fd)
    404 {
    405 	if (state.fd_rm != NULL)
    406 		state.fd_rm(fd, state.select_data);
    407 }
    408 
    409 void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction)
    410 {
    411 	struct cras_server_state *s;
    412 
    413 	s = cras_system_state_update_begin();
    414 	if (!s)
    415 		return;
    416 
    417 	s->num_active_streams[direction]++;
    418 	s->num_streams_attached++;
    419 
    420 	cras_system_state_update_complete();
    421 	cras_observer_notify_num_active_streams(
    422 		direction, s->num_active_streams[direction]);
    423 }
    424 
    425 void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction)
    426 {
    427 	struct cras_server_state *s;
    428 	unsigned i, sum;
    429 
    430 
    431 	s = cras_system_state_update_begin();
    432 	if (!s)
    433 		return;
    434 
    435 	sum = 0;
    436 	for (i=0; i < CRAS_NUM_DIRECTIONS; i++)
    437 		sum += s->num_active_streams[i];
    438 
    439 	/* Set the last active time when removing the final stream. */
    440 	if (sum == 1)
    441 		cras_clock_gettime(CLOCK_MONOTONIC_RAW,
    442 				   &s->last_active_stream_time);
    443 	s->num_active_streams[direction]--;
    444 
    445 	cras_system_state_update_complete();
    446 	cras_observer_notify_num_active_streams(
    447 		direction, s->num_active_streams[direction]);
    448 }
    449 
    450 unsigned cras_system_state_get_active_streams()
    451 {
    452 	unsigned i, sum;
    453 	sum = 0;
    454 	for (i=0; i < CRAS_NUM_DIRECTIONS; i++)
    455 		sum += state.exp_state->num_active_streams[i];
    456 	return sum;
    457 }
    458 
    459 unsigned cras_system_state_get_active_streams_by_direction(
    460 	enum CRAS_STREAM_DIRECTION direction)
    461 {
    462 	return state.exp_state->num_active_streams[direction];
    463 }
    464 
    465 void cras_system_state_get_last_stream_active_time(struct cras_timespec *ts)
    466 {
    467 	*ts = state.exp_state->last_active_stream_time;
    468 }
    469 
    470 int cras_system_state_get_output_devs(const struct cras_iodev_info **devs)
    471 {
    472 	*devs = state.exp_state->output_devs;
    473 	return state.exp_state->num_output_devs;
    474 }
    475 
    476 int cras_system_state_get_input_devs(const struct cras_iodev_info **devs)
    477 {
    478 	*devs = state.exp_state->input_devs;
    479 	return state.exp_state->num_input_devs;
    480 }
    481 
    482 int cras_system_state_get_output_nodes(const struct cras_ionode_info **nodes)
    483 {
    484 	*nodes = state.exp_state->output_nodes;
    485 	return state.exp_state->num_output_nodes;
    486 }
    487 
    488 int cras_system_state_get_input_nodes(const struct cras_ionode_info **nodes)
    489 {
    490 	*nodes = state.exp_state->input_nodes;
    491 	return state.exp_state->num_input_nodes;
    492 }
    493 
    494 struct cras_server_state *cras_system_state_update_begin()
    495 {
    496 	if (pthread_mutex_lock(&state.update_lock)) {
    497 		syslog(LOG_ERR, "Failed to lock stream mutex");
    498 		return NULL;
    499 	}
    500 
    501 	__sync_fetch_and_add(&state.exp_state->update_count, 1);
    502 	return state.exp_state;
    503 }
    504 
    505 void cras_system_state_update_complete()
    506 {
    507 	__sync_fetch_and_add(&state.exp_state->update_count, 1);
    508 	pthread_mutex_unlock(&state.update_lock);
    509 }
    510 
    511 struct cras_server_state *cras_system_state_get_no_lock()
    512 {
    513 	return state.exp_state;
    514 }
    515 
    516 key_t cras_sys_state_shm_fd()
    517 {
    518 	return state.shm_fd_ro;
    519 }
    520 
    521 struct cras_tm *cras_system_state_get_tm()
    522 {
    523 	return state.tm;
    524 }
    525