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