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 <assert.h> 7 #include <stdlib.h> 8 #include <syslog.h> 9 10 #include "audio_thread.h" 11 #include "cras_config.h" 12 #include "cras_dsp.h" 13 #include "cras_iodev.h" 14 #include "cras_iodev_list.h" 15 #include "cras_messages.h" 16 #include "cras_observer.h" 17 #include "cras_rclient.h" 18 #include "cras_rstream.h" 19 #include "cras_system_state.h" 20 #include "cras_types.h" 21 #include "cras_util.h" 22 #include "stream_list.h" 23 #include "utlist.h" 24 25 /* An attached client. 26 * id - The id of the client. 27 * fd - Connection for client communication. 28 */ 29 struct cras_rclient { 30 struct cras_observer_client *observer; 31 size_t id; 32 int fd; 33 }; 34 35 /* Handles a message from the client to connect a new stream */ 36 static int handle_client_stream_connect(struct cras_rclient *client, 37 const struct cras_connect_message *msg, 38 int aud_fd) 39 { 40 struct cras_rstream *stream; 41 struct cras_client_stream_connected reply; 42 struct cras_audio_format remote_fmt; 43 struct cras_rstream_config stream_config; 44 int rc; 45 int stream_fds[2]; 46 47 unpack_cras_audio_format(&remote_fmt, &msg->format); 48 49 /* check the aud_fd is valid. */ 50 if (aud_fd < 0) { 51 syslog(LOG_ERR, "Invalid fd in stream connect.\n"); 52 rc = -EINVAL; 53 goto reply_err; 54 } 55 /* When full, getting an error is preferable to blocking. */ 56 cras_make_fd_nonblocking(aud_fd); 57 58 /* Create the stream with the specified parameters. */ 59 stream_config.stream_id = msg->stream_id; 60 stream_config.stream_type = msg->stream_type; 61 stream_config.direction = msg->direction; 62 stream_config.dev_idx = msg->dev_idx; 63 stream_config.flags = msg->flags; 64 stream_config.format = &remote_fmt; 65 stream_config.buffer_frames = msg->buffer_frames; 66 stream_config.cb_threshold = msg->cb_threshold; 67 stream_config.audio_fd = aud_fd; 68 stream_config.client = client; 69 rc = stream_list_add(cras_iodev_list_get_stream_list(), 70 &stream_config, &stream); 71 if (rc) { 72 rc = -ENOMEM; 73 goto reply_err; 74 } 75 76 /* Tell client about the stream setup. */ 77 syslog(LOG_DEBUG, "Send connected for stream %x\n", msg->stream_id); 78 cras_fill_client_stream_connected( 79 &reply, 80 0, /* No error. */ 81 msg->stream_id, 82 &remote_fmt, 83 cras_rstream_get_total_shm_size(stream)); 84 stream_fds[0] = cras_rstream_input_shm_fd(stream); 85 stream_fds[1] = cras_rstream_output_shm_fd(stream); 86 rc = cras_rclient_send_message(client, &reply.header, stream_fds, 2); 87 if (rc < 0) { 88 syslog(LOG_ERR, "Failed to send connected messaged\n"); 89 stream_list_rm(cras_iodev_list_get_stream_list(), 90 stream->stream_id); 91 goto reply_err; 92 } 93 94 return 0; 95 96 reply_err: 97 /* Send the error code to the client. */ 98 cras_fill_client_stream_connected(&reply, rc, msg->stream_id, 99 &remote_fmt, 0); 100 cras_rclient_send_message(client, &reply.header, NULL, 0); 101 102 if (aud_fd >= 0) 103 close(aud_fd); 104 105 return rc; 106 } 107 108 /* Handles messages from the client requesting that a stream be removed from the 109 * server. */ 110 static int handle_client_stream_disconnect( 111 struct cras_rclient *client, 112 const struct cras_disconnect_stream_message *msg) 113 { 114 return stream_list_rm(cras_iodev_list_get_stream_list(), 115 msg->stream_id); 116 } 117 118 /* Handles dumping audio thread debug info back to the client. */ 119 static void dump_audio_thread_info(struct cras_rclient *client) 120 { 121 struct cras_client_audio_debug_info_ready msg; 122 struct cras_server_state *state; 123 124 cras_fill_client_audio_debug_info_ready(&msg); 125 state = cras_system_state_get_no_lock(); 126 audio_thread_dump_thread_info(cras_iodev_list_get_audio_thread(), 127 &state->audio_debug_info); 128 cras_rclient_send_message(client, &msg.header, NULL, 0); 129 } 130 131 static void handle_get_hotword_models(struct cras_rclient *client, 132 cras_node_id_t node_id) 133 { 134 struct cras_client_get_hotword_models_ready *msg; 135 char *hotword_models; 136 unsigned hotword_models_size; 137 uint8_t buf[CRAS_CLIENT_MAX_MSG_SIZE]; 138 139 msg = (struct cras_client_get_hotword_models_ready *)buf; 140 hotword_models = cras_iodev_list_get_hotword_models(node_id); 141 if (!hotword_models) 142 goto empty_reply; 143 hotword_models_size = strlen(hotword_models); 144 if (hotword_models_size + sizeof(*msg) > CRAS_CLIENT_MAX_MSG_SIZE) { 145 free(hotword_models); 146 goto empty_reply; 147 } 148 149 cras_fill_client_get_hotword_models_ready(msg, hotword_models, 150 hotword_models_size); 151 cras_rclient_send_message(client, &msg->header, NULL, 0); 152 free(hotword_models); 153 return; 154 155 empty_reply: 156 cras_fill_client_get_hotword_models_ready(msg, NULL, 0); 157 cras_rclient_send_message(client, &msg->header, NULL, 0); 158 } 159 160 /* Client notification callback functions. */ 161 162 static void send_output_volume_changed(void *context, int32_t volume) 163 { 164 struct cras_client_volume_changed msg; 165 struct cras_rclient *client = (struct cras_rclient *)context; 166 167 cras_fill_client_output_volume_changed(&msg, volume); 168 cras_rclient_send_message(client, &msg.header, NULL, 0); 169 } 170 171 static void send_output_mute_changed(void *context, int muted, 172 int user_muted, int mute_locked) 173 { 174 struct cras_client_mute_changed msg; 175 struct cras_rclient *client = (struct cras_rclient *)context; 176 177 cras_fill_client_output_mute_changed(&msg, muted, 178 user_muted, mute_locked); 179 cras_rclient_send_message(client, &msg.header, NULL, 0); 180 } 181 182 static void send_capture_gain_changed(void *context, int32_t gain) 183 { 184 struct cras_client_volume_changed msg; 185 struct cras_rclient *client = (struct cras_rclient *)context; 186 187 cras_fill_client_capture_gain_changed(&msg, gain); 188 cras_rclient_send_message(client, &msg.header, NULL, 0); 189 } 190 191 static void send_capture_mute_changed(void *context, int muted, int mute_locked) 192 { 193 struct cras_client_mute_changed msg; 194 struct cras_rclient *client = (struct cras_rclient *)context; 195 196 cras_fill_client_capture_mute_changed(&msg, muted, mute_locked); 197 cras_rclient_send_message(client, &msg.header, NULL, 0); 198 } 199 200 static void send_nodes_changed(void *context) 201 { 202 struct cras_client_nodes_changed msg; 203 struct cras_rclient *client = (struct cras_rclient *)context; 204 205 cras_fill_client_nodes_changed(&msg); 206 cras_rclient_send_message(client, &msg.header, NULL, 0); 207 } 208 209 static void send_active_node_changed(void *context, 210 enum CRAS_STREAM_DIRECTION dir, 211 cras_node_id_t node_id) 212 { 213 struct cras_client_active_node_changed msg; 214 struct cras_rclient *client = (struct cras_rclient *)context; 215 216 cras_fill_client_active_node_changed(&msg, dir, node_id); 217 cras_rclient_send_message(client, &msg.header, NULL, 0); 218 } 219 220 static void send_output_node_volume_changed(void *context, 221 cras_node_id_t node_id, 222 int32_t volume) 223 { 224 struct cras_client_node_value_changed msg; 225 struct cras_rclient *client = (struct cras_rclient *)context; 226 227 cras_fill_client_output_node_volume_changed(&msg, node_id, volume); 228 cras_rclient_send_message(client, &msg.header, NULL, 0); 229 } 230 231 static void send_node_left_right_swapped_changed(void *context, 232 cras_node_id_t node_id, 233 int swapped) 234 { 235 struct cras_client_node_value_changed msg; 236 struct cras_rclient *client = (struct cras_rclient *)context; 237 238 cras_fill_client_node_left_right_swapped_changed( 239 &msg, node_id, swapped); 240 cras_rclient_send_message(client, &msg.header, NULL, 0); 241 } 242 243 static void send_input_node_gain_changed(void *context, 244 cras_node_id_t node_id, 245 int32_t gain) 246 { 247 struct cras_client_node_value_changed msg; 248 struct cras_rclient *client = (struct cras_rclient *)context; 249 250 cras_fill_client_input_node_gain_changed(&msg, node_id, gain); 251 cras_rclient_send_message(client, &msg.header, NULL, 0); 252 } 253 254 static void send_num_active_streams_changed(void *context, 255 enum CRAS_STREAM_DIRECTION dir, 256 uint32_t num_active_streams) 257 { 258 struct cras_client_num_active_streams_changed msg; 259 struct cras_rclient *client = (struct cras_rclient *)context; 260 261 cras_fill_client_num_active_streams_changed( 262 &msg, dir, num_active_streams); 263 cras_rclient_send_message(client, &msg.header, NULL, 0); 264 } 265 266 static void register_for_notification(struct cras_rclient *client, 267 enum CRAS_CLIENT_MESSAGE_ID msg_id, 268 int do_register) 269 { 270 struct cras_observer_ops observer_ops; 271 int empty; 272 273 cras_observer_get_ops(client->observer, &observer_ops); 274 275 switch (msg_id) { 276 case CRAS_CLIENT_OUTPUT_VOLUME_CHANGED: 277 observer_ops.output_volume_changed = 278 do_register ? send_output_volume_changed : NULL; 279 break; 280 case CRAS_CLIENT_OUTPUT_MUTE_CHANGED: 281 observer_ops.output_mute_changed = 282 do_register ? send_output_mute_changed : NULL; 283 break; 284 case CRAS_CLIENT_CAPTURE_GAIN_CHANGED: 285 observer_ops.capture_gain_changed = 286 do_register ? send_capture_gain_changed : NULL; 287 break; 288 case CRAS_CLIENT_CAPTURE_MUTE_CHANGED: 289 observer_ops.capture_mute_changed = 290 do_register ? send_capture_mute_changed : NULL; 291 break; 292 case CRAS_CLIENT_NODES_CHANGED: 293 observer_ops.nodes_changed = 294 do_register ? send_nodes_changed : NULL; 295 break; 296 case CRAS_CLIENT_ACTIVE_NODE_CHANGED: 297 observer_ops.active_node_changed = 298 do_register ? send_active_node_changed : NULL; 299 break; 300 case CRAS_CLIENT_OUTPUT_NODE_VOLUME_CHANGED: 301 observer_ops.output_node_volume_changed = 302 do_register ? send_output_node_volume_changed : NULL; 303 break; 304 case CRAS_CLIENT_NODE_LEFT_RIGHT_SWAPPED_CHANGED: 305 observer_ops.node_left_right_swapped_changed = 306 do_register ? send_node_left_right_swapped_changed : NULL; 307 break; 308 case CRAS_CLIENT_INPUT_NODE_GAIN_CHANGED: 309 observer_ops.input_node_gain_changed = 310 do_register ? send_input_node_gain_changed : NULL; 311 break; 312 case CRAS_CLIENT_NUM_ACTIVE_STREAMS_CHANGED: 313 observer_ops.num_active_streams_changed = 314 do_register ? send_num_active_streams_changed : NULL; 315 break; 316 default: 317 syslog(LOG_ERR, 318 "Invalid client notification message ID: %u", msg_id); 319 break; 320 } 321 322 empty = cras_observer_ops_are_empty(&observer_ops); 323 if (client->observer) { 324 if (empty) { 325 cras_observer_remove(client->observer); 326 client->observer = NULL; 327 } else { 328 cras_observer_set_ops(client->observer, &observer_ops); 329 } 330 } else if (!empty) { 331 client->observer = cras_observer_add(&observer_ops, client); 332 } 333 } 334 335 /* 336 * Exported Functions. 337 */ 338 339 /* Creates a client structure and sends a message back informing the client that 340 * the conneciton has succeeded. */ 341 struct cras_rclient *cras_rclient_create(int fd, size_t id) 342 { 343 struct cras_rclient *client; 344 struct cras_client_connected msg; 345 int state_fd; 346 347 client = (struct cras_rclient *)calloc(1, sizeof(struct cras_rclient)); 348 if (!client) 349 return NULL; 350 351 client->fd = fd; 352 client->id = id; 353 354 cras_fill_client_connected(&msg, client->id); 355 state_fd = cras_sys_state_shm_fd(); 356 cras_rclient_send_message(client, &msg.header, &state_fd, 1); 357 358 return client; 359 } 360 361 /* Removes all streams that the client owns and destroys it. */ 362 void cras_rclient_destroy(struct cras_rclient *client) 363 { 364 cras_observer_remove(client->observer); 365 stream_list_rm_all_client_streams( 366 cras_iodev_list_get_stream_list(), client); 367 free(client); 368 } 369 370 /* Entry point for handling a message from the client. Called from the main 371 * server context. */ 372 int cras_rclient_message_from_client(struct cras_rclient *client, 373 const struct cras_server_message *msg, 374 int fd) { 375 assert(client && msg); 376 377 /* Most messages should not have a file descriptor. */ 378 switch (msg->id) { 379 case CRAS_SERVER_CONNECT_STREAM: 380 break; 381 default: 382 if (fd != -1) { 383 syslog(LOG_ERR, 384 "Message %d should not have fd attached.", 385 msg->id); 386 close(fd); 387 return -1; 388 } 389 break; 390 } 391 392 switch (msg->id) { 393 case CRAS_SERVER_CONNECT_STREAM: 394 handle_client_stream_connect(client, 395 (const struct cras_connect_message *)msg, fd); 396 break; 397 case CRAS_SERVER_DISCONNECT_STREAM: 398 handle_client_stream_disconnect(client, 399 (const struct cras_disconnect_stream_message *)msg); 400 break; 401 case CRAS_SERVER_SET_SYSTEM_VOLUME: 402 cras_system_set_volume( 403 ((const struct cras_set_system_volume *)msg)->volume); 404 break; 405 case CRAS_SERVER_SET_SYSTEM_MUTE: 406 cras_system_set_mute( 407 ((const struct cras_set_system_mute *)msg)->mute); 408 break; 409 case CRAS_SERVER_SET_USER_MUTE: 410 cras_system_set_user_mute( 411 ((const struct cras_set_system_mute *)msg)->mute); 412 break; 413 case CRAS_SERVER_SET_SYSTEM_MUTE_LOCKED: 414 cras_system_set_mute_locked( 415 ((const struct cras_set_system_mute *)msg)->mute); 416 break; 417 case CRAS_SERVER_SET_SYSTEM_CAPTURE_GAIN: { 418 const struct cras_set_system_capture_gain *m = 419 (const struct cras_set_system_capture_gain *)msg; 420 cras_system_set_capture_gain(m->gain); 421 break; 422 } 423 case CRAS_SERVER_SET_SYSTEM_CAPTURE_MUTE: 424 cras_system_set_capture_mute( 425 ((const struct cras_set_system_mute *)msg)->mute); 426 break; 427 case CRAS_SERVER_SET_SYSTEM_CAPTURE_MUTE_LOCKED: 428 cras_system_set_capture_mute_locked( 429 ((const struct cras_set_system_mute *)msg)->mute); 430 break; 431 case CRAS_SERVER_SET_NODE_ATTR: { 432 const struct cras_set_node_attr *m = 433 (const struct cras_set_node_attr *)msg; 434 cras_iodev_list_set_node_attr(m->node_id, m->attr, m->value); 435 break; 436 } 437 case CRAS_SERVER_SELECT_NODE: { 438 const struct cras_select_node *m = 439 (const struct cras_select_node *)msg; 440 cras_iodev_list_select_node(m->direction, m->node_id); 441 break; 442 } 443 case CRAS_SERVER_ADD_ACTIVE_NODE: { 444 const struct cras_add_active_node *m = 445 (const struct cras_add_active_node *)msg; 446 cras_iodev_list_add_active_node(m->direction, m->node_id); 447 break; 448 } 449 case CRAS_SERVER_RM_ACTIVE_NODE: { 450 const struct cras_rm_active_node *m = 451 (const struct cras_rm_active_node *)msg; 452 cras_iodev_list_rm_active_node(m->direction, m->node_id); 453 break; 454 } 455 case CRAS_SERVER_RELOAD_DSP: 456 cras_dsp_reload_ini(); 457 break; 458 case CRAS_SERVER_DUMP_DSP_INFO: 459 cras_dsp_dump_info(); 460 break; 461 case CRAS_SERVER_DUMP_AUDIO_THREAD: 462 dump_audio_thread_info(client); 463 break; 464 case CRAS_SERVER_ADD_TEST_DEV: { 465 const struct cras_add_test_dev *m = 466 (const struct cras_add_test_dev *)msg; 467 cras_iodev_list_add_test_dev(m->type); 468 break; 469 } 470 case CRAS_SERVER_TEST_DEV_COMMAND: { 471 const struct cras_test_dev_command *m = 472 (const struct cras_test_dev_command *)msg; 473 cras_iodev_list_test_dev_command( 474 m->iodev_idx, (enum CRAS_TEST_IODEV_CMD)m->command, 475 m->data_len, m->data); 476 break; 477 } 478 case CRAS_SERVER_SUSPEND: 479 cras_system_set_suspended(1); 480 break; 481 case CRAS_SERVER_RESUME: 482 cras_system_set_suspended(0); 483 break; 484 case CRAS_CONFIG_GLOBAL_REMIX: { 485 const struct cras_config_global_remix *m = 486 (const struct cras_config_global_remix *)msg; 487 audio_thread_config_global_remix( 488 cras_iodev_list_get_audio_thread(), 489 m->num_channels, 490 m->coefficient); 491 break; 492 } 493 case CRAS_SERVER_GET_HOTWORD_MODELS: { 494 handle_get_hotword_models(client, 495 ((const struct cras_get_hotword_models *)msg)->node_id); 496 break; 497 } 498 case CRAS_SERVER_SET_HOTWORD_MODEL: { 499 const struct cras_set_hotword_model *m = 500 (const struct cras_set_hotword_model *)msg; 501 cras_iodev_list_set_hotword_model(m->node_id, 502 m->model_name); 503 break; 504 } 505 case CRAS_SERVER_REGISTER_NOTIFICATION: { 506 const struct cras_register_notification *m = 507 (struct cras_register_notification *)msg; 508 register_for_notification( 509 client, (enum CRAS_CLIENT_MESSAGE_ID)m->msg_id, 510 m->do_register); 511 break; 512 } 513 default: 514 break; 515 } 516 517 return 0; 518 } 519 520 /* Sends a message to the client. */ 521 int cras_rclient_send_message(const struct cras_rclient *client, 522 const struct cras_client_message *msg, 523 int *fds, 524 unsigned int num_fds) 525 { 526 return cras_send_with_fds(client->fd, (const void *)msg, msg->length, 527 fds, num_fds); 528 } 529 530