• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2013 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 <dbus/dbus.h>
7 #include <errno.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <syslog.h>
12 
13 #include "audio_thread.h"
14 #include "cras_bt_player.h"
15 #include "cras_dbus.h"
16 #include "cras_dbus_control.h"
17 #include "cras_dbus_util.h"
18 #include "cras_hfp_ag_profile.h"
19 #include "cras_iodev_list.h"
20 #include "cras_main_thread_log.h"
21 #include "cras_observer.h"
22 #include "cras_system_state.h"
23 #include "cras_utf8.h"
24 #include "cras_util.h"
25 #include "utlist.h"
26 
27 #define CRAS_CONTROL_INTERFACE "org.chromium.cras.Control"
28 #define CRAS_ROOT_OBJECT_PATH "/org/chromium/cras"
29 #define CONTROL_INTROSPECT_XML                                                  \
30 	DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                               \
31 	"<node>\n"                                                              \
32 	"  <interface name=\"" CRAS_CONTROL_INTERFACE "\">\n"                   \
33 	"    <method name=\"SetOutputVolume\">\n"                               \
34 	"      <arg name=\"volume\" type=\"i\" direction=\"in\"/>\n"            \
35 	"    </method>\n"                                                       \
36 	"    <method name=\"SetOutputNodeVolume\">\n"                           \
37 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
38 	"      <arg name=\"volume\" type=\"i\" direction=\"in\"/>\n"            \
39 	"    </method>\n"                                                       \
40 	"    <method name=\"SwapLeftRight\">\n"                                 \
41 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
42 	"      <arg name=\"swap\" type=\"b\" direction=\"in\"/>\n"              \
43 	"    </method>\n"                                                       \
44 	"    <method name=\"SetOutputMute\">\n"                                 \
45 	"      <arg name=\"mute_on\" type=\"b\" direction=\"in\"/>\n"           \
46 	"    </method>\n"                                                       \
47 	"    <method name=\"SetOutputUserMute\">\n"                             \
48 	"      <arg name=\"mute_on\" type=\"b\" direction=\"in\"/>\n"           \
49 	"    </method>\n"                                                       \
50 	"    <method name=\"SetSuspendAudio\">\n"                               \
51 	"      <arg name=\"suspend\" type=\"b\" direction=\"in\"/>\n"           \
52 	"    </method>\n"                                                       \
53 	"    <method name=\"SetInputNodeGain\">\n"                              \
54 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
55 	"      <arg name=\"gain\" type=\"i\" direction=\"in\"/>\n"              \
56 	"    </method>\n"                                                       \
57 	"    <method name=\"SetInputMute\">\n"                                  \
58 	"      <arg name=\"mute_on\" type=\"b\" direction=\"in\"/>\n"           \
59 	"    </method>\n"                                                       \
60 	"    <method name=\"GetVolumeState\">\n"                                \
61 	"      <arg name=\"output_volume\" type=\"i\" direction=\"out\"/>\n"    \
62 	"      <arg name=\"output_mute\" type=\"b\" direction=\"out\"/>\n"      \
63 	"      <arg name=\"input_mute\" type=\"b\" direction=\"out\"/>\n"       \
64 	"      <arg name=\"output_user_mute\" type=\"b\" direction=\"out\"/>\n" \
65 	"    </method>\n"                                                       \
66 	"    <method name=\"GetDefaultOutputBufferSize\">\n"                    \
67 	"      <arg name=\"buffer_size\" type=\"i\" direction=\"out\"/>\n"      \
68 	"    </method>\n"                                                       \
69 	"    <method name=\"GetNodes\">\n"                                      \
70 	"      <arg name=\"nodes\" type=\"a{sv}\" direction=\"out\"/>\n"        \
71 	"    </method>\n"                                                       \
72 	"    <method name=\"GetSystemAecSupported\">\n"                         \
73 	"      <arg name=\"supported\" type=\"b\" direction=\"out\"/>\n"        \
74 	"    </method>\n"                                                       \
75 	"    <method name=\"GetSystemAecGroupId\">\n"                           \
76 	"      <arg name=\"group_id\" type=\"i\" direction=\"out\"/>\n"         \
77 	"    </method>\n"                                                       \
78 	"    <method name=\"GetDeprioritizeBtWbsMic\">\n"                       \
79 	"      <arg name=\"deprioritized\" type=\"b\" direction=\"out\"/>\n"    \
80 	"    </method>\n"                                                       \
81 	"    <method name=\"SetActiveOutputNode\">\n"                           \
82 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
83 	"    </method>\n"                                                       \
84 	"    <method name=\"SetActiveInputNode\">\n"                            \
85 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
86 	"    </method>\n"                                                       \
87 	"    <method name=\"AddActiveInputNode\">\n"                            \
88 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
89 	"    </method>\n"                                                       \
90 	"    <method name=\"AddActiveOutputNode\">\n"                           \
91 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
92 	"    </method>\n"                                                       \
93 	"    <method name=\"RemoveActiveInputNode\">\n"                         \
94 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
95 	"    </method>\n"                                                       \
96 	"    <method name=\"RemoveActiveOutputNode\">\n"                        \
97 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
98 	"    </method>\n"                                                       \
99 	"    <method name=\"SetFixA2dpPacketSize\">\n"                          \
100 	"      <arg name=\"toggle\" type=\"b\" direction=\"in\"/>\n"            \
101 	"    </method>\n"                                                       \
102 	"    <method name=\"GetNumberOfActiveStreams\">\n"                      \
103 	"      <arg name=\"num\" type=\"i\" direction=\"out\"/>\n"              \
104 	"    </method>\n"                                                       \
105 	"    <method name=\"GetNumberOfActiveOutputStreams\">\n"                \
106 	"      <arg name=\"num\" type=\"i\" direction=\"out\"/>\n"              \
107 	"    </method>\n"                                                       \
108 	"    <method name=\"GetNumberOfActiveInputStreams\">\n"                 \
109 	"      <arg name=\"num\" type=\"i\" direction=\"out\"/>\n"              \
110 	"    </method>\n"                                                       \
111 	"    <method name=\"GetNumberOfInputStreamsWithPermission\">\n"         \
112 	"      <arg name=\"num\" type=\"a{sv}\" direction=\"out\"/>\n"          \
113 	"    </method>\n"                                                       \
114 	"    <method name=\"SetGlobalOutputChannelRemix\">\n"                   \
115 	"      <arg name=\"num_channels\" type=\"i\" direction=\"in\"/>\n"      \
116 	"      <arg name=\"coefficient\" type=\"ad\" direction=\"in\"/>\n"      \
117 	"    </method>\n"                                                       \
118 	"    <method name=\"SetHotwordModel\">\n"                               \
119 	"      <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n"           \
120 	"      <arg name=\"model_name\" type=\"s\" direction=\"in\"/>\n"        \
121 	"    </method>\n"                                                       \
122 	"    <method name=\"IsAudioOutputActive\">\n"                           \
123 	"      <arg name=\"active\" type=\"b\" direction=\"out\"/>\n"           \
124 	"    </method>\n"                                                       \
125 	"    <method name=\"SetWbsEnabled\">\n"                                 \
126 	"      <arg name=\"enabled\" type=\"b\" direction=\"in\"/>\n"           \
127 	"    </method>\n"                                                       \
128 	"    <method name=\"SetNoiseCancellationEnabled\">\n"                   \
129 	"      <arg name=\"enabled\" type=\"b\" direction=\"in\"/>\n"           \
130 	"    </method>\n"                                                       \
131 	"    <method name=\"SetPlayerPlaybackStatus\">\n"                       \
132 	"      <arg name=\"status\" type=\"s\" direction=\"in\"/>\n"            \
133 	"    </method>\n"                                                       \
134 	"    <method name=\"SetPlayerIdentity\">\n"                             \
135 	"      <arg name=\"identity\" type=\"s\" direction=\"in\"/>\n"          \
136 	"    </method>\n"                                                       \
137 	"    <method name=\"SetPlayerPosition\">\n"                             \
138 	"      <arg name=\"position\" type=\"x\" direction=\"in\"/>\n"          \
139 	"    </method>\n"                                                       \
140 	"    <method name=\"SetPlayerMetadata\">\n"                             \
141 	"      <arg name=\"metadata\" type=\"a{sv}\" direction=\"in\"/>\n"      \
142 	"    </method>\n"                                                       \
143 	"  </interface>\n"                                                      \
144 	"  <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"            \
145 	"    <method name=\"Introspect\">\n"                                    \
146 	"      <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"             \
147 	"    </method>\n"                                                       \
148 	"  </interface>\n"                                                      \
149 	"</node>\n"
150 
151 struct cras_dbus_control {
152 	DBusConnection *conn;
153 	struct cras_observer_client *observer;
154 };
155 static struct cras_dbus_control dbus_control;
156 
157 /* helper to extract a single argument from a DBus message. */
get_single_arg(DBusMessage * message,int dbus_type,void * arg)158 static int get_single_arg(DBusMessage *message, int dbus_type, void *arg)
159 {
160 	DBusError dbus_error;
161 
162 	dbus_error_init(&dbus_error);
163 
164 	if (!dbus_message_get_args(message, &dbus_error, dbus_type, arg,
165 				   DBUS_TYPE_INVALID)) {
166 		syslog(LOG_WARNING, "Bad method received: %s",
167 		       dbus_error.message);
168 		dbus_error_free(&dbus_error);
169 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
170 	}
171 
172 	return 0;
173 }
174 
get_string_metadata(DBusMessageIter * iter,const char ** dst)175 static bool get_string_metadata(DBusMessageIter *iter, const char **dst)
176 {
177 	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
178 		return FALSE;
179 
180 	dbus_message_iter_get_basic(iter, dst);
181 	return TRUE;
182 }
183 
get_int64_metadata(DBusMessageIter * iter,dbus_int64_t * dst)184 static bool get_int64_metadata(DBusMessageIter *iter, dbus_int64_t *dst)
185 {
186 	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INT64)
187 		return FALSE;
188 
189 	dbus_message_iter_get_basic(iter, dst);
190 	return TRUE;
191 }
192 
get_metadata(DBusMessage * message,const char ** title,const char ** artist,const char ** album,dbus_int64_t * length)193 static bool get_metadata(DBusMessage *message, const char **title,
194 			 const char **artist, const char **album,
195 			 dbus_int64_t *length)
196 {
197 	DBusError dbus_error;
198 	DBusMessageIter iter, dict;
199 
200 	dbus_error_init(&dbus_error);
201 	dbus_message_iter_init(message, &iter);
202 
203 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
204 		return FALSE;
205 
206 	dbus_message_iter_recurse(&iter, &dict);
207 
208 	while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
209 		DBusMessageIter entry, var;
210 		const char *key;
211 
212 		if (dbus_message_iter_get_arg_type(&dict) !=
213 		    DBUS_TYPE_DICT_ENTRY)
214 			return FALSE;
215 
216 		dbus_message_iter_recurse(&dict, &entry);
217 		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
218 			return FALSE;
219 
220 		dbus_message_iter_get_basic(&entry, &key);
221 		dbus_message_iter_next(&entry);
222 
223 		if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
224 			return FALSE;
225 
226 		dbus_message_iter_recurse(&entry, &var);
227 		if (strcasecmp(key, "title") == 0) {
228 			if (!get_string_metadata(&var, title))
229 				return FALSE;
230 		} else if (strcasecmp(key, "artist") == 0) {
231 			if (!get_string_metadata(&var, artist))
232 				return FALSE;
233 		} else if (strcasecmp(key, "album") == 0) {
234 			if (!get_string_metadata(&var, album))
235 				return FALSE;
236 		} else if (strcasecmp(key, "length") == 0) {
237 			if (!get_int64_metadata(&var, length))
238 				return FALSE;
239 		} else
240 			syslog(LOG_WARNING, "%s not supported, ignoring", key);
241 
242 		dbus_message_iter_next(&dict);
243 	}
244 
245 	return TRUE;
246 }
247 
248 /* Helper to send an empty reply. */
send_empty_reply(DBusConnection * conn,DBusMessage * message)249 static void send_empty_reply(DBusConnection *conn, DBusMessage *message)
250 {
251 	DBusMessage *reply;
252 	dbus_uint32_t serial = 0;
253 
254 	reply = dbus_message_new_method_return(message);
255 	if (!reply)
256 		return;
257 
258 	dbus_connection_send(conn, reply, &serial);
259 
260 	dbus_message_unref(reply);
261 }
262 
263 /* Helper to send an int32 reply. */
send_int32_reply(DBusConnection * conn,DBusMessage * message,dbus_int32_t value)264 static void send_int32_reply(DBusConnection *conn, DBusMessage *message,
265 			     dbus_int32_t value)
266 {
267 	DBusMessage *reply;
268 	dbus_uint32_t serial = 0;
269 
270 	reply = dbus_message_new_method_return(message);
271 	if (!reply)
272 		return;
273 
274 	dbus_message_append_args(reply, DBUS_TYPE_INT32, &value,
275 				 DBUS_TYPE_INVALID);
276 	dbus_connection_send(conn, reply, &serial);
277 
278 	dbus_message_unref(reply);
279 }
280 
281 /* Handlers for exported DBus method calls. */
282 static DBusHandlerResult
handle_set_output_volume(DBusConnection * conn,DBusMessage * message,void * arg)283 handle_set_output_volume(DBusConnection *conn, DBusMessage *message, void *arg)
284 {
285 	int rc;
286 	dbus_int32_t new_vol;
287 
288 	rc = get_single_arg(message, DBUS_TYPE_INT32, &new_vol);
289 	if (rc)
290 		return rc;
291 
292 	cras_system_set_volume(new_vol);
293 
294 	send_empty_reply(conn, message);
295 
296 	return DBUS_HANDLER_RESULT_HANDLED;
297 }
298 
handle_set_output_node_volume(DBusConnection * conn,DBusMessage * message,void * arg)299 static DBusHandlerResult handle_set_output_node_volume(DBusConnection *conn,
300 						       DBusMessage *message,
301 						       void *arg)
302 {
303 	dbus_int32_t new_vol;
304 	cras_node_id_t id;
305 	DBusError dbus_error;
306 
307 	dbus_error_init(&dbus_error);
308 
309 	if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_UINT64, &id,
310 				   DBUS_TYPE_INT32, &new_vol,
311 				   DBUS_TYPE_INVALID)) {
312 		syslog(LOG_WARNING, "Bad method received: %s",
313 		       dbus_error.message);
314 		dbus_error_free(&dbus_error);
315 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
316 	}
317 
318 	cras_iodev_list_set_node_attr(id, IONODE_ATTR_VOLUME, new_vol);
319 
320 	send_empty_reply(conn, message);
321 
322 	return DBUS_HANDLER_RESULT_HANDLED;
323 }
324 
handle_swap_left_right(DBusConnection * conn,DBusMessage * message,void * arg)325 static DBusHandlerResult handle_swap_left_right(DBusConnection *conn,
326 						DBusMessage *message, void *arg)
327 {
328 	cras_node_id_t id;
329 	dbus_bool_t swap;
330 	DBusError dbus_error;
331 
332 	dbus_error_init(&dbus_error);
333 
334 	if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_UINT64, &id,
335 				   DBUS_TYPE_BOOLEAN, &swap,
336 				   DBUS_TYPE_INVALID)) {
337 		syslog(LOG_WARNING, "Bad method received: %s",
338 		       dbus_error.message);
339 		dbus_error_free(&dbus_error);
340 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
341 	}
342 
343 	cras_iodev_list_set_node_attr(id, IONODE_ATTR_SWAP_LEFT_RIGHT, swap);
344 
345 	send_empty_reply(conn, message);
346 
347 	return DBUS_HANDLER_RESULT_HANDLED;
348 }
349 
handle_set_output_mute(DBusConnection * conn,DBusMessage * message,void * arg)350 static DBusHandlerResult handle_set_output_mute(DBusConnection *conn,
351 						DBusMessage *message, void *arg)
352 {
353 	int rc;
354 	dbus_bool_t new_mute;
355 
356 	rc = get_single_arg(message, DBUS_TYPE_BOOLEAN, &new_mute);
357 	if (rc)
358 		return rc;
359 
360 	cras_system_set_mute(new_mute);
361 
362 	send_empty_reply(conn, message);
363 
364 	return DBUS_HANDLER_RESULT_HANDLED;
365 }
366 
handle_set_output_user_mute(DBusConnection * conn,DBusMessage * message,void * arg)367 static DBusHandlerResult handle_set_output_user_mute(DBusConnection *conn,
368 						     DBusMessage *message,
369 						     void *arg)
370 {
371 	int rc;
372 	dbus_bool_t new_mute;
373 
374 	rc = get_single_arg(message, DBUS_TYPE_BOOLEAN, &new_mute);
375 	if (rc)
376 		return rc;
377 
378 	cras_system_set_user_mute(new_mute);
379 	MAINLOG(main_log, MAIN_THREAD_SET_OUTPUT_USER_MUTE, new_mute, 0, 0);
380 
381 	send_empty_reply(conn, message);
382 
383 	return DBUS_HANDLER_RESULT_HANDLED;
384 }
385 
386 static DBusHandlerResult
handle_set_suspend_audio(DBusConnection * conn,DBusMessage * message,void * arg)387 handle_set_suspend_audio(DBusConnection *conn, DBusMessage *message, void *arg)
388 {
389 	int rc;
390 	dbus_bool_t suspend;
391 	rc = get_single_arg(message, DBUS_TYPE_BOOLEAN, &suspend);
392 	if (rc)
393 		return rc;
394 
395 	cras_system_set_suspended(suspend);
396 
397 	send_empty_reply(conn, message);
398 
399 	return DBUS_HANDLER_RESULT_HANDLED;
400 }
401 
handle_set_input_node_gain(DBusConnection * conn,DBusMessage * message,void * arg)402 static DBusHandlerResult handle_set_input_node_gain(DBusConnection *conn,
403 						    DBusMessage *message,
404 						    void *arg)
405 {
406 	dbus_int32_t new_gain;
407 	cras_node_id_t id;
408 	DBusError dbus_error;
409 
410 	dbus_error_init(&dbus_error);
411 
412 	if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_UINT64, &id,
413 				   DBUS_TYPE_INT32, &new_gain,
414 				   DBUS_TYPE_INVALID)) {
415 		syslog(LOG_WARNING, "Bad method received: %s",
416 		       dbus_error.message);
417 		dbus_error_free(&dbus_error);
418 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
419 	}
420 
421 	cras_iodev_list_set_node_attr(id, IONODE_ATTR_CAPTURE_GAIN, new_gain);
422 
423 	send_empty_reply(conn, message);
424 
425 	return DBUS_HANDLER_RESULT_HANDLED;
426 }
427 
handle_set_input_mute(DBusConnection * conn,DBusMessage * message,void * arg)428 static DBusHandlerResult handle_set_input_mute(DBusConnection *conn,
429 					       DBusMessage *message, void *arg)
430 {
431 	int rc;
432 	dbus_bool_t new_mute;
433 
434 	rc = get_single_arg(message, DBUS_TYPE_BOOLEAN, &new_mute);
435 	if (rc)
436 		return rc;
437 
438 	cras_system_set_capture_mute(new_mute);
439 
440 	send_empty_reply(conn, message);
441 
442 	return DBUS_HANDLER_RESULT_HANDLED;
443 }
444 
445 static DBusHandlerResult
handle_get_volume_state(DBusConnection * conn,DBusMessage * message,void * arg)446 handle_get_volume_state(DBusConnection *conn, DBusMessage *message, void *arg)
447 {
448 	DBusMessage *reply;
449 	dbus_uint32_t serial = 0;
450 	dbus_int32_t volume;
451 	dbus_bool_t system_muted;
452 	dbus_bool_t user_muted;
453 	dbus_bool_t capture_muted;
454 
455 	reply = dbus_message_new_method_return(message);
456 
457 	volume = cras_system_get_volume();
458 	system_muted = cras_system_get_system_mute();
459 	user_muted = cras_system_get_user_mute();
460 	capture_muted = cras_system_get_capture_mute();
461 
462 	dbus_message_append_args(reply, DBUS_TYPE_INT32, &volume,
463 				 DBUS_TYPE_BOOLEAN, &system_muted,
464 				 DBUS_TYPE_BOOLEAN, &capture_muted,
465 				 DBUS_TYPE_BOOLEAN, &user_muted,
466 				 DBUS_TYPE_INVALID);
467 
468 	dbus_connection_send(conn, reply, &serial);
469 
470 	dbus_message_unref(reply);
471 
472 	return DBUS_HANDLER_RESULT_HANDLED;
473 }
474 
475 static DBusHandlerResult
handle_get_default_output_buffer_size(DBusConnection * conn,DBusMessage * message,void * arg)476 handle_get_default_output_buffer_size(DBusConnection *conn,
477 				      DBusMessage *message, void *arg)
478 {
479 	DBusMessage *reply;
480 	dbus_uint32_t serial = 0;
481 	dbus_int32_t buffer_size;
482 
483 	reply = dbus_message_new_method_return(message);
484 
485 	buffer_size = cras_system_get_default_output_buffer_size();
486 	dbus_message_append_args(reply, DBUS_TYPE_INT32, &buffer_size,
487 				 DBUS_TYPE_INVALID);
488 
489 	dbus_connection_send(conn, reply, &serial);
490 
491 	dbus_message_unref(reply);
492 
493 	return DBUS_HANDLER_RESULT_HANDLED;
494 }
495 
496 /* Appends the information about a node to the dbus message. Returns
497  * false if not enough memory. */
append_node_dict(DBusMessageIter * iter,const struct cras_iodev_info * dev,const struct cras_ionode_info * node,enum CRAS_STREAM_DIRECTION direction)498 static dbus_bool_t append_node_dict(DBusMessageIter *iter,
499 				    const struct cras_iodev_info *dev,
500 				    const struct cras_ionode_info *node,
501 				    enum CRAS_STREAM_DIRECTION direction)
502 {
503 	DBusMessageIter dict;
504 	dbus_bool_t is_input;
505 	dbus_uint64_t id;
506 	const char *dev_name = dev->name;
507 	dbus_uint64_t stable_dev_id = node->stable_id;
508 	const char *node_type = node->type;
509 	const char *node_name = node->name;
510 	dbus_bool_t active;
511 	dbus_uint64_t plugged_time = node->plugged_time.tv_sec * 1000000ULL +
512 				     node->plugged_time.tv_usec;
513 	dbus_uint64_t node_volume = node->volume;
514 	dbus_int64_t node_capture_gain = node->capture_gain;
515 	char *models, *empty_models = "";
516 
517 	is_input = (direction == CRAS_STREAM_INPUT);
518 	id = node->iodev_idx;
519 	id = (id << 32) | node->ionode_idx;
520 	active = !!node->active;
521 
522 	// If dev_name is not utf8, libdbus may abort cras.
523 	if (!is_utf8_string(dev_name)) {
524 		syslog(LOG_ERR,
525 		       "Non-utf8 device name '%s' cannot be sent via dbus",
526 		       dev_name);
527 		dev_name = "";
528 	}
529 
530 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}",
531 					      &dict))
532 		return FALSE;
533 	if (!append_key_value(&dict, "IsInput", DBUS_TYPE_BOOLEAN,
534 			      DBUS_TYPE_BOOLEAN_AS_STRING, &is_input))
535 		return FALSE;
536 	if (!append_key_value(&dict, "Id", DBUS_TYPE_UINT64,
537 			      DBUS_TYPE_UINT64_AS_STRING, &id))
538 		return FALSE;
539 	if (!append_key_value(&dict, "DeviceName", DBUS_TYPE_STRING,
540 			      DBUS_TYPE_STRING_AS_STRING, &dev_name))
541 		return FALSE;
542 	/*
543 	 * If stable id migration is needed, use key 'StableDeviceIdNew'
544 	 * together with 'StableDeviceId'.
545 	 */
546 	if (!append_key_value(&dict, "StableDeviceId", DBUS_TYPE_UINT64,
547 			      DBUS_TYPE_UINT64_AS_STRING, &stable_dev_id))
548 		return FALSE;
549 	if (!append_key_value(&dict, "Type", DBUS_TYPE_STRING,
550 			      DBUS_TYPE_STRING_AS_STRING, &node_type))
551 		return FALSE;
552 	if (!append_key_value(&dict, "Name", DBUS_TYPE_STRING,
553 			      DBUS_TYPE_STRING_AS_STRING, &node_name))
554 		return FALSE;
555 	if (!append_key_value(&dict, "Active", DBUS_TYPE_BOOLEAN,
556 			      DBUS_TYPE_BOOLEAN_AS_STRING, &active))
557 		return FALSE;
558 	if (!append_key_value(&dict, "PluggedTime", DBUS_TYPE_UINT64,
559 			      DBUS_TYPE_UINT64_AS_STRING, &plugged_time))
560 		return FALSE;
561 	if (!append_key_value(&dict, "NodeVolume", DBUS_TYPE_UINT64,
562 			      DBUS_TYPE_UINT64_AS_STRING, &node_volume))
563 		return FALSE;
564 	if (!append_key_value(&dict, "NodeCaptureGain", DBUS_TYPE_INT64,
565 			      DBUS_TYPE_INT64_AS_STRING, &node_capture_gain))
566 		return FALSE;
567 
568 	models = cras_iodev_list_get_hotword_models(id);
569 	if (!append_key_value(&dict, "HotwordModels", DBUS_TYPE_STRING,
570 			      DBUS_TYPE_STRING_AS_STRING,
571 			      models ? &models : &empty_models)) {
572 		free(models);
573 		return FALSE;
574 	}
575 	free(models);
576 
577 	if (!dbus_message_iter_close_container(iter, &dict))
578 		return FALSE;
579 
580 	return TRUE;
581 }
582 
583 /* Appends the information about all nodes in a given direction. Returns false
584  * if not enough memory. */
append_nodes(enum CRAS_STREAM_DIRECTION direction,DBusMessageIter * array)585 static dbus_bool_t append_nodes(enum CRAS_STREAM_DIRECTION direction,
586 				DBusMessageIter *array)
587 {
588 	const struct cras_iodev_info *devs;
589 	const struct cras_ionode_info *nodes;
590 	int ndevs, nnodes;
591 	int i, j;
592 
593 	if (direction == CRAS_STREAM_OUTPUT) {
594 		ndevs = cras_system_state_get_output_devs(&devs);
595 		nnodes = cras_system_state_get_output_nodes(&nodes);
596 	} else {
597 		ndevs = cras_system_state_get_input_devs(&devs);
598 		nnodes = cras_system_state_get_input_nodes(&nodes);
599 	}
600 
601 	for (i = 0; i < nnodes; i++) {
602 		/* Don't reply unplugged nodes. */
603 		if (!nodes[i].plugged)
604 			continue;
605 		/* Find the device for this node. */
606 		for (j = 0; j < ndevs; j++)
607 			if (devs[j].idx == nodes[i].iodev_idx)
608 				break;
609 		if (j == ndevs)
610 			continue;
611 		/* Send information about this node. */
612 		if (!append_node_dict(array, &devs[j], &nodes[i], direction))
613 			return FALSE;
614 	}
615 
616 	return TRUE;
617 }
618 
handle_get_nodes(DBusConnection * conn,DBusMessage * message,void * arg)619 static DBusHandlerResult handle_get_nodes(DBusConnection *conn,
620 					  DBusMessage *message, void *arg)
621 {
622 	DBusMessage *reply;
623 	DBusMessageIter array;
624 	dbus_uint32_t serial = 0;
625 
626 	reply = dbus_message_new_method_return(message);
627 	dbus_message_iter_init_append(reply, &array);
628 	if (!append_nodes(CRAS_STREAM_OUTPUT, &array))
629 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
630 	if (!append_nodes(CRAS_STREAM_INPUT, &array))
631 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
632 	dbus_connection_send(conn, reply, &serial);
633 	dbus_message_unref(reply);
634 
635 	return DBUS_HANDLER_RESULT_HANDLED;
636 }
637 
handle_get_system_aec_supported(DBusConnection * conn,DBusMessage * message,void * arg)638 static DBusHandlerResult handle_get_system_aec_supported(DBusConnection *conn,
639 							 DBusMessage *message,
640 							 void *arg)
641 {
642 	DBusMessage *reply;
643 	dbus_uint32_t serial = 0;
644 	dbus_bool_t system_aec_supported;
645 
646 	reply = dbus_message_new_method_return(message);
647 
648 	system_aec_supported = cras_system_get_aec_supported();
649 	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
650 				 &system_aec_supported, DBUS_TYPE_INVALID);
651 
652 	dbus_connection_send(conn, reply, &serial);
653 
654 	dbus_message_unref(reply);
655 
656 	return DBUS_HANDLER_RESULT_HANDLED;
657 }
658 
handle_get_system_aec_group_id(DBusConnection * conn,DBusMessage * message,void * arg)659 static DBusHandlerResult handle_get_system_aec_group_id(DBusConnection *conn,
660 							DBusMessage *message,
661 							void *arg)
662 {
663 	DBusMessage *reply;
664 	dbus_uint32_t serial = 0;
665 	dbus_int32_t system_aec_group_id;
666 
667 	reply = dbus_message_new_method_return(message);
668 
669 	system_aec_group_id = cras_system_get_aec_group_id();
670 	dbus_message_append_args(reply, DBUS_TYPE_INT32, &system_aec_group_id,
671 				 DBUS_TYPE_INVALID);
672 
673 	dbus_connection_send(conn, reply, &serial);
674 
675 	dbus_message_unref(reply);
676 
677 	return DBUS_HANDLER_RESULT_HANDLED;
678 }
679 
680 static DBusHandlerResult
handle_get_deprioritize_bt_wbs_mic(DBusConnection * conn,DBusMessage * message,void * arg)681 handle_get_deprioritize_bt_wbs_mic(DBusConnection *conn, DBusMessage *message,
682 				   void *arg)
683 {
684 	DBusMessage *reply;
685 	dbus_uint32_t serial = 0;
686 	dbus_bool_t deprioritized;
687 
688 	reply = dbus_message_new_method_return(message);
689 
690 	deprioritized = cras_system_get_deprioritize_bt_wbs_mic();
691 	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &deprioritized,
692 				 DBUS_TYPE_INVALID);
693 
694 	dbus_connection_send(conn, reply, &serial);
695 
696 	dbus_message_unref(reply);
697 
698 	return DBUS_HANDLER_RESULT_HANDLED;
699 }
700 
701 static DBusHandlerResult
handle_set_active_node(DBusConnection * conn,DBusMessage * message,void * arg,enum CRAS_STREAM_DIRECTION direction)702 handle_set_active_node(DBusConnection *conn, DBusMessage *message, void *arg,
703 		       enum CRAS_STREAM_DIRECTION direction)
704 {
705 	int rc;
706 	cras_node_id_t id;
707 
708 	rc = get_single_arg(message, DBUS_TYPE_UINT64, &id);
709 	if (rc)
710 		return rc;
711 
712 	cras_iodev_list_select_node(direction, id);
713 
714 	send_empty_reply(conn, message);
715 
716 	return DBUS_HANDLER_RESULT_HANDLED;
717 }
718 
719 static DBusHandlerResult
handle_add_active_node(DBusConnection * conn,DBusMessage * message,void * arg,enum CRAS_STREAM_DIRECTION direction)720 handle_add_active_node(DBusConnection *conn, DBusMessage *message, void *arg,
721 		       enum CRAS_STREAM_DIRECTION direction)
722 {
723 	int rc;
724 	cras_node_id_t id;
725 
726 	rc = get_single_arg(message, DBUS_TYPE_UINT64, &id);
727 	if (rc)
728 		return rc;
729 
730 	cras_iodev_list_add_active_node(direction, id);
731 
732 	send_empty_reply(conn, message);
733 
734 	return DBUS_HANDLER_RESULT_HANDLED;
735 }
736 
737 static DBusHandlerResult
handle_rm_active_node(DBusConnection * conn,DBusMessage * message,void * arg,enum CRAS_STREAM_DIRECTION direction)738 handle_rm_active_node(DBusConnection *conn, DBusMessage *message, void *arg,
739 		      enum CRAS_STREAM_DIRECTION direction)
740 {
741 	int rc;
742 	cras_node_id_t id;
743 
744 	rc = get_single_arg(message, DBUS_TYPE_UINT64, &id);
745 	if (rc)
746 		return rc;
747 
748 	cras_iodev_list_rm_active_node(direction, id);
749 
750 	send_empty_reply(conn, message);
751 
752 	return DBUS_HANDLER_RESULT_HANDLED;
753 }
754 
handle_set_fix_a2dp_packet_size(DBusConnection * conn,DBusMessage * message,void * arg)755 static DBusHandlerResult handle_set_fix_a2dp_packet_size(DBusConnection *conn,
756 							 DBusMessage *message,
757 							 void *arg)
758 {
759 	int rc;
760 	dbus_bool_t enabled = FALSE;
761 
762 	rc = get_single_arg(message, DBUS_TYPE_BOOLEAN, &enabled);
763 	if (rc)
764 		return rc;
765 
766 	cras_system_set_bt_fix_a2dp_packet_size_enabled(enabled);
767 
768 	send_empty_reply(conn, message);
769 
770 	return DBUS_HANDLER_RESULT_HANDLED;
771 }
772 
handle_get_num_active_streams(DBusConnection * conn,DBusMessage * message,void * arg)773 static DBusHandlerResult handle_get_num_active_streams(DBusConnection *conn,
774 						       DBusMessage *message,
775 						       void *arg)
776 {
777 	send_int32_reply(conn, message, cras_system_state_get_active_streams());
778 	return DBUS_HANDLER_RESULT_HANDLED;
779 }
780 
781 static DBusHandlerResult
handle_get_num_active_streams_use_input_hw(DBusConnection * conn,DBusMessage * message,void * arg)782 handle_get_num_active_streams_use_input_hw(DBusConnection *conn,
783 					   DBusMessage *message, void *arg)
784 {
785 	dbus_int32_t num = 0;
786 	unsigned i;
787 
788 	for (i = 0; i < CRAS_NUM_DIRECTIONS; i++) {
789 		if (cras_stream_uses_input_hw(i))
790 			num += cras_system_state_get_active_streams_by_direction(
791 				i);
792 	}
793 	send_int32_reply(conn, message, num);
794 
795 	return DBUS_HANDLER_RESULT_HANDLED;
796 }
797 
798 static DBusHandlerResult
handle_get_num_active_streams_use_output_hw(DBusConnection * conn,DBusMessage * message,void * arg)799 handle_get_num_active_streams_use_output_hw(DBusConnection *conn,
800 					    DBusMessage *message, void *arg)
801 {
802 	dbus_int32_t num = 0;
803 	unsigned i;
804 
805 	for (i = 0; i < CRAS_NUM_DIRECTIONS; i++) {
806 		if (cras_stream_uses_output_hw(i))
807 			num += cras_system_state_get_active_streams_by_direction(
808 				i);
809 	}
810 	send_int32_reply(conn, message, num);
811 
812 	return DBUS_HANDLER_RESULT_HANDLED;
813 }
814 
append_num_input_streams_with_permission(DBusMessage * message,uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])815 static bool append_num_input_streams_with_permission(
816 	DBusMessage *message, uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
817 {
818 	DBusMessageIter array;
819 	DBusMessageIter dict;
820 	unsigned type;
821 
822 	dbus_message_iter_init_append(message, &array);
823 	for (type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type) {
824 		const char *client_type_str = cras_client_type_str(type);
825 		if (!is_utf8_string(client_type_str)) {
826 			syslog(LOG_ERR,
827 			       "Non-utf8 clinet_type_str '%s' cannot be sent "
828 			       "via dbus",
829 			       client_type_str);
830 			client_type_str = "";
831 		}
832 
833 		if (!dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
834 						      "{sv}", &dict))
835 			return false;
836 		if (!append_key_value(&dict, "ClientType", DBUS_TYPE_STRING,
837 				      DBUS_TYPE_STRING_AS_STRING,
838 				      &client_type_str))
839 			return false;
840 		if (!append_key_value(&dict, "NumStreamsWithPermission",
841 				      DBUS_TYPE_UINT32,
842 				      DBUS_TYPE_UINT32_AS_STRING,
843 				      &num_input_streams[type]))
844 			return false;
845 		if (!dbus_message_iter_close_container(&array, &dict))
846 			return false;
847 	}
848 	return true;
849 }
850 
851 static DBusHandlerResult
handle_get_num_input_streams_with_permission(DBusConnection * conn,DBusMessage * message,void * arg)852 handle_get_num_input_streams_with_permission(DBusConnection *conn,
853 					     DBusMessage *message, void *arg)
854 {
855 	DBusMessage *reply;
856 	dbus_uint32_t serial = 0;
857 	uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE] = {};
858 
859 	reply = dbus_message_new_method_return(message);
860 
861 	cras_system_state_get_input_streams_with_permission(num_input_streams);
862 	if (!append_num_input_streams_with_permission(reply, num_input_streams))
863 		goto error;
864 
865 	dbus_connection_send(conn, reply, &serial);
866 	dbus_message_unref(reply);
867 	return DBUS_HANDLER_RESULT_HANDLED;
868 
869 error:
870 	dbus_message_unref(reply);
871 	return DBUS_HANDLER_RESULT_NEED_MEMORY;
872 }
873 
874 static DBusHandlerResult
handle_set_global_output_channel_remix(DBusConnection * conn,DBusMessage * message,void * arg)875 handle_set_global_output_channel_remix(DBusConnection *conn,
876 				       DBusMessage *message, void *arg)
877 {
878 	dbus_int32_t num_channels;
879 	double *coeff_array;
880 	dbus_int32_t count;
881 	DBusError dbus_error;
882 	float *coefficient;
883 	int i;
884 
885 	dbus_error_init(&dbus_error);
886 
887 	if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_INT32,
888 				   &num_channels, DBUS_TYPE_ARRAY,
889 				   DBUS_TYPE_DOUBLE, &coeff_array, &count,
890 				   DBUS_TYPE_INVALID)) {
891 		syslog(LOG_WARNING, "Set global output channel remix error: %s",
892 		       dbus_error.message);
893 		dbus_error_free(&dbus_error);
894 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
895 	}
896 
897 	coefficient = (float *)calloc(count, sizeof(*coefficient));
898 	if (!coefficient)
899 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
900 
901 	for (i = 0; i < count; i++)
902 		coefficient[i] = coeff_array[i];
903 
904 	audio_thread_config_global_remix(cras_iodev_list_get_audio_thread(),
905 					 num_channels, coefficient);
906 
907 	send_empty_reply(conn, message);
908 	free(coefficient);
909 	return DBUS_HANDLER_RESULT_HANDLED;
910 }
911 
912 static DBusHandlerResult
handle_set_hotword_model(DBusConnection * conn,DBusMessage * message,void * arg)913 handle_set_hotword_model(DBusConnection *conn, DBusMessage *message, void *arg)
914 {
915 	cras_node_id_t id;
916 	const char *model_name;
917 	DBusError dbus_error;
918 	dbus_int32_t ret;
919 
920 	dbus_error_init(&dbus_error);
921 
922 	if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_UINT64, &id,
923 				   DBUS_TYPE_STRING, &model_name,
924 				   DBUS_TYPE_INVALID)) {
925 		syslog(LOG_WARNING, "Bad method received: %s",
926 		       dbus_error.message);
927 		dbus_error_free(&dbus_error);
928 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
929 	}
930 
931 	ret = cras_iodev_list_set_hotword_model(id, model_name);
932 	send_int32_reply(conn, message, ret);
933 
934 	return DBUS_HANDLER_RESULT_HANDLED;
935 }
936 
handle_is_audio_active(DBusConnection * conn,DBusMessage * message,void * arg)937 static DBusHandlerResult handle_is_audio_active(DBusConnection *conn,
938 						DBusMessage *message, void *arg)
939 {
940 	dbus_int32_t active = cras_system_state_get_non_empty_status();
941 
942 	send_int32_reply(conn, message, active);
943 
944 	return DBUS_HANDLER_RESULT_HANDLED;
945 }
946 
handle_set_wbs_enabled(DBusConnection * conn,DBusMessage * message,void * arg)947 static DBusHandlerResult handle_set_wbs_enabled(DBusConnection *conn,
948 						DBusMessage *message, void *arg)
949 {
950 	int rc;
951 	dbus_bool_t enabled;
952 
953 	rc = get_single_arg(message, DBUS_TYPE_BOOLEAN, &enabled);
954 	if (rc)
955 		return rc;
956 
957 	cras_system_set_bt_wbs_enabled(enabled);
958 
959 	send_empty_reply(conn, message);
960 
961 	return DBUS_HANDLER_RESULT_HANDLED;
962 }
963 
964 static DBusHandlerResult
handle_set_noise_cancellation_enabled(DBusConnection * conn,DBusMessage * message,void * arg)965 handle_set_noise_cancellation_enabled(DBusConnection *conn,
966 				      DBusMessage *message, void *arg)
967 {
968 	int rc;
969 	dbus_bool_t enabled;
970 
971 	rc = get_single_arg(message, DBUS_TYPE_BOOLEAN, &enabled);
972 	if (rc)
973 		return rc;
974 
975 	cras_system_set_noise_cancellation_enabled(enabled);
976 
977 	send_empty_reply(conn, message);
978 
979 	return DBUS_HANDLER_RESULT_HANDLED;
980 }
981 
handle_set_player_playback_status(DBusConnection * conn,DBusMessage * message,void * arg)982 static DBusHandlerResult handle_set_player_playback_status(DBusConnection *conn,
983 							   DBusMessage *message,
984 							   void *arg)
985 {
986 	char *status;
987 	DBusError dbus_error;
988 	int rc;
989 
990 	dbus_error_init(&dbus_error);
991 
992 	rc = get_single_arg(message, DBUS_TYPE_STRING, &status);
993 	if (rc)
994 		return rc;
995 
996 	rc = cras_bt_player_update_playback_status(conn, status);
997 	if (rc) {
998 		syslog(LOG_WARNING,
999 		       "CRAS failed to update BT Player Status: %d", rc);
1000 	}
1001 
1002 	send_empty_reply(conn, message);
1003 
1004 	return DBUS_HANDLER_RESULT_HANDLED;
1005 }
1006 
handle_set_player_identity(DBusConnection * conn,DBusMessage * message,void * arg)1007 static DBusHandlerResult handle_set_player_identity(DBusConnection *conn,
1008 						    DBusMessage *message,
1009 						    void *arg)
1010 {
1011 	char *identity;
1012 	DBusError dbus_error;
1013 	int rc;
1014 
1015 	dbus_error_init(&dbus_error);
1016 
1017 	rc = get_single_arg(message, DBUS_TYPE_STRING, &identity);
1018 	if (rc)
1019 		return rc;
1020 
1021 	rc = cras_bt_player_update_identity(conn, identity);
1022 	if (rc) {
1023 		syslog(LOG_WARNING,
1024 		       "CRAS failed to update BT Player Identity: %d", rc);
1025 	}
1026 
1027 	send_empty_reply(conn, message);
1028 
1029 	return DBUS_HANDLER_RESULT_HANDLED;
1030 }
1031 
handle_set_player_position(DBusConnection * conn,DBusMessage * message,void * arg)1032 static DBusHandlerResult handle_set_player_position(DBusConnection *conn,
1033 						    DBusMessage *message,
1034 						    void *arg)
1035 {
1036 	dbus_int64_t position;
1037 	DBusError dbus_error;
1038 	int rc;
1039 
1040 	dbus_error_init(&dbus_error);
1041 
1042 	rc = get_single_arg(message, DBUS_TYPE_INT64, &position);
1043 	if (rc)
1044 		return rc;
1045 
1046 	rc = cras_bt_player_update_position(conn, position);
1047 	if (rc) {
1048 		syslog(LOG_WARNING,
1049 		       "CRAS failed to update BT Player Position: %d", rc);
1050 	}
1051 
1052 	send_empty_reply(conn, message);
1053 
1054 	return DBUS_HANDLER_RESULT_HANDLED;
1055 }
1056 
handle_set_player_metadata(DBusConnection * conn,DBusMessage * message,void * arg)1057 static DBusHandlerResult handle_set_player_metadata(DBusConnection *conn,
1058 						    DBusMessage *message,
1059 						    void *arg)
1060 {
1061 	DBusError dbus_error;
1062 	int rc;
1063 
1064 	dbus_error_init(&dbus_error);
1065 	const char *title = NULL, *artist = NULL, *album = NULL;
1066 	dbus_int64_t length = 0;
1067 
1068 	if (!get_metadata(message, &title, &artist, &album, &length))
1069 		return -EINVAL;
1070 
1071 	rc = cras_bt_player_update_metadata(conn, title, artist, album, length);
1072 	if (rc) {
1073 		syslog(LOG_WARNING, "CRAS failed to update BT Metadata: %d",
1074 		       rc);
1075 	}
1076 
1077 	send_empty_reply(conn, message);
1078 
1079 	return DBUS_HANDLER_RESULT_HANDLED;
1080 }
1081 
1082 /* Handle incoming messages. */
handle_control_message(DBusConnection * conn,DBusMessage * message,void * arg)1083 static DBusHandlerResult handle_control_message(DBusConnection *conn,
1084 						DBusMessage *message, void *arg)
1085 {
1086 	syslog(LOG_DEBUG, "Control message: %s %s %s",
1087 	       dbus_message_get_path(message),
1088 	       dbus_message_get_interface(message),
1089 	       dbus_message_get_member(message));
1090 
1091 	if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE,
1092 					"Introspect")) {
1093 		DBusMessage *reply;
1094 		const char *xml = CONTROL_INTROSPECT_XML;
1095 
1096 		reply = dbus_message_new_method_return(message);
1097 		if (!reply)
1098 			return DBUS_HANDLER_RESULT_NEED_MEMORY;
1099 		if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &xml,
1100 					      DBUS_TYPE_INVALID))
1101 			return DBUS_HANDLER_RESULT_NEED_MEMORY;
1102 		if (!dbus_connection_send(conn, reply, NULL))
1103 			return DBUS_HANDLER_RESULT_NEED_MEMORY;
1104 
1105 		dbus_message_unref(reply);
1106 		return DBUS_HANDLER_RESULT_HANDLED;
1107 
1108 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1109 					       "SetOutputVolume")) {
1110 		return handle_set_output_volume(conn, message, arg);
1111 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1112 					       "SetOutputNodeVolume")) {
1113 		return handle_set_output_node_volume(conn, message, arg);
1114 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1115 					       "SwapLeftRight")) {
1116 		return handle_swap_left_right(conn, message, arg);
1117 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1118 					       "SetOutputMute")) {
1119 		return handle_set_output_mute(conn, message, arg);
1120 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1121 					       "SetOutputUserMute")) {
1122 		return handle_set_output_user_mute(conn, message, arg);
1123 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1124 					       "SetSuspendAudio")) {
1125 		return handle_set_suspend_audio(conn, message, arg);
1126 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1127 					       "SetInputNodeGain")) {
1128 		return handle_set_input_node_gain(conn, message, arg);
1129 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1130 					       "SetInputMute")) {
1131 		return handle_set_input_mute(conn, message, arg);
1132 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1133 					       "GetVolumeState")) {
1134 		return handle_get_volume_state(conn, message, arg);
1135 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1136 					       "GetDefaultOutputBufferSize")) {
1137 		return handle_get_default_output_buffer_size(conn, message,
1138 							     arg);
1139 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1140 					       "GetNodes")) {
1141 		return handle_get_nodes(conn, message, arg);
1142 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1143 					       "GetSystemAecSupported")) {
1144 		return handle_get_system_aec_supported(conn, message, arg);
1145 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1146 					       "GetSystemAecGroupId")) {
1147 		return handle_get_system_aec_group_id(conn, message, arg);
1148 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1149 					       "GetDeprioritizeBtWbsMic")) {
1150 		return handle_get_deprioritize_bt_wbs_mic(conn, message, arg);
1151 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1152 					       "SetActiveOutputNode")) {
1153 		return handle_set_active_node(conn, message, arg,
1154 					      CRAS_STREAM_OUTPUT);
1155 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1156 					       "SetActiveInputNode")) {
1157 		return handle_set_active_node(conn, message, arg,
1158 					      CRAS_STREAM_INPUT);
1159 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1160 					       "AddActiveInputNode")) {
1161 		return handle_add_active_node(conn, message, arg,
1162 					      CRAS_STREAM_INPUT);
1163 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1164 					       "AddActiveOutputNode")) {
1165 		return handle_add_active_node(conn, message, arg,
1166 					      CRAS_STREAM_OUTPUT);
1167 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1168 					       "RemoveActiveInputNode")) {
1169 		return handle_rm_active_node(conn, message, arg,
1170 					     CRAS_STREAM_INPUT);
1171 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1172 					       "RemoveActiveOutputNode")) {
1173 		return handle_rm_active_node(conn, message, arg,
1174 					     CRAS_STREAM_OUTPUT);
1175 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1176 					       "SetFixA2dpPacketSize")) {
1177 		return handle_set_fix_a2dp_packet_size(conn, message, arg);
1178 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1179 					       "GetNumberOfActiveStreams")) {
1180 		return handle_get_num_active_streams(conn, message, arg);
1181 	} else if (dbus_message_is_method_call(
1182 			   message, CRAS_CONTROL_INTERFACE,
1183 			   "GetNumberOfActiveInputStreams")) {
1184 		return handle_get_num_active_streams_use_input_hw(conn, message,
1185 								  arg);
1186 	} else if (dbus_message_is_method_call(
1187 			   message, CRAS_CONTROL_INTERFACE,
1188 			   "GetNumberOfInputStreamsWithPermission")) {
1189 		return handle_get_num_input_streams_with_permission(
1190 			conn, message, arg);
1191 	} else if (dbus_message_is_method_call(
1192 			   message, CRAS_CONTROL_INTERFACE,
1193 			   "GetNumberOfActiveOutputStreams")) {
1194 		return handle_get_num_active_streams_use_output_hw(
1195 			conn, message, arg);
1196 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1197 					       "SetGlobalOutputChannelRemix")) {
1198 		return handle_set_global_output_channel_remix(conn, message,
1199 							      arg);
1200 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1201 					       "SetHotwordModel")) {
1202 		return handle_set_hotword_model(conn, message, arg);
1203 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1204 					       "IsAudioOutputActive")) {
1205 		return handle_is_audio_active(conn, message, arg);
1206 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1207 					       "SetWbsEnabled")) {
1208 		return handle_set_wbs_enabled(conn, message, arg);
1209 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1210 					       "SetNoiseCancellationEnabled")) {
1211 		return handle_set_noise_cancellation_enabled(conn, message,
1212 							     arg);
1213 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1214 					       "SetPlayerPlaybackStatus")) {
1215 		return handle_set_player_playback_status(conn, message, arg);
1216 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1217 					       "SetPlayerIdentity")) {
1218 		return handle_set_player_identity(conn, message, arg);
1219 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1220 					       "SetPlayerPosition")) {
1221 		return handle_set_player_position(conn, message, arg);
1222 	} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
1223 					       "SetPlayerMetadata")) {
1224 		return handle_set_player_metadata(conn, message, arg);
1225 	}
1226 
1227 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1228 }
1229 
1230 /* Creates a new DBus message, must be freed with dbus_message_unref. */
create_dbus_message(const char * name)1231 static DBusMessage *create_dbus_message(const char *name)
1232 {
1233 	DBusMessage *msg;
1234 	msg = dbus_message_new_signal(CRAS_ROOT_OBJECT_PATH,
1235 				      CRAS_CONTROL_INTERFACE, name);
1236 	if (!msg)
1237 		syslog(LOG_ERR, "Failed to create signal");
1238 
1239 	return msg;
1240 }
1241 
1242 /* Handlers for system updates that generate DBus signals. */
1243 
signal_output_volume(void * context,int32_t volume)1244 static void signal_output_volume(void *context, int32_t volume)
1245 {
1246 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1247 	dbus_uint32_t serial = 0;
1248 	DBusMessage *msg;
1249 
1250 	msg = create_dbus_message("OutputVolumeChanged");
1251 	if (!msg)
1252 		return;
1253 
1254 	volume = cras_system_get_volume();
1255 	dbus_message_append_args(msg, DBUS_TYPE_INT32, &volume,
1256 				 DBUS_TYPE_INVALID);
1257 	dbus_connection_send(control->conn, msg, &serial);
1258 	dbus_message_unref(msg);
1259 }
1260 
signal_output_mute(void * context,int muted,int user_muted,int mute_locked)1261 static void signal_output_mute(void *context, int muted, int user_muted,
1262 			       int mute_locked)
1263 {
1264 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1265 	dbus_uint32_t serial = 0;
1266 	DBusMessage *msg;
1267 
1268 	msg = create_dbus_message("OutputMuteChanged");
1269 	if (!msg)
1270 		return;
1271 
1272 	muted = cras_system_get_system_mute();
1273 	user_muted = cras_system_get_user_mute();
1274 	dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &muted,
1275 				 DBUS_TYPE_BOOLEAN, &user_muted,
1276 				 DBUS_TYPE_INVALID);
1277 	dbus_connection_send(control->conn, msg, &serial);
1278 	dbus_message_unref(msg);
1279 }
1280 
signal_capture_gain(void * context,int32_t gain)1281 static void signal_capture_gain(void *context, int32_t gain)
1282 {
1283 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1284 	dbus_uint32_t serial = 0;
1285 	DBusMessage *msg;
1286 
1287 	msg = create_dbus_message("InputGainChanged");
1288 	if (!msg)
1289 		return;
1290 
1291 	dbus_message_append_args(msg, DBUS_TYPE_INT32, &gain,
1292 				 DBUS_TYPE_INVALID);
1293 	dbus_connection_send(control->conn, msg, &serial);
1294 	dbus_message_unref(msg);
1295 }
1296 
signal_capture_mute(void * context,int muted,int mute_locked)1297 static void signal_capture_mute(void *context, int muted, int mute_locked)
1298 {
1299 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1300 	dbus_uint32_t serial = 0;
1301 	DBusMessage *msg;
1302 
1303 	msg = create_dbus_message("InputMuteChanged");
1304 	if (!msg)
1305 		return;
1306 
1307 	dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &muted,
1308 				 DBUS_TYPE_INVALID);
1309 	dbus_connection_send(control->conn, msg, &serial);
1310 	dbus_message_unref(msg);
1311 }
1312 
signal_nodes_changed(void * context)1313 static void signal_nodes_changed(void *context)
1314 {
1315 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1316 	dbus_uint32_t serial = 0;
1317 	DBusMessage *msg;
1318 
1319 	msg = create_dbus_message("NodesChanged");
1320 	if (!msg)
1321 		return;
1322 
1323 	dbus_connection_send(control->conn, msg, &serial);
1324 	dbus_message_unref(msg);
1325 }
1326 
signal_active_node_changed(void * context,enum CRAS_STREAM_DIRECTION dir,cras_node_id_t node_id)1327 static void signal_active_node_changed(void *context,
1328 				       enum CRAS_STREAM_DIRECTION dir,
1329 				       cras_node_id_t node_id)
1330 {
1331 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1332 	DBusMessage *msg;
1333 	dbus_uint32_t serial = 0;
1334 
1335 	msg = create_dbus_message((dir == CRAS_STREAM_OUTPUT) ?
1336 						"ActiveOutputNodeChanged" :
1337 						"ActiveInputNodeChanged");
1338 	if (!msg)
1339 		return;
1340 	dbus_message_append_args(msg, DBUS_TYPE_UINT64, &node_id,
1341 				 DBUS_TYPE_INVALID);
1342 	dbus_connection_send(control->conn, msg, &serial);
1343 	dbus_message_unref(msg);
1344 }
1345 
1346 /* Called by iodev_list when a node volume changes. */
signal_node_volume_changed(void * context,cras_node_id_t node_id,int32_t volume)1347 static void signal_node_volume_changed(void *context, cras_node_id_t node_id,
1348 				       int32_t volume)
1349 {
1350 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1351 	dbus_uint32_t serial = 0;
1352 	DBusMessage *msg;
1353 
1354 	msg = create_dbus_message("OutputNodeVolumeChanged");
1355 	if (!msg)
1356 		return;
1357 
1358 	dbus_message_append_args(msg, DBUS_TYPE_UINT64, &node_id,
1359 				 DBUS_TYPE_INT32, &volume, DBUS_TYPE_INVALID);
1360 	dbus_connection_send(control->conn, msg, &serial);
1361 	dbus_message_unref(msg);
1362 }
1363 
signal_node_capture_gain_changed(void * context,cras_node_id_t node_id,int capture_gain)1364 static void signal_node_capture_gain_changed(void *context,
1365 					     cras_node_id_t node_id,
1366 					     int capture_gain)
1367 {
1368 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1369 	dbus_uint32_t serial = 0;
1370 	DBusMessage *msg;
1371 
1372 	msg = create_dbus_message("InputNodeGainChanged");
1373 	if (!msg)
1374 		return;
1375 
1376 	dbus_message_append_args(msg, DBUS_TYPE_UINT64, &node_id,
1377 				 DBUS_TYPE_INT32, &capture_gain,
1378 				 DBUS_TYPE_INVALID);
1379 	dbus_connection_send(control->conn, msg, &serial);
1380 	dbus_message_unref(msg);
1381 }
1382 
signal_node_left_right_swapped_changed(void * context,cras_node_id_t node_id,int swapped)1383 static void signal_node_left_right_swapped_changed(void *context,
1384 						   cras_node_id_t node_id,
1385 						   int swapped)
1386 {
1387 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1388 	dbus_uint32_t serial = 0;
1389 	DBusMessage *msg;
1390 
1391 	msg = create_dbus_message("NodeLeftRightSwappedChanged");
1392 	if (!msg)
1393 		return;
1394 
1395 	dbus_message_append_args(msg, DBUS_TYPE_UINT64, &node_id,
1396 				 DBUS_TYPE_BOOLEAN, &swapped,
1397 				 DBUS_TYPE_INVALID);
1398 	dbus_connection_send(control->conn, msg, &serial);
1399 	dbus_message_unref(msg);
1400 }
1401 
signal_num_active_streams_changed(void * context,enum CRAS_STREAM_DIRECTION dir,uint32_t num_active_streams)1402 static void signal_num_active_streams_changed(void *context,
1403 					      enum CRAS_STREAM_DIRECTION dir,
1404 					      uint32_t num_active_streams)
1405 {
1406 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1407 	dbus_uint32_t serial = 0;
1408 	DBusMessage *msg;
1409 	dbus_int32_t num;
1410 
1411 	msg = create_dbus_message("NumberOfActiveStreamsChanged");
1412 	if (!msg)
1413 		return;
1414 
1415 	num = cras_system_state_get_active_streams();
1416 	dbus_message_append_args(msg, DBUS_TYPE_INT32, &num, DBUS_TYPE_INVALID);
1417 	dbus_connection_send(control->conn, msg, &serial);
1418 	dbus_message_unref(msg);
1419 }
1420 
signal_num_input_streams_with_permission_changed(void * context,uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])1421 static void signal_num_input_streams_with_permission_changed(
1422 	void *context, uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
1423 {
1424 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1425 	dbus_uint32_t serial = 0;
1426 	DBusMessage *msg;
1427 
1428 	msg = create_dbus_message("NumberOfInputStreamsWithPermissionChanged");
1429 	if (!msg)
1430 		return;
1431 
1432 	if (!append_num_input_streams_with_permission(msg, num_input_streams))
1433 		goto error;
1434 
1435 	dbus_connection_send(control->conn, msg, &serial);
1436 error:
1437 	dbus_message_unref(msg);
1438 }
1439 
signal_hotword_triggered(void * context,int64_t tv_sec,int64_t tv_nsec)1440 static void signal_hotword_triggered(void *context, int64_t tv_sec,
1441 				     int64_t tv_nsec)
1442 {
1443 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1444 	dbus_uint32_t serial = 0;
1445 	DBusMessage *msg;
1446 
1447 	msg = create_dbus_message("HotwordTriggered");
1448 	if (!msg)
1449 		return;
1450 
1451 	dbus_message_append_args(msg, DBUS_TYPE_INT64, &tv_sec, DBUS_TYPE_INT64,
1452 				 &tv_nsec, DBUS_TYPE_INVALID);
1453 	dbus_connection_send(control->conn, msg, &serial);
1454 	dbus_message_unref(msg);
1455 }
1456 
signal_non_empty_audio_state_changed(void * context,int non_empty)1457 static void signal_non_empty_audio_state_changed(void *context, int non_empty)
1458 {
1459 	struct cras_dbus_control *control = (struct cras_dbus_control *)context;
1460 
1461 	dbus_uint32_t serial = 0;
1462 	DBusMessage *msg;
1463 
1464 	msg = create_dbus_message("AudioOutputActiveStateChanged");
1465 	if (!msg)
1466 		return;
1467 
1468 	dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &non_empty,
1469 				 DBUS_TYPE_INVALID);
1470 
1471 	dbus_connection_send(control->conn, msg, &serial);
1472 	dbus_message_unref(msg);
1473 }
1474 
1475 /* Exported Interface */
1476 
cras_dbus_control_start(DBusConnection * conn)1477 void cras_dbus_control_start(DBusConnection *conn)
1478 {
1479 	static const DBusObjectPathVTable control_vtable = {
1480 		.message_function = handle_control_message,
1481 	};
1482 
1483 	DBusError dbus_error;
1484 	struct cras_observer_ops observer_ops;
1485 
1486 	dbus_control.conn = conn;
1487 	dbus_connection_ref(dbus_control.conn);
1488 
1489 	if (!dbus_connection_register_object_path(conn, CRAS_ROOT_OBJECT_PATH,
1490 						  &control_vtable,
1491 						  &dbus_error)) {
1492 		syslog(LOG_WARNING, "Couldn't register CRAS control: %s: %s",
1493 		       CRAS_ROOT_OBJECT_PATH, dbus_error.message);
1494 		dbus_error_free(&dbus_error);
1495 		return;
1496 	}
1497 
1498 	memset(&observer_ops, 0, sizeof(observer_ops));
1499 	observer_ops.output_volume_changed = signal_output_volume;
1500 	observer_ops.output_mute_changed = signal_output_mute;
1501 	observer_ops.capture_gain_changed = signal_capture_gain;
1502 	observer_ops.capture_mute_changed = signal_capture_mute;
1503 	observer_ops.num_active_streams_changed =
1504 		signal_num_active_streams_changed;
1505 	observer_ops.num_input_streams_with_permission_changed =
1506 		signal_num_input_streams_with_permission_changed;
1507 	observer_ops.nodes_changed = signal_nodes_changed;
1508 	observer_ops.active_node_changed = signal_active_node_changed;
1509 	observer_ops.input_node_gain_changed = signal_node_capture_gain_changed;
1510 	observer_ops.output_node_volume_changed = signal_node_volume_changed;
1511 	observer_ops.node_left_right_swapped_changed =
1512 		signal_node_left_right_swapped_changed;
1513 	observer_ops.hotword_triggered = signal_hotword_triggered;
1514 	observer_ops.non_empty_audio_state_changed =
1515 		signal_non_empty_audio_state_changed;
1516 
1517 	dbus_control.observer = cras_observer_add(&observer_ops, &dbus_control);
1518 }
1519 
cras_dbus_control_stop()1520 void cras_dbus_control_stop()
1521 {
1522 	if (!dbus_control.conn)
1523 		return;
1524 
1525 	dbus_connection_unregister_object_path(dbus_control.conn,
1526 					       CRAS_ROOT_OBJECT_PATH);
1527 
1528 	dbus_connection_unref(dbus_control.conn);
1529 	dbus_control.conn = NULL;
1530 	cras_observer_remove(dbus_control.observer);
1531 	dbus_control.observer = NULL;
1532 }
1533