Home | History | Annotate | Download | only in server
      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