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