1 /* Copyright 2016 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 "cras_observer.h" 7 8 #include "cras_alert.h" 9 #include "cras_iodev_list.h" 10 #include "utlist.h" 11 12 struct cras_observer_client { 13 struct cras_observer_ops ops; 14 void *context; 15 struct cras_observer_client *next, *prev; 16 }; 17 18 struct cras_observer_alerts { 19 struct cras_alert *output_volume; 20 struct cras_alert *output_mute; 21 struct cras_alert *capture_gain; 22 struct cras_alert *capture_mute; 23 struct cras_alert *nodes; 24 struct cras_alert *active_node; 25 struct cras_alert *output_node_volume; 26 struct cras_alert *node_left_right_swapped; 27 struct cras_alert *input_node_gain; 28 struct cras_alert *suspend_changed; 29 struct cras_alert *hotword_triggered; 30 /* If all events for active streams went through a single alert then 31 * we might miss some because the alert code does not send every 32 * alert message. To ensure that the event sent contains the correct 33 * number of active streams per direction, make the alerts 34 * per-direciton. */ 35 struct cras_alert *num_active_streams[CRAS_NUM_DIRECTIONS]; 36 struct cras_alert *non_empty_audio_state_changed; 37 }; 38 39 struct cras_observer_server { 40 struct cras_observer_alerts alerts; 41 struct cras_observer_client *clients; 42 }; 43 44 struct cras_observer_alert_data_volume { 45 int32_t volume; 46 }; 47 48 struct cras_observer_alert_data_mute { 49 int muted; 50 int user_muted; 51 int mute_locked; 52 }; 53 54 struct cras_observer_alert_data_active_node { 55 enum CRAS_STREAM_DIRECTION direction; 56 cras_node_id_t node_id; 57 }; 58 59 struct cras_observer_alert_data_node_volume { 60 cras_node_id_t node_id; 61 int32_t volume; 62 }; 63 64 struct cras_observer_alert_data_node_lr_swapped { 65 cras_node_id_t node_id; 66 int swapped; 67 }; 68 69 struct cras_observer_alert_data_suspend { 70 int suspended; 71 }; 72 73 struct cras_observer_alert_data_streams { 74 enum CRAS_STREAM_DIRECTION direction; 75 uint32_t num_active_streams; 76 }; 77 78 struct cras_observer_alert_data_hotword_triggered { 79 int64_t tv_sec; 80 int64_t tv_nsec; 81 }; 82 83 struct cras_observer_non_empty_audio_state { 84 int non_empty; 85 }; 86 87 /* Global observer instance. */ 88 static struct cras_observer_server *g_observer; 89 90 /* Empty observer ops. */ 91 static struct cras_observer_ops g_empty_ops; 92 93 /* 94 * Alert handlers for delayed callbacks. 95 */ 96 97 static void output_volume_alert(void *arg, void *data) 98 { 99 struct cras_observer_client *client; 100 struct cras_observer_alert_data_volume *volume_data = 101 (struct cras_observer_alert_data_volume *)data; 102 103 DL_FOREACH(g_observer->clients, client) { 104 if (client->ops.output_volume_changed) 105 client->ops.output_volume_changed( 106 client->context, 107 volume_data->volume); 108 } 109 } 110 111 static void output_mute_alert(void *arg, void *data) 112 { 113 struct cras_observer_client *client; 114 struct cras_observer_alert_data_mute *mute_data = 115 (struct cras_observer_alert_data_mute *)data; 116 117 DL_FOREACH(g_observer->clients, client) { 118 if (client->ops.output_mute_changed) 119 client->ops.output_mute_changed( 120 client->context, 121 mute_data->muted, 122 mute_data->user_muted, 123 mute_data->mute_locked); 124 } 125 } 126 127 static void capture_gain_alert(void *arg, void *data) 128 { 129 struct cras_observer_client *client; 130 struct cras_observer_alert_data_volume *volume_data = 131 (struct cras_observer_alert_data_volume *)data; 132 133 DL_FOREACH(g_observer->clients, client) { 134 if (client->ops.capture_gain_changed) 135 client->ops.capture_gain_changed( 136 client->context, 137 volume_data->volume); 138 } 139 } 140 141 static void capture_mute_alert(void *arg, void *data) 142 { 143 struct cras_observer_client *client; 144 struct cras_observer_alert_data_mute *mute_data = 145 (struct cras_observer_alert_data_mute *)data; 146 147 DL_FOREACH(g_observer->clients, client) { 148 if (client->ops.capture_mute_changed) 149 client->ops.capture_mute_changed( 150 client->context, 151 mute_data->muted, 152 mute_data->mute_locked); 153 } 154 } 155 156 static void nodes_prepare(struct cras_alert *alert) 157 { 158 cras_iodev_list_update_device_list(); 159 } 160 161 static void nodes_alert(void *arg, void *data) 162 { 163 struct cras_observer_client *client; 164 165 DL_FOREACH(g_observer->clients, client) { 166 if (client->ops.nodes_changed) 167 client->ops.nodes_changed(client->context); 168 } 169 } 170 171 static void active_node_alert(void *arg, void *data) 172 { 173 struct cras_observer_client *client; 174 struct cras_observer_alert_data_active_node *node_data = 175 (struct cras_observer_alert_data_active_node *)data; 176 177 DL_FOREACH(g_observer->clients, client) { 178 if (client->ops.active_node_changed) 179 client->ops.active_node_changed( 180 client->context, 181 node_data->direction, 182 node_data->node_id); 183 } 184 } 185 186 static void output_node_volume_alert(void *arg, void *data) 187 { 188 struct cras_observer_client *client; 189 struct cras_observer_alert_data_node_volume *node_data = 190 (struct cras_observer_alert_data_node_volume *)data; 191 192 DL_FOREACH(g_observer->clients, client) { 193 if (client->ops.output_node_volume_changed) 194 client->ops.output_node_volume_changed( 195 client->context, 196 node_data->node_id, 197 node_data->volume); 198 } 199 } 200 201 static void node_left_right_swapped_alert(void *arg, void *data) 202 { 203 struct cras_observer_client *client; 204 struct cras_observer_alert_data_node_lr_swapped *node_data = 205 (struct cras_observer_alert_data_node_lr_swapped *)data; 206 207 DL_FOREACH(g_observer->clients, client) { 208 if (client->ops.node_left_right_swapped_changed) 209 client->ops.node_left_right_swapped_changed( 210 client->context, 211 node_data->node_id, 212 node_data->swapped); 213 } 214 } 215 216 static void input_node_gain_alert(void *arg, void *data) 217 { 218 struct cras_observer_client *client; 219 struct cras_observer_alert_data_node_volume *node_data = 220 (struct cras_observer_alert_data_node_volume *)data; 221 222 DL_FOREACH(g_observer->clients, client) { 223 if (client->ops.input_node_gain_changed) 224 client->ops.input_node_gain_changed( 225 client->context, 226 node_data->node_id, 227 node_data->volume); 228 } 229 } 230 231 static void suspend_changed_alert(void *arg, void *data) 232 { 233 struct cras_observer_client *client; 234 struct cras_observer_alert_data_suspend *suspend_data = 235 (struct cras_observer_alert_data_suspend *)data; 236 237 DL_FOREACH(g_observer->clients, client) { 238 if (client->ops.suspend_changed) 239 client->ops.suspend_changed( 240 client->context, 241 suspend_data->suspended); 242 } 243 } 244 245 static void num_active_streams_alert(void *arg, void *data) 246 { 247 struct cras_observer_client *client; 248 struct cras_observer_alert_data_streams *streams_data = 249 (struct cras_observer_alert_data_streams *)data; 250 251 DL_FOREACH(g_observer->clients, client) { 252 if (client->ops.num_active_streams_changed) 253 client->ops.num_active_streams_changed( 254 client->context, 255 streams_data->direction, 256 streams_data->num_active_streams); 257 } 258 } 259 260 static void hotword_triggered_alert(void *arg, void *data) 261 { 262 struct cras_observer_client *client; 263 struct cras_observer_alert_data_hotword_triggered *triggered_data = 264 (struct cras_observer_alert_data_hotword_triggered *)data; 265 266 DL_FOREACH(g_observer->clients, client) { 267 if (client->ops.hotword_triggered) 268 client->ops.hotword_triggered( 269 client->context, 270 triggered_data->tv_sec, 271 triggered_data->tv_nsec); 272 } 273 } 274 275 static void non_empty_audio_state_changed_alert(void *arg, void *data) 276 { 277 struct cras_observer_client *client; 278 struct cras_observer_non_empty_audio_state *non_empty_audio_data = 279 (struct cras_observer_non_empty_audio_state *)data; 280 281 DL_FOREACH(g_observer->clients, client) { 282 if (client->ops.non_empty_audio_state_changed) { 283 client->ops.non_empty_audio_state_changed( 284 client->context, 285 non_empty_audio_data->non_empty); 286 } 287 } 288 } 289 290 static int cras_observer_server_set_alert(struct cras_alert **alert, 291 cras_alert_cb cb, 292 cras_alert_prepare prepare, 293 unsigned int flags) 294 { 295 *alert = cras_alert_create(prepare, flags); 296 if (!*alert) 297 return -ENOMEM; 298 return cras_alert_add_callback(*alert, cb, NULL); 299 } 300 301 #define CRAS_OBSERVER_SET_ALERT(alert,prepare,flags) \ 302 do { \ 303 rc = cras_observer_server_set_alert( \ 304 &g_observer->alerts.alert, alert##_alert, \ 305 prepare, flags); \ 306 if (rc) \ 307 goto error; \ 308 } while(0) 309 310 #define CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(alert,direction) \ 311 do { \ 312 rc = cras_observer_server_set_alert( \ 313 &g_observer->alerts.alert[direction], \ 314 alert##_alert, NULL, 0); \ 315 if (rc) \ 316 goto error; \ 317 } while(0) 318 319 /* 320 * Public interface 321 */ 322 323 int cras_observer_server_init() 324 { 325 int rc; 326 327 memset(&g_empty_ops, 0, sizeof(g_empty_ops)); 328 g_observer = (struct cras_observer_server *) 329 calloc(1, sizeof(struct cras_observer_server)); 330 if (!g_observer) 331 return -ENOMEM; 332 333 CRAS_OBSERVER_SET_ALERT(output_volume, NULL, 0); 334 CRAS_OBSERVER_SET_ALERT(output_mute, NULL, 0); 335 CRAS_OBSERVER_SET_ALERT(capture_gain, NULL, 0); 336 CRAS_OBSERVER_SET_ALERT(capture_mute, NULL, 0); 337 CRAS_OBSERVER_SET_ALERT(nodes, nodes_prepare, 0); 338 CRAS_OBSERVER_SET_ALERT(active_node, nodes_prepare, 339 CRAS_ALERT_FLAG_KEEP_ALL_DATA); 340 CRAS_OBSERVER_SET_ALERT(output_node_volume, NULL, 0); 341 CRAS_OBSERVER_SET_ALERT(node_left_right_swapped, NULL, 0); 342 CRAS_OBSERVER_SET_ALERT(input_node_gain, NULL, 0); 343 CRAS_OBSERVER_SET_ALERT(suspend_changed, NULL, 0); 344 CRAS_OBSERVER_SET_ALERT(hotword_triggered, NULL, 0); 345 CRAS_OBSERVER_SET_ALERT(non_empty_audio_state_changed, NULL, 0); 346 347 CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION( 348 num_active_streams, CRAS_STREAM_OUTPUT); 349 CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION( 350 num_active_streams, CRAS_STREAM_INPUT); 351 CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION( 352 num_active_streams, CRAS_STREAM_POST_MIX_PRE_DSP); 353 354 return 0; 355 356 error: 357 cras_observer_server_free(); 358 return rc; 359 } 360 361 void cras_observer_server_free() 362 { 363 if (!g_observer) 364 return; 365 cras_alert_destroy(g_observer->alerts.output_volume); 366 cras_alert_destroy(g_observer->alerts.output_mute); 367 cras_alert_destroy(g_observer->alerts.capture_gain); 368 cras_alert_destroy(g_observer->alerts.capture_mute); 369 cras_alert_destroy(g_observer->alerts.nodes); 370 cras_alert_destroy(g_observer->alerts.active_node); 371 cras_alert_destroy(g_observer->alerts.output_node_volume); 372 cras_alert_destroy(g_observer->alerts.node_left_right_swapped); 373 cras_alert_destroy(g_observer->alerts.input_node_gain); 374 cras_alert_destroy(g_observer->alerts.suspend_changed); 375 cras_alert_destroy(g_observer->alerts.hotword_triggered); 376 cras_alert_destroy(g_observer->alerts.non_empty_audio_state_changed); 377 cras_alert_destroy(g_observer->alerts.num_active_streams[ 378 CRAS_STREAM_OUTPUT]); 379 cras_alert_destroy(g_observer->alerts.num_active_streams[ 380 CRAS_STREAM_INPUT]); 381 cras_alert_destroy(g_observer->alerts.num_active_streams[ 382 CRAS_STREAM_POST_MIX_PRE_DSP]); 383 free(g_observer); 384 g_observer = NULL; 385 } 386 387 int cras_observer_ops_are_empty(const struct cras_observer_ops *ops) 388 { 389 return memcmp(ops, &g_empty_ops, sizeof(*ops)) == 0; 390 } 391 392 void cras_observer_get_ops(const struct cras_observer_client *client, 393 struct cras_observer_ops *ops) 394 { 395 if (!ops) 396 return; 397 if (!client) 398 memset(ops, 0, sizeof(*ops)); 399 else 400 memcpy(ops, &client->ops, sizeof(*ops)); 401 } 402 403 void cras_observer_set_ops(struct cras_observer_client *client, 404 const struct cras_observer_ops *ops) 405 { 406 if (!client) 407 return; 408 if (!ops) 409 memset(&client->ops, 0, sizeof(client->ops)); 410 else 411 memcpy(&client->ops, ops, sizeof(client->ops)); 412 } 413 414 struct cras_observer_client *cras_observer_add( 415 const struct cras_observer_ops *ops, 416 void *context) 417 { 418 struct cras_observer_client *client; 419 420 client = (struct cras_observer_client *)calloc(1, sizeof(*client)); 421 if (!client) 422 return NULL; 423 client->context = context; 424 DL_APPEND(g_observer->clients, client); 425 cras_observer_set_ops(client, ops); 426 return client; 427 } 428 429 void cras_observer_remove(struct cras_observer_client *client) 430 { 431 if (!client) 432 return; 433 DL_DELETE(g_observer->clients, client); 434 free(client); 435 } 436 437 /* 438 * Public interface for notifiers. 439 */ 440 441 void cras_observer_notify_output_volume(int32_t volume) 442 { 443 struct cras_observer_alert_data_volume data; 444 445 data.volume = volume; 446 cras_alert_pending_data(g_observer->alerts.output_volume, 447 &data, sizeof(data)); 448 } 449 450 void cras_observer_notify_output_mute(int muted, int user_muted, 451 int mute_locked) 452 { 453 struct cras_observer_alert_data_mute data; 454 455 data.muted = muted; 456 data.user_muted = user_muted; 457 data.mute_locked = mute_locked; 458 cras_alert_pending_data(g_observer->alerts.output_mute, 459 &data, sizeof(data)); 460 } 461 462 void cras_observer_notify_capture_gain(int32_t gain) 463 { 464 struct cras_observer_alert_data_volume data; 465 466 data.volume = gain; 467 cras_alert_pending_data(g_observer->alerts.capture_gain, 468 &data, sizeof(data)); 469 } 470 471 void cras_observer_notify_capture_mute(int muted, int mute_locked) 472 { 473 struct cras_observer_alert_data_mute data; 474 475 data.muted = muted; 476 data.user_muted = 0; 477 data.mute_locked = mute_locked; 478 cras_alert_pending_data(g_observer->alerts.capture_mute, 479 &data, sizeof(data)); 480 } 481 482 void cras_observer_notify_nodes(void) 483 { 484 cras_alert_pending(g_observer->alerts.nodes); 485 } 486 487 void cras_observer_notify_active_node(enum CRAS_STREAM_DIRECTION dir, 488 cras_node_id_t node_id) 489 { 490 struct cras_observer_alert_data_active_node data; 491 492 data.direction = dir; 493 data.node_id = node_id; 494 cras_alert_pending_data(g_observer->alerts.active_node, 495 &data, sizeof(data)); 496 } 497 498 void cras_observer_notify_output_node_volume(cras_node_id_t node_id, 499 int32_t volume) 500 { 501 struct cras_observer_alert_data_node_volume data; 502 503 data.node_id = node_id; 504 data.volume = volume; 505 cras_alert_pending_data(g_observer->alerts.output_node_volume, 506 &data, sizeof(data)); 507 } 508 509 void cras_observer_notify_node_left_right_swapped(cras_node_id_t node_id, 510 int swapped) 511 { 512 struct cras_observer_alert_data_node_lr_swapped data; 513 514 data.node_id = node_id; 515 data.swapped = swapped; 516 cras_alert_pending_data(g_observer->alerts.node_left_right_swapped, 517 &data, sizeof(data)); 518 } 519 520 void cras_observer_notify_input_node_gain(cras_node_id_t node_id, 521 int32_t gain) 522 { 523 struct cras_observer_alert_data_node_volume data; 524 525 data.node_id = node_id; 526 data.volume = gain; 527 cras_alert_pending_data(g_observer->alerts.input_node_gain, 528 &data, sizeof(data)); 529 } 530 531 void cras_observer_notify_suspend_changed(int suspended) 532 { 533 struct cras_observer_alert_data_suspend data; 534 535 data.suspended = suspended; 536 cras_alert_pending_data(g_observer->alerts.suspend_changed, 537 &data, sizeof(data)); 538 } 539 540 void cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir, 541 uint32_t num_active_streams) 542 { 543 struct cras_observer_alert_data_streams data; 544 struct cras_alert *alert; 545 546 data.direction = dir; 547 data.num_active_streams = num_active_streams; 548 alert = g_observer->alerts.num_active_streams[dir]; 549 if (!alert) 550 return; 551 552 cras_alert_pending_data(alert, &data, sizeof(data)); 553 } 554 555 void cras_observer_notify_hotword_triggered(int64_t tv_sec, int64_t tv_nsec) 556 { 557 struct cras_observer_alert_data_hotword_triggered data; 558 559 data.tv_sec = tv_sec; 560 data.tv_nsec = tv_nsec; 561 cras_alert_pending_data(g_observer->alerts.hotword_triggered, 562 &data, sizeof(data)); 563 } 564 565 void cras_observer_notify_non_empty_audio_state_changed(int non_empty) 566 { 567 struct cras_observer_non_empty_audio_state data; 568 569 data.non_empty = non_empty; 570 571 cras_alert_pending_data(g_observer->alerts.non_empty_audio_state_changed, 572 &data, sizeof(data)); 573 }