• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_apm_list.h"
12 #include "cras_config.h"
13 #include "cras_dsp.h"
14 #include "cras_iodev.h"
15 #include "cras_iodev_list.h"
16 #include "cras_messages.h"
17 #include "cras_observer.h"
18 #include "cras_rclient.h"
19 #include "cras_rstream.h"
20 #include "cras_server_metrics.h"
21 #include "cras_system_state.h"
22 #include "cras_types.h"
23 #include "cras_util.h"
24 #include "stream_list.h"
25 #include "utlist.h"
26 
27 /* An attached client.
28  *  id - The id of the client.
29  *  fd - Connection for client communication.
30  */
31 struct cras_rclient {
32 	struct cras_observer_client *observer;
33 	size_t id;
34 	int fd;
35 };
36 
37 /* Handles a message from the client to connect a new stream */
handle_client_stream_connect(struct cras_rclient * client,const struct cras_connect_message * msg,int aud_fd)38 static int handle_client_stream_connect(struct cras_rclient *client,
39 					const struct cras_connect_message *msg,
40 					int aud_fd)
41 {
42 	struct cras_rstream *stream;
43 	struct cras_client_stream_connected stream_connected;
44 	struct cras_client_stream_connected_old stream_connected_old;
45 	struct cras_client_message *reply;
46 	struct cras_audio_format remote_fmt;
47 	struct cras_rstream_config stream_config;
48 	int rc;
49 	int stream_fds[2];
50 
51 	unpack_cras_audio_format(&remote_fmt, &msg->format);
52 
53 	/* check the aud_fd is valid. */
54 	if (aud_fd < 0) {
55 		syslog(LOG_ERR, "Invalid fd in stream connect.\n");
56 		rc = -EINVAL;
57 		goto reply_err;
58 	}
59 	/* When full, getting an error is preferable to blocking. */
60 	cras_make_fd_nonblocking(aud_fd);
61 
62 	/* Create the stream with the specified parameters. */
63 	stream_config.stream_id = msg->stream_id;
64 	stream_config.stream_type = msg->stream_type;
65 	stream_config.direction = msg->direction;
66 	stream_config.dev_idx = msg->dev_idx;
67 	stream_config.flags = msg->flags;
68 	stream_config.effects = msg->effects;
69 	stream_config.format = &remote_fmt;
70 	stream_config.buffer_frames = msg->buffer_frames;
71 	stream_config.cb_threshold = msg->cb_threshold;
72 	stream_config.audio_fd = aud_fd;
73 	stream_config.client = client;
74 	rc = stream_list_add(cras_iodev_list_get_stream_list(),
75 			     &stream_config, &stream);
76 	if (rc) {
77 		rc = -ENOMEM;
78 		goto reply_err;
79 	}
80 
81 	/* Tell client about the stream setup. */
82 	syslog(LOG_DEBUG, "Send connected for stream %x\n", msg->stream_id);
83 	if (msg->proto_version == CRAS_PROTO_VER) {
84 		cras_fill_client_stream_connected(
85 				&stream_connected,
86 				0, /* No error. */
87 				msg->stream_id,
88 				&remote_fmt,
89 				cras_rstream_get_total_shm_size(stream),
90 				cras_rstream_get_effects(stream));
91 		reply = &stream_connected.header;
92 	} else {
93 		cras_fill_client_stream_connected_old(
94 				&stream_connected_old,
95 				0, /* No error. */
96 				msg->stream_id,
97 				&remote_fmt,
98 				cras_rstream_get_total_shm_size(stream));
99 		reply = &stream_connected_old.header;
100 	}
101 	stream_fds[0] = cras_rstream_input_shm_fd(stream);
102 	stream_fds[1] = cras_rstream_output_shm_fd(stream);
103 	rc = cras_rclient_send_message(client, reply, stream_fds, 2);
104 	if (rc < 0) {
105 		syslog(LOG_ERR, "Failed to send connected messaged\n");
106 		stream_list_rm(cras_iodev_list_get_stream_list(),
107 			       stream->stream_id);
108 		goto reply_err;
109 	}
110 
111 	/* Metrics logs the stream configurations. */
112 	cras_server_metrics_stream_config(&stream_config);
113 
114 	return 0;
115 
116 reply_err:
117 	/* Send the error code to the client. */
118 	if (msg->proto_version == CRAS_PROTO_VER) {
119 		cras_fill_client_stream_connected(
120 				&stream_connected, rc, msg->stream_id,
121 				&remote_fmt, 0, msg->effects);
122 		reply = &stream_connected.header;
123 	} else {
124 		cras_fill_client_stream_connected_old(
125 				&stream_connected_old, rc, msg->stream_id,
126 				&remote_fmt, 0);
127 		reply = &stream_connected_old.header;
128 	}
129 	cras_rclient_send_message(client, reply, NULL, 0);
130 
131 	if (aud_fd >= 0)
132 		close(aud_fd);
133 
134 	return rc;
135 }
136 
137 /* Handles messages from the client requesting that a stream be removed from the
138  * server. */
handle_client_stream_disconnect(struct cras_rclient * client,const struct cras_disconnect_stream_message * msg)139 static int handle_client_stream_disconnect(
140 		struct cras_rclient *client,
141 		const struct cras_disconnect_stream_message *msg)
142 {
143 	return stream_list_rm(cras_iodev_list_get_stream_list(),
144 			      msg->stream_id);
145 }
146 
147 /* Handles dumping audio thread debug info back to the client. */
dump_audio_thread_info(struct cras_rclient * client)148 static void dump_audio_thread_info(struct cras_rclient *client)
149 {
150 	struct cras_client_audio_debug_info_ready msg;
151 	struct cras_server_state *state;
152 
153 	cras_fill_client_audio_debug_info_ready(&msg);
154 	state = cras_system_state_get_no_lock();
155 	audio_thread_dump_thread_info(cras_iodev_list_get_audio_thread(),
156 				      &state->audio_debug_info);
157 	cras_rclient_send_message(client, &msg.header, NULL, 0);
158 }
159 
160 /* Handles dumping audio snapshots to shared memory for the client. */
dump_audio_thread_snapshots(struct cras_rclient * client)161 static void dump_audio_thread_snapshots(struct cras_rclient *client)
162 {
163 	struct cras_client_audio_debug_info_ready msg;
164 
165 	cras_fill_client_audio_debug_info_ready(&msg);
166 	cras_system_state_dump_snapshots();
167 	cras_rclient_send_message(client, &msg.header, NULL, 0);
168 }
169 
handle_get_hotword_models(struct cras_rclient * client,cras_node_id_t node_id)170 static void handle_get_hotword_models(struct cras_rclient *client,
171 				      cras_node_id_t node_id)
172 {
173 	struct cras_client_get_hotword_models_ready *msg;
174 	char *hotword_models;
175 	unsigned hotword_models_size;
176 	uint8_t buf[CRAS_CLIENT_MAX_MSG_SIZE];
177 
178 	msg = (struct cras_client_get_hotword_models_ready *)buf;
179 	hotword_models = cras_iodev_list_get_hotword_models(node_id);
180 	if (!hotword_models)
181 		goto empty_reply;
182 	hotword_models_size = strlen(hotword_models);
183 	if (hotword_models_size + sizeof(*msg) > CRAS_CLIENT_MAX_MSG_SIZE) {
184 		free(hotword_models);
185 		goto empty_reply;
186 	}
187 
188 	cras_fill_client_get_hotword_models_ready(msg, hotword_models,
189 						  hotword_models_size);
190 	cras_rclient_send_message(client, &msg->header, NULL, 0);
191 	free(hotword_models);
192 	return;
193 
194 empty_reply:
195 	cras_fill_client_get_hotword_models_ready(msg, NULL, 0);
196 	cras_rclient_send_message(client, &msg->header, NULL, 0);
197 }
198 
199 /* Client notification callback functions. */
200 
send_output_volume_changed(void * context,int32_t volume)201 static void send_output_volume_changed(void *context, int32_t volume)
202 {
203 	struct cras_client_volume_changed msg;
204 	struct cras_rclient *client = (struct cras_rclient *)context;
205 
206 	cras_fill_client_output_volume_changed(&msg, volume);
207 	cras_rclient_send_message(client, &msg.header, NULL, 0);
208 }
209 
send_output_mute_changed(void * context,int muted,int user_muted,int mute_locked)210 static void send_output_mute_changed(void *context, int muted,
211 				     int user_muted, int mute_locked)
212 {
213 	struct cras_client_mute_changed msg;
214 	struct cras_rclient *client = (struct cras_rclient *)context;
215 
216 	cras_fill_client_output_mute_changed(&msg, muted,
217 					     user_muted, mute_locked);
218 	cras_rclient_send_message(client, &msg.header, NULL, 0);
219 }
220 
send_capture_gain_changed(void * context,int32_t gain)221 static void send_capture_gain_changed(void *context, int32_t gain)
222 {
223 	struct cras_client_volume_changed msg;
224 	struct cras_rclient *client = (struct cras_rclient *)context;
225 
226 	cras_fill_client_capture_gain_changed(&msg, gain);
227 	cras_rclient_send_message(client, &msg.header, NULL, 0);
228 }
229 
send_capture_mute_changed(void * context,int muted,int mute_locked)230 static void send_capture_mute_changed(void *context, int muted, int mute_locked)
231 {
232 	struct cras_client_mute_changed msg;
233 	struct cras_rclient *client = (struct cras_rclient *)context;
234 
235 	cras_fill_client_capture_mute_changed(&msg, muted, mute_locked);
236 	cras_rclient_send_message(client, &msg.header, NULL, 0);
237 }
238 
send_nodes_changed(void * context)239 static void send_nodes_changed(void *context)
240 {
241 	struct cras_client_nodes_changed msg;
242 	struct cras_rclient *client = (struct cras_rclient *)context;
243 
244 	cras_fill_client_nodes_changed(&msg);
245 	cras_rclient_send_message(client, &msg.header, NULL, 0);
246 }
247 
send_active_node_changed(void * context,enum CRAS_STREAM_DIRECTION dir,cras_node_id_t node_id)248 static void send_active_node_changed(void *context,
249 				     enum CRAS_STREAM_DIRECTION dir,
250 				     cras_node_id_t node_id)
251 {
252 	struct cras_client_active_node_changed msg;
253 	struct cras_rclient *client = (struct cras_rclient *)context;
254 
255 	cras_fill_client_active_node_changed(&msg, dir, node_id);
256 	cras_rclient_send_message(client, &msg.header, NULL, 0);
257 }
258 
send_output_node_volume_changed(void * context,cras_node_id_t node_id,int32_t volume)259 static void send_output_node_volume_changed(void *context,
260 					    cras_node_id_t node_id,
261 					    int32_t volume)
262 {
263 	struct cras_client_node_value_changed msg;
264 	struct cras_rclient *client = (struct cras_rclient *)context;
265 
266 	cras_fill_client_output_node_volume_changed(&msg, node_id, volume);
267 	cras_rclient_send_message(client, &msg.header, NULL, 0);
268 }
269 
send_node_left_right_swapped_changed(void * context,cras_node_id_t node_id,int swapped)270 static void send_node_left_right_swapped_changed(void *context,
271 						 cras_node_id_t node_id,
272 						 int swapped)
273 {
274 	struct cras_client_node_value_changed msg;
275 	struct cras_rclient *client = (struct cras_rclient *)context;
276 
277 	cras_fill_client_node_left_right_swapped_changed(
278 						&msg, node_id, swapped);
279 	cras_rclient_send_message(client, &msg.header, NULL, 0);
280 }
281 
send_input_node_gain_changed(void * context,cras_node_id_t node_id,int32_t gain)282 static void send_input_node_gain_changed(void *context,
283 					 cras_node_id_t node_id,
284 					 int32_t gain)
285 {
286 	struct cras_client_node_value_changed msg;
287 	struct cras_rclient *client = (struct cras_rclient *)context;
288 
289 	cras_fill_client_input_node_gain_changed(&msg, node_id, gain);
290 	cras_rclient_send_message(client, &msg.header, NULL, 0);
291 }
292 
send_num_active_streams_changed(void * context,enum CRAS_STREAM_DIRECTION dir,uint32_t num_active_streams)293 static void send_num_active_streams_changed(void *context,
294 					    enum CRAS_STREAM_DIRECTION dir,
295 					    uint32_t num_active_streams)
296 {
297 	struct cras_client_num_active_streams_changed msg;
298 	struct cras_rclient *client = (struct cras_rclient *)context;
299 
300 	cras_fill_client_num_active_streams_changed(
301 					&msg, dir, num_active_streams);
302 	cras_rclient_send_message(client, &msg.header, NULL, 0);
303 }
304 
register_for_notification(struct cras_rclient * client,enum CRAS_CLIENT_MESSAGE_ID msg_id,int do_register)305 static void register_for_notification(struct cras_rclient *client,
306 				      enum CRAS_CLIENT_MESSAGE_ID msg_id,
307 				      int do_register)
308 {
309 	struct cras_observer_ops observer_ops;
310 	int empty;
311 
312 	cras_observer_get_ops(client->observer, &observer_ops);
313 
314 	switch (msg_id) {
315 	case CRAS_CLIENT_OUTPUT_VOLUME_CHANGED:
316 		observer_ops.output_volume_changed =
317 			do_register ? send_output_volume_changed : NULL;
318 		break;
319 	case CRAS_CLIENT_OUTPUT_MUTE_CHANGED:
320 		observer_ops.output_mute_changed =
321 			do_register ? send_output_mute_changed : NULL;
322 		break;
323 	case CRAS_CLIENT_CAPTURE_GAIN_CHANGED:
324 		observer_ops.capture_gain_changed =
325 			do_register ? send_capture_gain_changed : NULL;
326 		break;
327 	case CRAS_CLIENT_CAPTURE_MUTE_CHANGED:
328 		observer_ops.capture_mute_changed =
329 			do_register ? send_capture_mute_changed : NULL;
330 		break;
331 	case CRAS_CLIENT_NODES_CHANGED:
332 		observer_ops.nodes_changed =
333 			do_register ? send_nodes_changed : NULL;
334 		break;
335 	case CRAS_CLIENT_ACTIVE_NODE_CHANGED:
336 		observer_ops.active_node_changed =
337 			do_register ? send_active_node_changed : NULL;
338 		break;
339 	case CRAS_CLIENT_OUTPUT_NODE_VOLUME_CHANGED:
340 		observer_ops.output_node_volume_changed =
341 			do_register ? send_output_node_volume_changed : NULL;
342 		break;
343 	case CRAS_CLIENT_NODE_LEFT_RIGHT_SWAPPED_CHANGED:
344 		observer_ops.node_left_right_swapped_changed =
345 		    do_register ? send_node_left_right_swapped_changed : NULL;
346 		break;
347 	case CRAS_CLIENT_INPUT_NODE_GAIN_CHANGED:
348 		observer_ops.input_node_gain_changed =
349 			do_register ? send_input_node_gain_changed : NULL;
350 		break;
351 	case CRAS_CLIENT_NUM_ACTIVE_STREAMS_CHANGED:
352 		observer_ops.num_active_streams_changed =
353 			do_register ? send_num_active_streams_changed : NULL;
354 		break;
355 	default:
356 		syslog(LOG_ERR,
357 		       "Invalid client notification message ID: %u", msg_id);
358 		break;
359 	}
360 
361 	empty = cras_observer_ops_are_empty(&observer_ops);
362 	if (client->observer) {
363 		if (empty) {
364 			cras_observer_remove(client->observer);
365 			client->observer = NULL;
366 		} else {
367 			cras_observer_set_ops(client->observer, &observer_ops);
368 		}
369 	} else if (!empty) {
370 		client->observer = cras_observer_add(&observer_ops, client);
371 	}
372 }
373 
374 /*
375  * Exported Functions.
376  */
377 
378 /* Creates a client structure and sends a message back informing the client that
379  * the conneciton has succeeded. */
cras_rclient_create(int fd,size_t id)380 struct cras_rclient *cras_rclient_create(int fd, size_t id)
381 {
382 	struct cras_rclient *client;
383 	struct cras_client_connected msg;
384 	int state_fd;
385 
386 	client = (struct cras_rclient *)calloc(1, sizeof(struct cras_rclient));
387 	if (!client)
388 		return NULL;
389 
390 	client->fd = fd;
391 	client->id = id;
392 
393 	cras_fill_client_connected(&msg, client->id);
394 	state_fd = cras_sys_state_shm_fd();
395 	cras_rclient_send_message(client, &msg.header, &state_fd, 1);
396 
397 	return client;
398 }
399 
400 /* Removes all streams that the client owns and destroys it. */
cras_rclient_destroy(struct cras_rclient * client)401 void cras_rclient_destroy(struct cras_rclient *client)
402 {
403 	cras_observer_remove(client->observer);
404 	stream_list_rm_all_client_streams(
405 			cras_iodev_list_get_stream_list(), client);
406 	free(client);
407 }
408 
409 /* Entry point for handling a message from the client.  Called from the main
410  * server context. */
cras_rclient_buffer_from_client(struct cras_rclient * client,const uint8_t * buf,size_t buf_len,int fd)411 int cras_rclient_buffer_from_client(struct cras_rclient *client,
412 				    const uint8_t *buf,
413 				    size_t buf_len,
414 				    int fd) {
415 	struct cras_server_message *msg = (struct cras_server_message *)buf;
416 
417 	if (buf_len < sizeof(*msg))
418 		return -EINVAL;
419 	if (msg->length != buf_len)
420 		return -EINVAL;
421 	cras_rclient_message_from_client(client, msg, fd);
422 	return 0;
423 }
424 
direction_valid(enum CRAS_STREAM_DIRECTION direction)425 static int direction_valid(enum CRAS_STREAM_DIRECTION direction)
426 {
427 	return direction < CRAS_NUM_DIRECTIONS &&
428 		direction != CRAS_STREAM_UNDEFINED;
429 }
430 
431 #define MSG_LEN_VALID(msg, type) ((msg)->length >= sizeof(type))
432 
433 /*
434  * Check if client is sending an old version of connect message
435  * and converts it to the correct cras_connect_message.
436  * Note that this is special check only for libcras transition in
437  * clients, from CRAS_PROTO_VER = 1 to 2.
438  * TODO(hychao): clean up the check once clients transition is done.
439  */
is_connect_msg_old(const struct cras_server_message * msg,struct cras_connect_message * cmsg)440 static int is_connect_msg_old(const struct cras_server_message *msg,
441 			      struct cras_connect_message *cmsg)
442 {
443 	struct cras_connect_message_old *old;
444 
445 	if (!MSG_LEN_VALID(msg, struct cras_connect_message_old))
446 		return 0;
447 
448 	old = (struct cras_connect_message_old *)msg;
449 	if (old->proto_version + 1 != CRAS_PROTO_VER)
450 		return 0;
451 
452 	memcpy(cmsg, old, sizeof(*old));
453 	cmsg->effects = 0;
454 	return 1;
455 }
456 
457 /* Entry point for handling a message from the client.  Called from the main
458  * server context. */
cras_rclient_message_from_client(struct cras_rclient * client,const struct cras_server_message * msg,int fd)459 int cras_rclient_message_from_client(struct cras_rclient *client,
460 				     const struct cras_server_message *msg,
461 				     int fd) {
462 	struct cras_connect_message cmsg;
463 
464 	assert(client && msg);
465 
466 	/* Most messages should not have a file descriptor. */
467 	switch (msg->id) {
468 	case CRAS_SERVER_CONNECT_STREAM:
469 		break;
470 	case CRAS_SERVER_SET_AEC_DUMP:
471 		syslog(LOG_ERR, "client msg for APM debug, fd %d", fd);
472 		break;
473 	default:
474 		if (fd != -1) {
475 			syslog(LOG_ERR,
476 			       "Message %d should not have fd attached.",
477 			       msg->id);
478 			close(fd);
479 			return -1;
480 		}
481 		break;
482 	}
483 
484 	switch (msg->id) {
485 	case CRAS_SERVER_CONNECT_STREAM:
486 		if (MSG_LEN_VALID(msg, struct cras_connect_message)) {
487 			handle_client_stream_connect(client,
488 				(const struct cras_connect_message *)msg, fd);
489 		} else if (is_connect_msg_old(msg, &cmsg)) {
490 			handle_client_stream_connect(client, &cmsg, fd);
491 		} else {
492 			return -EINVAL;
493 		}
494 		break;
495 	case CRAS_SERVER_DISCONNECT_STREAM:
496 		if (!MSG_LEN_VALID(msg, struct cras_disconnect_stream_message))
497 			return -EINVAL;
498 		handle_client_stream_disconnect(client,
499 			(const struct cras_disconnect_stream_message *)msg);
500 		break;
501 	case CRAS_SERVER_SET_SYSTEM_VOLUME:
502 		if (!MSG_LEN_VALID(msg, struct cras_set_system_volume))
503 			return -EINVAL;
504 		cras_system_set_volume(
505 			((const struct cras_set_system_volume *)msg)->volume);
506 		break;
507 	case CRAS_SERVER_SET_SYSTEM_MUTE:
508 		if (!MSG_LEN_VALID(msg, struct cras_set_system_mute))
509 			return -EINVAL;
510 		cras_system_set_mute(
511 			((const struct cras_set_system_mute *)msg)->mute);
512 		break;
513 	case CRAS_SERVER_SET_USER_MUTE:
514 		if (!MSG_LEN_VALID(msg, struct cras_set_system_mute))
515 			return -EINVAL;
516 		cras_system_set_user_mute(
517 			((const struct cras_set_system_mute *)msg)->mute);
518 		break;
519 	case CRAS_SERVER_SET_SYSTEM_MUTE_LOCKED:
520 		if (!MSG_LEN_VALID(msg, struct cras_set_system_mute))
521 			return -EINVAL;
522 		cras_system_set_mute_locked(
523 			((const struct cras_set_system_mute *)msg)->mute);
524 		break;
525 	case CRAS_SERVER_SET_SYSTEM_CAPTURE_GAIN: {
526 		const struct cras_set_system_capture_gain *m =
527 			(const struct cras_set_system_capture_gain *)msg;
528 		if (!MSG_LEN_VALID(msg, struct cras_set_system_capture_gain))
529 			return -EINVAL;
530 		cras_system_set_capture_gain(m->gain);
531 		break;
532 	}
533 	case CRAS_SERVER_SET_SYSTEM_CAPTURE_MUTE:
534 		if (!MSG_LEN_VALID(msg, struct cras_set_system_mute))
535 			return -EINVAL;
536 		cras_system_set_capture_mute(
537 			((const struct cras_set_system_mute *)msg)->mute);
538 		break;
539 	case CRAS_SERVER_SET_SYSTEM_CAPTURE_MUTE_LOCKED:
540 		if (!MSG_LEN_VALID(msg, struct cras_set_system_mute))
541 			return -EINVAL;
542 		cras_system_set_capture_mute_locked(
543 			((const struct cras_set_system_mute *)msg)->mute);
544 		break;
545 	case CRAS_SERVER_SET_NODE_ATTR: {
546 		const struct cras_set_node_attr *m =
547 			(const struct cras_set_node_attr *)msg;
548 		if (!MSG_LEN_VALID(msg, struct cras_set_node_attr))
549 			return -EINVAL;
550 		cras_iodev_list_set_node_attr(m->node_id, m->attr, m->value);
551 		break;
552 	}
553 	case CRAS_SERVER_SELECT_NODE: {
554 		const struct cras_select_node *m =
555 			(const struct cras_select_node *)msg;
556 		if (!MSG_LEN_VALID(msg, struct cras_select_node) ||
557 		    !direction_valid(m->direction))
558 			return -EINVAL;
559 		cras_iodev_list_select_node(m->direction, m->node_id);
560 		break;
561 	}
562 	case CRAS_SERVER_ADD_ACTIVE_NODE: {
563 		const struct cras_add_active_node *m =
564 			(const struct cras_add_active_node *)msg;
565 		if (!MSG_LEN_VALID(msg, struct cras_add_active_node) ||
566 		    !direction_valid(m->direction))
567 			return -EINVAL;
568 		cras_iodev_list_add_active_node(m->direction, m->node_id);
569 		break;
570 	}
571 	case CRAS_SERVER_RM_ACTIVE_NODE: {
572 		const struct cras_rm_active_node *m =
573 			(const struct cras_rm_active_node *)msg;
574 		if (!MSG_LEN_VALID(msg, struct cras_rm_active_node) ||
575 		    !direction_valid(m->direction))
576 			return -EINVAL;
577 		cras_iodev_list_rm_active_node(m->direction, m->node_id);
578 		break;
579 	}
580 	case CRAS_SERVER_RELOAD_DSP:
581 		cras_dsp_reload_ini();
582 		break;
583 	case CRAS_SERVER_DUMP_DSP_INFO:
584 		cras_dsp_dump_info();
585 		break;
586 	case CRAS_SERVER_DUMP_AUDIO_THREAD:
587 		dump_audio_thread_info(client);
588 		break;
589 	case CRAS_SERVER_DUMP_SNAPSHOTS:
590 		dump_audio_thread_snapshots(client);
591 		break;
592 	case CRAS_SERVER_ADD_TEST_DEV: {
593 		const struct cras_add_test_dev *m =
594 			(const struct cras_add_test_dev *)msg;
595 		if (!MSG_LEN_VALID(msg, struct cras_add_test_dev))
596 			return -EINVAL;
597 		cras_iodev_list_add_test_dev(m->type);
598 		break;
599 	}
600 	case CRAS_SERVER_TEST_DEV_COMMAND: {
601 		const struct cras_test_dev_command *m =
602 			(const struct cras_test_dev_command *)msg;
603 		if (!MSG_LEN_VALID(msg, struct cras_test_dev_command))
604 			return -EINVAL;
605 		cras_iodev_list_test_dev_command(
606 			m->iodev_idx, (enum CRAS_TEST_IODEV_CMD)m->command,
607 			m->data_len, m->data);
608 		break;
609 	}
610 	case CRAS_SERVER_SUSPEND:
611 		cras_system_set_suspended(1);
612 		break;
613 	case CRAS_SERVER_RESUME:
614 		cras_system_set_suspended(0);
615 		break;
616 	case CRAS_CONFIG_GLOBAL_REMIX: {
617 		const struct cras_config_global_remix *m =
618 			(const struct cras_config_global_remix *)msg;
619 		if (!MSG_LEN_VALID(msg, struct cras_config_global_remix) ||
620 		    m->num_channels > CRAS_MAX_REMIX_CHANNELS)
621 			return -EINVAL;
622 		size_t size_with_coefficients = sizeof(*m) +
623 			m->num_channels * m->num_channels *
624 			sizeof(m->coefficient[0]);
625 		if (size_with_coefficients != msg->length)
626 			return -EINVAL;
627 		audio_thread_config_global_remix(
628 				cras_iodev_list_get_audio_thread(),
629 				m->num_channels,
630 				m->coefficient);
631 		break;
632 	}
633 	case CRAS_SERVER_GET_HOTWORD_MODELS: {
634 		if (!MSG_LEN_VALID(msg, struct cras_get_hotword_models))
635 			return -EINVAL;
636 		handle_get_hotword_models(client,
637 			((const struct cras_get_hotword_models *)msg)->node_id);
638 		break;
639 	}
640 	case CRAS_SERVER_SET_HOTWORD_MODEL: {
641 		const struct cras_set_hotword_model *m =
642 			(const struct cras_set_hotword_model *)msg;
643 		if (!MSG_LEN_VALID(msg, struct cras_set_hotword_model))
644 			return -EINVAL;
645 		cras_iodev_list_set_hotword_model(m->node_id,
646 						  m->model_name);
647 		break;
648 	}
649 	case CRAS_SERVER_REGISTER_NOTIFICATION: {
650 		const struct cras_register_notification *m =
651 			(struct cras_register_notification *)msg;
652 		if (!MSG_LEN_VALID(msg, struct cras_register_notification))
653 			return -EINVAL;
654 		register_for_notification(
655 			client, (enum CRAS_CLIENT_MESSAGE_ID)m->msg_id,
656 			m->do_register);
657 		break;
658 	}
659 	case CRAS_SERVER_SET_AEC_DUMP: {
660 		const struct cras_set_aec_dump *m =
661 			(const struct cras_set_aec_dump *)msg;
662 		if (!MSG_LEN_VALID(msg, struct cras_set_aec_dump))
663 			return -EINVAL;
664 		audio_thread_set_aec_dump(
665 				cras_iodev_list_get_audio_thread(),
666 				m->stream_id,
667 				m->start, fd);
668 		break;
669 	}
670 	case CRAS_SERVER_RELOAD_AEC_CONFIG:
671 		cras_apm_list_reload_aec_config();
672 		break;
673 	default:
674 		break;
675 	}
676 
677 	return 0;
678 }
679 
680 /* Sends a message to the client. */
cras_rclient_send_message(const struct cras_rclient * client,const struct cras_client_message * msg,int * fds,unsigned int num_fds)681 int cras_rclient_send_message(const struct cras_rclient *client,
682 			      const struct cras_client_message *msg,
683 			      int *fds,
684 			      unsigned int num_fds)
685 {
686 	return cras_send_with_fds(client->fd, (const void *)msg, msg->length,
687 				  fds, num_fds);
688 }
689 
690