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 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 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 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 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 167 size_t cras_system_get_volume() 168 { 169 return state.exp_state->volume; 170 } 171 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 182 long cras_system_get_capture_gain() 183 { 184 return state.exp_state->capture_gain; 185 } 186 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 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 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 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 224 int cras_system_get_mute() 225 { 226 return state.exp_state->mute || state.exp_state->user_mute; 227 } 228 229 int cras_system_get_user_mute() 230 { 231 return state.exp_state->user_mute; 232 } 233 234 int cras_system_get_system_mute() 235 { 236 return state.exp_state->mute; 237 } 238 239 int cras_system_get_mute_locked() 240 { 241 return state.exp_state->mute_locked; 242 } 243 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 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 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 265 int cras_system_get_capture_mute() 266 { 267 return state.exp_state->capture_mute; 268 } 269 270 int cras_system_get_capture_mute_locked() 271 { 272 return state.exp_state->capture_mute_locked; 273 } 274 275 int cras_system_get_suspended() 276 { 277 return state.exp_state->suspended; 278 } 279 280 void cras_system_set_suspended(int suspended) 281 { 282 state.exp_state->suspended = suspended; 283 cras_observer_notify_suspend_changed(suspended); 284 } 285 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 292 long cras_system_get_min_volume() 293 { 294 return state.exp_state->min_volume_dBFS; 295 } 296 297 long cras_system_get_max_volume() 298 { 299 return state.exp_state->max_volume_dBFS; 300 } 301 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 310 long cras_system_get_min_capture_gain() 311 { 312 return state.exp_state->min_capture_gain; 313 } 314 315 long cras_system_get_max_capture_gain() 316 { 317 return state.exp_state->max_capture_gain; 318 } 319 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 511 struct cras_server_state *cras_system_state_get_no_lock() 512 { 513 return state.exp_state; 514 } 515 516 key_t cras_sys_state_shm_fd() 517 { 518 return state.shm_fd_ro; 519 } 520 521 struct cras_tm *cras_system_state_get_tm() 522 { 523 return state.tm; 524 } 525