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 <errno.h>
7 #include <fcntl.h>
8 #include <pthread.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <sys/mman.h>
12 #include <sys/param.h>
13 #include <sys/stat.h>
14 #include <syslog.h>
15 
16 #include "cras_alsa_card.h"
17 #include "cras_alert.h"
18 #include "cras_board_config.h"
19 #include "cras_config.h"
20 #include "cras_device_blocklist.h"
21 #include "cras_iodev_list.h"
22 #include "cras_observer.h"
23 #include "cras_shm.h"
24 #include "cras_system_state.h"
25 #include "cras_tm.h"
26 #include "cras_types.h"
27 #include "cras_util.h"
28 #include "utlist.h"
29 
30 struct card_list {
31 	struct cras_alsa_card *card;
32 	struct card_list *prev, *next;
33 };
34 
35 struct name_list {
36 	char name[NAME_MAX];
37 	struct name_list *prev, *next;
38 };
39 
40 /* The system state.
41  * Members:
42  *    exp_state - The exported system state shared with clients.
43  *    shm_name - Name of posix shm region for exported state.
44  *    shm_fd - fd for shm area of system_state struct.
45  *    shm_fd_ro - fd for shm area of system_state struct, opened read-only.
46  *        This copy is to dup and pass to clients.
47  *    shm_size - Size of the shm area.
48  *    device_config_dir - Directory of device configs where volume curves live.
49  *    internal_ucm_suffix - The suffix to append to internal card name to
50  *        control which ucm config file to load.
51  *    device_blocklist - Blocklist of device the server will ignore.
52  *    cards - A list of active sound cards in the system.
53  *    update_lock - Protects the update_count, as audio threads can update the
54  *      stream count.
55  *    tm - The system-wide timer manager.
56  *    add_task - Function to handle adding a task for main thread to execute.
57  *    task_data - Data to be passed to add_task handler function.
58  *    main_thread_tid - The thread id of the main thread.
59  *    bt_fix_a2dp_packet_size - The flag to override A2DP packet size set by
60  *      Blueetoh peer devices to a smaller default value.
61  */
62 static struct {
63 	struct cras_server_state *exp_state;
64 	char shm_name[NAME_MAX];
65 	int shm_fd;
66 	int shm_fd_ro;
67 	size_t shm_size;
68 	const char *device_config_dir;
69 	const char *internal_ucm_suffix;
70 	struct name_list *ignore_suffix_cards;
71 	struct cras_device_blocklist *device_blocklist;
72 	struct card_list *cards;
73 	pthread_mutex_t update_lock;
74 	struct cras_tm *tm;
75 	/* Select loop callback registration. */
76 	int (*fd_add)(int fd, void (*cb)(void *data, int events), void *cb_data,
77 		      int events, void *select_data);
78 	void (*fd_rm)(int fd, void *select_data);
79 	void *select_data;
80 	int (*add_task)(void (*callback)(void *data), void *callback_data,
81 			void *task_data);
82 	void *task_data;
83 	struct cras_audio_thread_snapshot_buffer snapshot_buffer;
84 	pthread_t main_thread_tid;
85 	bool bt_fix_a2dp_packet_size;
86 } state;
87 
88 /* The string format is CARD1,CARD2,CARD3. Divide it into a list. */
init_ignore_suffix_cards(char * str)89 void init_ignore_suffix_cards(char *str)
90 {
91 	struct name_list *card;
92 	char *ptr;
93 
94 	state.ignore_suffix_cards = NULL;
95 
96 	if (str == NULL)
97 		return;
98 
99 	ptr = strtok(str, ",");
100 	while (ptr != NULL) {
101 		card = (struct name_list *)calloc(1, sizeof(*card));
102 		if (!card) {
103 			syslog(LOG_ERR, "Failed to call calloc: %d", errno);
104 			return;
105 		}
106 		strncpy(card->name, ptr, NAME_MAX - 1);
107 		DL_APPEND(state.ignore_suffix_cards, card);
108 		ptr = strtok(NULL, ",");
109 	}
110 }
111 
deinit_ignore_suffix_cards()112 void deinit_ignore_suffix_cards()
113 {
114 	struct name_list *card;
115 	DL_FOREACH (state.ignore_suffix_cards, card) {
116 		DL_DELETE(state.ignore_suffix_cards, card);
117 		free(card);
118 	}
119 }
120 
121 /*
122  * Exported Interface.
123  */
124 
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)125 void cras_system_state_init(const char *device_config_dir, const char *shm_name,
126 			    int rw_shm_fd, int ro_shm_fd,
127 			    struct cras_server_state *exp_state,
128 			    size_t exp_state_size)
129 {
130 	struct cras_board_config board_config;
131 	int rc;
132 
133 	assert(sizeof(*exp_state) == exp_state_size);
134 	state.shm_size = sizeof(*exp_state);
135 
136 	strncpy(state.shm_name, shm_name, sizeof(state.shm_name));
137 	state.shm_name[sizeof(state.shm_name) - 1] = '\0';
138 	state.shm_fd = rw_shm_fd;
139 	state.shm_fd_ro = ro_shm_fd;
140 
141 	/* Read board config. */
142 	memset(&board_config, 0, sizeof(board_config));
143 	cras_board_config_get(device_config_dir, &board_config);
144 
145 	/* Initial system state. */
146 	exp_state->state_version = CRAS_SERVER_STATE_VERSION;
147 	exp_state->volume = CRAS_MAX_SYSTEM_VOLUME;
148 	exp_state->mute = 0;
149 	exp_state->mute_locked = 0;
150 	exp_state->suspended = 0;
151 	exp_state->capture_mute = 0;
152 	exp_state->capture_mute_locked = 0;
153 	exp_state->min_volume_dBFS = DEFAULT_MIN_VOLUME_DBFS;
154 	exp_state->max_volume_dBFS = DEFAULT_MAX_VOLUME_DBFS;
155 	exp_state->num_streams_attached = 0;
156 	exp_state->default_output_buffer_size =
157 		board_config.default_output_buffer_size;
158 	exp_state->aec_supported = board_config.aec_supported;
159 	exp_state->aec_group_id = board_config.aec_group_id;
160 	exp_state->bt_wbs_enabled = board_config.bt_wbs_enabled;
161 	exp_state->deprioritize_bt_wbs_mic =
162 		board_config.deprioritize_bt_wbs_mic;
163 	exp_state->noise_cancellation_enabled = 0;
164 	exp_state->hotword_pause_at_suspend =
165 		board_config.hotword_pause_at_suspend;
166 
167 	if ((rc = pthread_mutex_init(&state.update_lock, 0) != 0)) {
168 		syslog(LOG_ERR, "Fatal: system state mutex init");
169 		exit(rc);
170 	}
171 
172 	state.exp_state = exp_state;
173 
174 	/* Directory for volume curve configs.
175 	 * Note that device_config_dir does not affect device blocklist.
176 	 * Device blocklist is common to all boards so we do not need
177 	 * to change device blocklist at run time. */
178 	state.device_config_dir = device_config_dir;
179 	state.internal_ucm_suffix = NULL;
180 	init_ignore_suffix_cards(board_config.ucm_ignore_suffix);
181 	free(board_config.ucm_ignore_suffix);
182 
183 	state.tm = cras_tm_init();
184 	if (!state.tm) {
185 		syslog(LOG_ERR, "Fatal: system state timer init");
186 		exit(-ENOMEM);
187 	}
188 
189 	/* Read config file for blocklisted devices. */
190 	state.device_blocklist =
191 		cras_device_blocklist_create(CRAS_CONFIG_FILE_DIR);
192 
193 	/* Initialize snapshot buffer memory */
194 	memset(&state.snapshot_buffer, 0,
195 	       sizeof(struct cras_audio_thread_snapshot_buffer));
196 
197 	/* Save thread id of the main thread. */
198 	state.main_thread_tid = pthread_self();
199 
200 	state.bt_fix_a2dp_packet_size = false;
201 }
202 
cras_system_state_set_internal_ucm_suffix(const char * internal_ucm_suffix)203 void cras_system_state_set_internal_ucm_suffix(const char *internal_ucm_suffix)
204 {
205 	state.internal_ucm_suffix = internal_ucm_suffix;
206 }
207 
cras_system_state_deinit()208 void cras_system_state_deinit()
209 {
210 	/* Free any resources used.  This prevents unit tests from leaking. */
211 
212 	cras_device_blocklist_destroy(state.device_blocklist);
213 
214 	cras_tm_deinit(state.tm);
215 
216 	if (state.exp_state) {
217 		munmap(state.exp_state, state.shm_size);
218 		cras_shm_close_unlink(state.shm_name, state.shm_fd);
219 		if (state.shm_fd_ro != state.shm_fd)
220 			close(state.shm_fd_ro);
221 	}
222 
223 	deinit_ignore_suffix_cards();
224 	pthread_mutex_destroy(&state.update_lock);
225 }
226 
cras_system_set_volume(size_t volume)227 void cras_system_set_volume(size_t volume)
228 {
229 	if (volume > CRAS_MAX_SYSTEM_VOLUME)
230 		syslog(LOG_DEBUG, "system volume set out of range %zu", volume);
231 
232 	state.exp_state->volume = MIN(volume, CRAS_MAX_SYSTEM_VOLUME);
233 	cras_observer_notify_output_volume(state.exp_state->volume);
234 }
235 
cras_system_get_volume()236 size_t cras_system_get_volume()
237 {
238 	return state.exp_state->volume;
239 }
240 
cras_system_notify_mute(void)241 void cras_system_notify_mute(void)
242 {
243 	cras_observer_notify_output_mute(state.exp_state->mute,
244 					 state.exp_state->user_mute,
245 					 state.exp_state->mute_locked);
246 }
247 
cras_system_set_user_mute(int mute)248 void cras_system_set_user_mute(int mute)
249 {
250 	int current_mute = cras_system_get_mute();
251 
252 	if (state.exp_state->user_mute == !!mute)
253 		return;
254 
255 	state.exp_state->user_mute = !!mute;
256 
257 	if (current_mute == (mute || state.exp_state->mute))
258 		return;
259 
260 	cras_system_notify_mute();
261 }
262 
cras_system_set_mute(int mute)263 void cras_system_set_mute(int mute)
264 {
265 	int current_mute = cras_system_get_mute();
266 
267 	if (state.exp_state->mute_locked)
268 		return;
269 
270 	if (state.exp_state->mute == !!mute)
271 		return;
272 
273 	state.exp_state->mute = !!mute;
274 
275 	if (current_mute == (mute || state.exp_state->user_mute))
276 		return;
277 
278 	cras_system_notify_mute();
279 }
280 
cras_system_set_mute_locked(int locked)281 void cras_system_set_mute_locked(int locked)
282 {
283 	if (state.exp_state->mute_locked == !!locked)
284 		return;
285 
286 	state.exp_state->mute_locked = !!locked;
287 }
288 
cras_system_get_mute()289 int cras_system_get_mute()
290 {
291 	return state.exp_state->mute || state.exp_state->user_mute;
292 }
293 
cras_system_get_user_mute()294 int cras_system_get_user_mute()
295 {
296 	return state.exp_state->user_mute;
297 }
298 
cras_system_get_system_mute()299 int cras_system_get_system_mute()
300 {
301 	return state.exp_state->mute;
302 }
303 
cras_system_get_mute_locked()304 int cras_system_get_mute_locked()
305 {
306 	return state.exp_state->mute_locked;
307 }
308 
cras_system_notify_capture_mute(void)309 void cras_system_notify_capture_mute(void)
310 {
311 	cras_observer_notify_capture_mute(state.exp_state->capture_mute,
312 					  state.exp_state->capture_mute_locked);
313 }
314 
cras_system_set_capture_mute(int mute)315 void cras_system_set_capture_mute(int mute)
316 {
317 	if (state.exp_state->capture_mute_locked)
318 		return;
319 
320 	state.exp_state->capture_mute = !!mute;
321 	cras_system_notify_capture_mute();
322 }
323 
cras_system_set_capture_mute_locked(int locked)324 void cras_system_set_capture_mute_locked(int locked)
325 {
326 	state.exp_state->capture_mute_locked = !!locked;
327 	cras_system_notify_capture_mute();
328 }
329 
cras_system_get_capture_mute()330 int cras_system_get_capture_mute()
331 {
332 	return state.exp_state->capture_mute;
333 }
334 
cras_system_get_capture_mute_locked()335 int cras_system_get_capture_mute_locked()
336 {
337 	return state.exp_state->capture_mute_locked;
338 }
339 
cras_system_get_suspended()340 int cras_system_get_suspended()
341 {
342 	return state.exp_state->suspended;
343 }
344 
cras_system_set_suspended(int suspended)345 void cras_system_set_suspended(int suspended)
346 {
347 	state.exp_state->suspended = suspended;
348 	cras_observer_notify_suspend_changed(suspended);
349 	cras_alert_process_all_pending_alerts();
350 }
351 
cras_system_set_volume_limits(long min,long max)352 void cras_system_set_volume_limits(long min, long max)
353 {
354 	state.exp_state->min_volume_dBFS = min;
355 	state.exp_state->max_volume_dBFS = max;
356 }
357 
cras_system_get_min_volume()358 long cras_system_get_min_volume()
359 {
360 	return state.exp_state->min_volume_dBFS;
361 }
362 
cras_system_get_max_volume()363 long cras_system_get_max_volume()
364 {
365 	return state.exp_state->max_volume_dBFS;
366 }
367 
cras_system_get_default_output_buffer_size()368 int cras_system_get_default_output_buffer_size()
369 {
370 	return state.exp_state->default_output_buffer_size;
371 }
372 
cras_system_get_aec_supported()373 int cras_system_get_aec_supported()
374 {
375 	return state.exp_state->aec_supported;
376 }
377 
cras_system_get_aec_group_id()378 int cras_system_get_aec_group_id()
379 {
380 	return state.exp_state->aec_group_id;
381 }
382 
cras_system_set_bt_wbs_enabled(bool enabled)383 void cras_system_set_bt_wbs_enabled(bool enabled)
384 {
385 	state.exp_state->bt_wbs_enabled = enabled;
386 }
387 
cras_system_get_bt_wbs_enabled()388 bool cras_system_get_bt_wbs_enabled()
389 {
390 	return !!state.exp_state->bt_wbs_enabled;
391 }
392 
cras_system_get_deprioritize_bt_wbs_mic()393 bool cras_system_get_deprioritize_bt_wbs_mic()
394 {
395 	return !!state.exp_state->deprioritize_bt_wbs_mic;
396 }
397 
cras_system_set_bt_fix_a2dp_packet_size_enabled(bool enabled)398 void cras_system_set_bt_fix_a2dp_packet_size_enabled(bool enabled)
399 {
400 	state.bt_fix_a2dp_packet_size = enabled;
401 }
402 
cras_system_get_bt_fix_a2dp_packet_size_enabled()403 bool cras_system_get_bt_fix_a2dp_packet_size_enabled()
404 {
405 	return state.bt_fix_a2dp_packet_size;
406 }
407 
cras_system_set_noise_cancellation_enabled(bool enabled)408 void cras_system_set_noise_cancellation_enabled(bool enabled)
409 {
410 	/* When the flag is toggled, propagate to all iodevs immediately. */
411 	if (cras_system_get_noise_cancellation_enabled() != enabled) {
412 		state.exp_state->noise_cancellation_enabled = enabled;
413 		cras_iodev_list_reset_for_noise_cancellation();
414 	}
415 }
416 
cras_system_get_noise_cancellation_enabled()417 bool cras_system_get_noise_cancellation_enabled()
418 {
419 	return !!state.exp_state->noise_cancellation_enabled;
420 }
421 
cras_system_check_ignore_ucm_suffix(const char * card_name)422 bool cras_system_check_ignore_ucm_suffix(const char *card_name)
423 {
424 	/* Check the general case: ALSA Loopback card "Loopback". */
425 	if (!strcmp("Loopback", card_name))
426 		return true;
427 
428 	/* Check board-specific ignore ucm suffix cards. */
429 	struct name_list *card;
430 	DL_FOREACH (state.ignore_suffix_cards, card) {
431 		if (!strcmp(card->name, card_name))
432 			return true;
433 	}
434 	return false;
435 }
436 
cras_system_get_hotword_pause_at_suspend()437 bool cras_system_get_hotword_pause_at_suspend()
438 {
439 	return !!state.exp_state->hotword_pause_at_suspend;
440 }
441 
cras_system_set_hotword_pause_at_suspend(bool pause)442 void cras_system_set_hotword_pause_at_suspend(bool pause)
443 {
444 	state.exp_state->hotword_pause_at_suspend = pause;
445 }
446 
cras_system_add_alsa_card(struct cras_alsa_card_info * alsa_card_info)447 int cras_system_add_alsa_card(struct cras_alsa_card_info *alsa_card_info)
448 {
449 	struct card_list *card;
450 	struct cras_alsa_card *alsa_card;
451 	unsigned card_index;
452 
453 	if (alsa_card_info == NULL)
454 		return -EINVAL;
455 
456 	card_index = alsa_card_info->card_index;
457 
458 	DL_FOREACH (state.cards, card) {
459 		if (card_index == cras_alsa_card_get_index(card->card))
460 			return -EEXIST;
461 	}
462 	alsa_card =
463 		cras_alsa_card_create(alsa_card_info, state.device_config_dir,
464 				      state.device_blocklist,
465 				      state.internal_ucm_suffix);
466 	if (alsa_card == NULL)
467 		return -ENOMEM;
468 	card = calloc(1, sizeof(*card));
469 	if (card == NULL)
470 		return -ENOMEM;
471 	card->card = alsa_card;
472 	DL_APPEND(state.cards, card);
473 	return 0;
474 }
475 
cras_system_remove_alsa_card(size_t alsa_card_index)476 int cras_system_remove_alsa_card(size_t alsa_card_index)
477 {
478 	struct card_list *card;
479 
480 	DL_FOREACH (state.cards, card) {
481 		if (alsa_card_index == cras_alsa_card_get_index(card->card))
482 			break;
483 	}
484 	if (card == NULL)
485 		return -EINVAL;
486 	DL_DELETE(state.cards, card);
487 	cras_alsa_card_destroy(card->card);
488 	free(card);
489 	return 0;
490 }
491 
cras_system_alsa_card_exists(unsigned alsa_card_index)492 int cras_system_alsa_card_exists(unsigned alsa_card_index)
493 {
494 	struct card_list *card;
495 
496 	DL_FOREACH (state.cards, card)
497 		if (alsa_card_index == cras_alsa_card_get_index(card->card))
498 			return 1;
499 	return 0;
500 }
501 
cras_system_set_select_handler(int (* add)(int fd,void (* callback)(void * data,int events),void * callback_data,int events,void * select_data),void (* rm)(int fd,void * select_data),void * select_data)502 int cras_system_set_select_handler(
503 	int (*add)(int fd, void (*callback)(void *data, int events),
504 		   void *callback_data, int events, void *select_data),
505 	void (*rm)(int fd, void *select_data), void *select_data)
506 {
507 	if (state.fd_add != NULL || state.fd_rm != NULL)
508 		return -EEXIST;
509 	state.fd_add = add;
510 	state.fd_rm = rm;
511 	state.select_data = select_data;
512 	return 0;
513 }
514 
cras_system_add_select_fd(int fd,void (* callback)(void * data,int revents),void * callback_data,int events)515 int cras_system_add_select_fd(int fd, void (*callback)(void *data, int revents),
516 			      void *callback_data, int events)
517 {
518 	if (state.fd_add == NULL)
519 		return -EINVAL;
520 	return state.fd_add(fd, callback, callback_data, events,
521 			    state.select_data);
522 }
523 
cras_system_set_add_task_handler(int (* add_task)(void (* cb)(void * data),void * callback_data,void * task_data),void * task_data)524 int cras_system_set_add_task_handler(int (*add_task)(void (*cb)(void *data),
525 						     void *callback_data,
526 						     void *task_data),
527 				     void *task_data)
528 {
529 	if (state.add_task != NULL)
530 		return -EEXIST;
531 
532 	state.add_task = add_task;
533 	state.task_data = task_data;
534 	return 0;
535 }
536 
cras_system_add_task(void (* callback)(void * data),void * callback_data)537 int cras_system_add_task(void (*callback)(void *data), void *callback_data)
538 {
539 	if (state.add_task == NULL)
540 		return -EINVAL;
541 
542 	return state.add_task(callback, callback_data, state.task_data);
543 }
544 
cras_system_rm_select_fd(int fd)545 void cras_system_rm_select_fd(int fd)
546 {
547 	if (state.fd_rm != NULL)
548 		state.fd_rm(fd, state.select_data);
549 }
550 
cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,enum CRAS_CLIENT_TYPE client_type)551 void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,
552 				    enum CRAS_CLIENT_TYPE client_type)
553 {
554 	struct cras_server_state *s;
555 
556 	s = cras_system_state_update_begin();
557 	if (!s)
558 		return;
559 
560 	s->num_active_streams[direction]++;
561 	s->num_streams_attached++;
562 	if (direction == CRAS_STREAM_INPUT) {
563 		s->num_input_streams_with_permission[client_type]++;
564 		cras_observer_notify_input_streams_with_permission(
565 			s->num_input_streams_with_permission);
566 	}
567 
568 	cras_system_state_update_complete();
569 	cras_observer_notify_num_active_streams(
570 		direction, s->num_active_streams[direction]);
571 }
572 
cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,enum CRAS_CLIENT_TYPE client_type)573 void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,
574 				      enum CRAS_CLIENT_TYPE client_type)
575 {
576 	struct cras_server_state *s;
577 	unsigned i, sum;
578 
579 	s = cras_system_state_update_begin();
580 	if (!s)
581 		return;
582 
583 	sum = 0;
584 	for (i = 0; i < CRAS_NUM_DIRECTIONS; i++)
585 		sum += s->num_active_streams[i];
586 
587 	/* Set the last active time when removing the final stream. */
588 	if (sum == 1)
589 		cras_clock_gettime(CLOCK_MONOTONIC_RAW,
590 				   &s->last_active_stream_time);
591 	s->num_active_streams[direction]--;
592 	if (direction == CRAS_STREAM_INPUT) {
593 		s->num_input_streams_with_permission[client_type]--;
594 		cras_observer_notify_input_streams_with_permission(
595 			s->num_input_streams_with_permission);
596 	}
597 
598 	cras_system_state_update_complete();
599 	cras_observer_notify_num_active_streams(
600 		direction, s->num_active_streams[direction]);
601 }
602 
cras_system_state_get_active_streams()603 unsigned cras_system_state_get_active_streams()
604 {
605 	unsigned i, sum;
606 	sum = 0;
607 	for (i = 0; i < CRAS_NUM_DIRECTIONS; i++)
608 		sum += state.exp_state->num_active_streams[i];
609 	return sum;
610 }
611 
cras_system_state_get_active_streams_by_direction(enum CRAS_STREAM_DIRECTION direction)612 unsigned cras_system_state_get_active_streams_by_direction(
613 	enum CRAS_STREAM_DIRECTION direction)
614 {
615 	return state.exp_state->num_active_streams[direction];
616 }
617 
cras_system_state_get_input_streams_with_permission(uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])618 void cras_system_state_get_input_streams_with_permission(
619 	uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
620 {
621 	unsigned type;
622 	for (type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type)
623 		num_input_streams[type] =
624 			state.exp_state->num_input_streams_with_permission[type];
625 }
626 
cras_system_state_get_last_stream_active_time(struct cras_timespec * ts)627 void cras_system_state_get_last_stream_active_time(struct cras_timespec *ts)
628 {
629 	*ts = state.exp_state->last_active_stream_time;
630 }
631 
cras_system_state_get_output_devs(const struct cras_iodev_info ** devs)632 int cras_system_state_get_output_devs(const struct cras_iodev_info **devs)
633 {
634 	*devs = state.exp_state->output_devs;
635 	return state.exp_state->num_output_devs;
636 }
637 
cras_system_state_get_input_devs(const struct cras_iodev_info ** devs)638 int cras_system_state_get_input_devs(const struct cras_iodev_info **devs)
639 {
640 	*devs = state.exp_state->input_devs;
641 	return state.exp_state->num_input_devs;
642 }
643 
cras_system_state_get_output_nodes(const struct cras_ionode_info ** nodes)644 int cras_system_state_get_output_nodes(const struct cras_ionode_info **nodes)
645 {
646 	*nodes = state.exp_state->output_nodes;
647 	return state.exp_state->num_output_nodes;
648 }
649 
cras_system_state_get_input_nodes(const struct cras_ionode_info ** nodes)650 int cras_system_state_get_input_nodes(const struct cras_ionode_info **nodes)
651 {
652 	*nodes = state.exp_state->input_nodes;
653 	return state.exp_state->num_input_nodes;
654 }
655 
cras_system_state_set_non_empty_status(int non_empty)656 void cras_system_state_set_non_empty_status(int non_empty)
657 {
658 	state.exp_state->non_empty_status = non_empty;
659 }
660 
cras_system_state_get_non_empty_status()661 int cras_system_state_get_non_empty_status()
662 {
663 	return state.exp_state->non_empty_status;
664 }
665 
cras_system_state_update_begin()666 struct cras_server_state *cras_system_state_update_begin()
667 {
668 	if (pthread_mutex_lock(&state.update_lock)) {
669 		syslog(LOG_ERR, "Failed to lock stream mutex");
670 		return NULL;
671 	}
672 
673 	__sync_fetch_and_add(&state.exp_state->update_count, 1);
674 	return state.exp_state;
675 }
676 
cras_system_state_update_complete()677 void cras_system_state_update_complete()
678 {
679 	__sync_fetch_and_add(&state.exp_state->update_count, 1);
680 	pthread_mutex_unlock(&state.update_lock);
681 }
682 
cras_system_state_get_no_lock()683 struct cras_server_state *cras_system_state_get_no_lock()
684 {
685 	return state.exp_state;
686 }
687 
cras_sys_state_shm_fd()688 key_t cras_sys_state_shm_fd()
689 {
690 	return state.shm_fd_ro;
691 }
692 
cras_system_state_get_tm()693 struct cras_tm *cras_system_state_get_tm()
694 {
695 	return state.tm;
696 }
697 
cras_system_state_dump_snapshots()698 void cras_system_state_dump_snapshots()
699 {
700 	memcpy(&state.exp_state->snapshot_buffer, &state.snapshot_buffer,
701 	       sizeof(struct cras_audio_thread_snapshot_buffer));
702 }
703 
cras_system_state_add_snapshot(struct cras_audio_thread_snapshot * snapshot)704 void cras_system_state_add_snapshot(struct cras_audio_thread_snapshot *snapshot)
705 {
706 	state.snapshot_buffer.snapshots[state.snapshot_buffer.pos++] =
707 		(*snapshot);
708 	state.snapshot_buffer.pos %= CRAS_MAX_AUDIO_THREAD_SNAPSHOTS;
709 }
710 
cras_system_state_in_main_thread()711 int cras_system_state_in_main_thread()
712 {
713 	return pthread_self() == state.main_thread_tid;
714 }
715