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