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