• 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  */
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 
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)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 
cras_system_state_set_internal_ucm_suffix(const char * internal_ucm_suffix)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 
cras_system_state_deinit()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 
cras_system_set_volume(size_t volume)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 
cras_system_get_volume()182 size_t cras_system_get_volume()
183 {
184 	return state.exp_state->volume;
185 }
186 
cras_system_set_capture_gain(long gain)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 
cras_system_get_capture_gain()197 long cras_system_get_capture_gain()
198 {
199 	return state.exp_state->capture_gain;
200 }
201 
cras_system_notify_mute(void)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 
cras_system_set_user_mute(int mute)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 
cras_system_set_mute(int mute)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 
cras_system_set_mute_locked(int locked)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 
cras_system_get_mute()250 int cras_system_get_mute()
251 {
252 	return state.exp_state->mute || state.exp_state->user_mute;
253 }
254 
cras_system_get_user_mute()255 int cras_system_get_user_mute()
256 {
257 	return state.exp_state->user_mute;
258 }
259 
cras_system_get_system_mute()260 int cras_system_get_system_mute()
261 {
262 	return state.exp_state->mute;
263 }
264 
cras_system_get_mute_locked()265 int cras_system_get_mute_locked()
266 {
267 	return state.exp_state->mute_locked;
268 }
269 
cras_system_notify_capture_mute(void)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 
cras_system_set_capture_mute(int mute)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 
cras_system_set_capture_mute_locked(int locked)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 
cras_system_get_capture_mute()291 int cras_system_get_capture_mute()
292 {
293 	return state.exp_state->capture_mute;
294 }
295 
cras_system_get_capture_mute_locked()296 int cras_system_get_capture_mute_locked()
297 {
298 	return state.exp_state->capture_mute_locked;
299 }
300 
cras_system_get_suspended()301 int cras_system_get_suspended()
302 {
303 	return state.exp_state->suspended;
304 }
305 
cras_system_set_suspended(int suspended)306 void cras_system_set_suspended(int suspended)
307 {
308 	state.exp_state->suspended = suspended;
309 	cras_observer_notify_suspend_changed(suspended);
310 }
311 
cras_system_set_volume_limits(long min,long max)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 
cras_system_get_min_volume()318 long cras_system_get_min_volume()
319 {
320 	return state.exp_state->min_volume_dBFS;
321 }
322 
cras_system_get_max_volume()323 long cras_system_get_max_volume()
324 {
325 	return state.exp_state->max_volume_dBFS;
326 }
327 
cras_system_set_capture_gain_limits(long min,long max)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 
cras_system_get_min_capture_gain()336 long cras_system_get_min_capture_gain()
337 {
338 	return state.exp_state->min_capture_gain;
339 }
340 
cras_system_get_max_capture_gain()341 long cras_system_get_max_capture_gain()
342 {
343 	return state.exp_state->max_capture_gain;
344 }
345 
cras_system_get_default_output_buffer_size()346 int cras_system_get_default_output_buffer_size()
347 {
348 	return state.exp_state->default_output_buffer_size;
349 }
350 
cras_system_get_aec_supported()351 int cras_system_get_aec_supported()
352 {
353 	return state.exp_state->aec_supported;
354 }
355 
cras_system_add_alsa_card(struct cras_alsa_card_info * alsa_card_info)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 
cras_system_remove_alsa_card(size_t alsa_card_index)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 
cras_system_alsa_card_exists(unsigned alsa_card_index)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 
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)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 
cras_system_add_select_fd(int fd,void (* callback)(void * data),void * callback_data)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 
cras_system_set_add_task_handler(int (* add_task)(void (* cb)(void * data),void * callback_data,void * task_data),void * task_data)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 
cras_system_add_task(void (* callback)(void * data),void * callback_data)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 
cras_system_rm_select_fd(int fd)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 
cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction)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 
cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction)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 
cras_system_state_get_active_streams()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 
cras_system_state_get_active_streams_by_direction(enum CRAS_STREAM_DIRECTION direction)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 
cras_system_state_get_last_stream_active_time(struct cras_timespec * ts)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 
cras_system_state_get_output_devs(const struct cras_iodev_info ** devs)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 
cras_system_state_get_input_devs(const struct cras_iodev_info ** devs)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 
cras_system_state_get_output_nodes(const struct cras_ionode_info ** nodes)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 
cras_system_state_get_input_nodes(const struct cras_ionode_info ** nodes)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 
cras_system_state_set_non_empty_status(int non_empty)551 void cras_system_state_set_non_empty_status(int non_empty)
552 {
553 	state.exp_state->non_empty_status = non_empty;
554 }
555 
cras_system_state_get_non_empty_status()556 int cras_system_state_get_non_empty_status()
557 {
558 	return state.exp_state->non_empty_status;
559 }
560 
cras_system_state_update_begin()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 
cras_system_state_update_complete()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 
cras_system_state_get_no_lock()578 struct cras_server_state *cras_system_state_get_no_lock()
579 {
580 	return state.exp_state;
581 }
582 
cras_sys_state_shm_fd()583 key_t cras_sys_state_shm_fd()
584 {
585 	return state.shm_fd_ro;
586 }
587 
cras_system_state_get_tm()588 struct cras_tm *cras_system_state_get_tm()
589 {
590 	return state.tm;
591 }
592 
593 
cras_system_state_dump_snapshots()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 
cras_system_state_add_snapshot(struct cras_audio_thread_snapshot * snapshot)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