• 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_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 
cras_system_state_init(const char * device_config_dir)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 
cras_system_state_set_internal_ucm_suffix(const char * internal_ucm_suffix)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 
cras_system_state_deinit()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 
cras_system_set_volume(size_t volume)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 
cras_system_get_volume()167 size_t cras_system_get_volume()
168 {
169 	return state.exp_state->volume;
170 }
171 
cras_system_set_capture_gain(long gain)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 
cras_system_get_capture_gain()182 long cras_system_get_capture_gain()
183 {
184 	return state.exp_state->capture_gain;
185 }
186 
cras_system_notify_mute(void)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 
cras_system_set_user_mute(int mute)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 
cras_system_set_mute(int mute)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 
cras_system_set_mute_locked(int locked)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 
cras_system_get_mute()224 int cras_system_get_mute()
225 {
226 	return state.exp_state->mute || state.exp_state->user_mute;
227 }
228 
cras_system_get_user_mute()229 int cras_system_get_user_mute()
230 {
231 	return state.exp_state->user_mute;
232 }
233 
cras_system_get_system_mute()234 int cras_system_get_system_mute()
235 {
236 	return state.exp_state->mute;
237 }
238 
cras_system_get_mute_locked()239 int cras_system_get_mute_locked()
240 {
241 	return state.exp_state->mute_locked;
242 }
243 
cras_system_notify_capture_mute(void)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 
cras_system_set_capture_mute(int mute)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 
cras_system_set_capture_mute_locked(int locked)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 
cras_system_get_capture_mute()265 int cras_system_get_capture_mute()
266 {
267 	return state.exp_state->capture_mute;
268 }
269 
cras_system_get_capture_mute_locked()270 int cras_system_get_capture_mute_locked()
271 {
272 	return state.exp_state->capture_mute_locked;
273 }
274 
cras_system_get_suspended()275 int cras_system_get_suspended()
276 {
277 	return state.exp_state->suspended;
278 }
279 
cras_system_set_suspended(int suspended)280 void cras_system_set_suspended(int suspended)
281 {
282 	state.exp_state->suspended = suspended;
283 	cras_observer_notify_suspend_changed(suspended);
284 }
285 
cras_system_set_volume_limits(long min,long max)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 
cras_system_get_min_volume()292 long cras_system_get_min_volume()
293 {
294 	return state.exp_state->min_volume_dBFS;
295 }
296 
cras_system_get_max_volume()297 long cras_system_get_max_volume()
298 {
299 	return state.exp_state->max_volume_dBFS;
300 }
301 
cras_system_set_capture_gain_limits(long min,long max)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 
cras_system_get_min_capture_gain()310 long cras_system_get_min_capture_gain()
311 {
312 	return state.exp_state->min_capture_gain;
313 }
314 
cras_system_get_max_capture_gain()315 long cras_system_get_max_capture_gain()
316 {
317 	return state.exp_state->max_capture_gain;
318 }
319 
cras_system_add_alsa_card(struct cras_alsa_card_info * alsa_card_info)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 
cras_system_remove_alsa_card(size_t alsa_card_index)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 
cras_system_alsa_card_exists(unsigned alsa_card_index)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 
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)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 
cras_system_add_select_fd(int fd,void (* callback)(void * data),void * callback_data)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 
cras_system_rm_select_fd(int fd)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 
cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction)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 
cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction)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 
cras_system_state_get_active_streams()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 
cras_system_state_get_active_streams_by_direction(enum CRAS_STREAM_DIRECTION direction)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 
cras_system_state_get_last_stream_active_time(struct cras_timespec * ts)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 
cras_system_state_get_output_devs(const struct cras_iodev_info ** devs)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 
cras_system_state_get_input_devs(const struct cras_iodev_info ** devs)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 
cras_system_state_get_output_nodes(const struct cras_ionode_info ** nodes)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 
cras_system_state_get_input_nodes(const struct cras_ionode_info ** nodes)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 
cras_system_state_update_begin()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 
cras_system_state_update_complete()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 
cras_system_state_get_no_lock()511 struct cras_server_state *cras_system_state_get_no_lock()
512 {
513 	return state.exp_state;
514 }
515 
cras_sys_state_shm_fd()516 key_t cras_sys_state_shm_fd()
517 {
518 	return state.shm_fd_ro;
519 }
520 
cras_system_state_get_tm()521 struct cras_tm *cras_system_state_get_tm()
522 {
523 	return state.tm;
524 }
525