summaryrefslogtreecommitdiff
path: root/cras
diff options
context:
space:
mode:
authorJohn Muir <muirj@google.com>2016-05-28 21:53:41 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-06-17 12:40:17 -0700
commit191f157af103edf5d58a5b259c35e2fb246f491e (patch)
treeb122b36443674f91c3a9743fed42ee9c84128e3b /cras
parentee4e108ef76b42691f22ab5821d848bc01599599 (diff)
downloadadhd-191f157af103edf5d58a5b259c35e2fb246f491e.tar.gz
CRAS: Add client-side notification registration and monitor.
Implement the client-side for notifications and a monitor program for functional testing. BUG=None TEST=Testing using the monitor program. Change-Id: Ied2c201679ae8921301c3cbb0655d3ad9bb145e4 Reviewed-on: https://chromium-review.googlesource.com/348656 Commit-Ready: John Muir <muirj@google.com> Tested-by: John Muir <muirj@google.com> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'cras')
-rw-r--r--cras/src/Makefile.am9
-rw-r--r--cras/src/libcras/cras_client.c230
-rw-r--r--cras/src/libcras/cras_client.h153
-rw-r--r--cras/src/tests/cras_monitor.c231
4 files changed, 622 insertions, 1 deletions
diff --git a/cras/src/Makefile.am b/cras/src/Makefile.am
index 5ecff8fe..09d6da28 100644
--- a/cras/src/Makefile.am
+++ b/cras/src/Makefile.am
@@ -32,7 +32,7 @@ endif
COMMON_CPPFLAGS = -O2 -Wall -Werror -Wno-error=cpp
COMMON_SIMD_CPPFLAGS = -O3 -Wall -Werror -Wno-error=cpp
-bin_PROGRAMS = cras cras_test_client
+bin_PROGRAMS = cras cras_test_client cras_monitor
if HAVE_DBUS
CRAS_DBUS_SOURCES = \
@@ -316,6 +316,13 @@ cras_test_client_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/src/libcras \
tests/cras_test_client.c: common/cras_version.h
+cras_monitor_SOURCES = tests/cras_monitor.c
+cras_monitor_LDADD = -lm libcras.la
+cras_monitor_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/src/libcras \
+ -I$(top_srcdir)/src/common -I$(top_builddir)/src/common
+
+tests/cras_monitor.c: common/cras_version.h
+
CLEANFILES = common/cras_version.h
.PHONY: common/cras_version.h
common/cras_version.h:
diff --git a/cras/src/libcras/cras_client.c b/cras/src/libcras/cras_client.c
index 1b6e70a1..08a08139 100644
--- a/cras/src/libcras/cras_client.c
+++ b/cras/src/libcras/cras_client.c
@@ -44,6 +44,7 @@
#include "cras_client.h"
#include "cras_config.h"
#include "cras_messages.h"
+#include "cras_observer_ops.h"
#include "cras_shm.h"
#include "cras_types.h"
#include "cras_util.h"
@@ -169,6 +170,8 @@ struct client_stream {
* server_err_cb - Function to call when failed to read messages from server.
* server_err_user_arg - User argument for server_err_cb.
* thread_priority_cb - Function to call for setting audio thread priority.
+ * observer_ops - Functions to call when system state changes.
+ * observer_context - Context passed to client in state change callbacks.
*/
struct cras_client {
int id;
@@ -187,6 +190,8 @@ struct cras_client {
cras_server_error_cb_t server_err_cb;
void *server_err_user_arg;
cras_thread_priority_cb_t thread_priority_cb;
+ struct cras_observer_ops observer_ops;
+ void *observer_context;
};
/*
@@ -1001,6 +1006,103 @@ static int handle_message_from_server(struct cras_client *client)
(const char *)cmsg->hotword_models);
break;
}
+ case CRAS_CLIENT_OUTPUT_VOLUME_CHANGED: {
+ struct cras_client_volume_changed *cmsg =
+ (struct cras_client_volume_changed *)msg;
+ if (client->observer_ops.output_volume_changed)
+ client->observer_ops.output_volume_changed(
+ client->observer_context,
+ cmsg->volume);
+ break;
+ }
+ case CRAS_CLIENT_OUTPUT_MUTE_CHANGED: {
+ struct cras_client_mute_changed *cmsg =
+ (struct cras_client_mute_changed *)msg;
+ if (client->observer_ops.output_mute_changed)
+ client->observer_ops.output_mute_changed(
+ client->observer_context,
+ cmsg->muted,
+ cmsg->user_muted,
+ cmsg->mute_locked);
+ break;
+ }
+ case CRAS_CLIENT_CAPTURE_GAIN_CHANGED: {
+ struct cras_client_volume_changed *cmsg =
+ (struct cras_client_volume_changed *)msg;
+ if (client->observer_ops.capture_gain_changed)
+ client->observer_ops.capture_gain_changed(
+ client->observer_context,
+ cmsg->volume);
+ break;
+ }
+ case CRAS_CLIENT_CAPTURE_MUTE_CHANGED: {
+ struct cras_client_mute_changed *cmsg =
+ (struct cras_client_mute_changed *)msg;
+ if (client->observer_ops.capture_mute_changed)
+ client->observer_ops.capture_mute_changed(
+ client->observer_context,
+ cmsg->muted,
+ cmsg->mute_locked);
+ break;
+ }
+ case CRAS_CLIENT_NODES_CHANGED: {
+ if (client->observer_ops.nodes_changed)
+ client->observer_ops.nodes_changed(
+ client->observer_context);
+ break;
+ }
+ case CRAS_CLIENT_ACTIVE_NODE_CHANGED: {
+ struct cras_client_active_node_changed *cmsg =
+ (struct cras_client_active_node_changed *)msg;
+ enum CRAS_STREAM_DIRECTION direction =
+ (enum CRAS_STREAM_DIRECTION)cmsg->direction;
+ if (client->observer_ops.active_node_changed)
+ client->observer_ops.active_node_changed(
+ client->observer_context,
+ direction, cmsg->node_id);
+ break;
+ }
+ case CRAS_CLIENT_OUTPUT_NODE_VOLUME_CHANGED: {
+ struct cras_client_node_value_changed *cmsg =
+ (struct cras_client_node_value_changed *)msg;
+ if (client->observer_ops.output_node_volume_changed)
+ client->observer_ops.output_node_volume_changed(
+ client->observer_context,
+ cmsg->node_id,
+ cmsg->value);
+ break;
+ }
+ case CRAS_CLIENT_NODE_LEFT_RIGHT_SWAPPED_CHANGED: {
+ struct cras_client_node_value_changed *cmsg =
+ (struct cras_client_node_value_changed *)msg;
+ if (client->observer_ops.node_left_right_swapped_changed)
+ client->observer_ops.node_left_right_swapped_changed(
+ client->observer_context,
+ cmsg->node_id,
+ cmsg->value);
+ break;
+ }
+ case CRAS_CLIENT_INPUT_NODE_GAIN_CHANGED: {
+ struct cras_client_node_value_changed *cmsg =
+ (struct cras_client_node_value_changed *)msg;
+ if (client->observer_ops.input_node_gain_changed)
+ client->observer_ops.input_node_gain_changed(
+ client->observer_context,
+ cmsg->node_id,
+ cmsg->value);
+ break;
+ }
+ case CRAS_CLIENT_NUM_ACTIVE_STREAMS_CHANGED: {
+ struct cras_client_num_active_streams_changed *cmsg =
+ (struct cras_client_num_active_streams_changed *)msg;
+ enum CRAS_STREAM_DIRECTION direction =
+ (enum CRAS_STREAM_DIRECTION)cmsg->direction;
+ if (client->observer_ops.num_active_streams_changed)
+ client->observer_ops.num_active_streams_changed(
+ client->observer_context,
+ direction, cmsg->num_active_streams);
+ break;
+ }
default:
break;
}
@@ -2217,3 +2319,131 @@ int cras_client_set_hotword_model(struct cras_client *client,
cras_fill_set_hotword_model_message(&msg, node_id, model_name);
return write_message_to_server(client, &msg.header);
}
+
+void cras_client_set_state_change_callback_context(
+ struct cras_client *client, void *context)
+{
+ if (!client)
+ return;
+ client->observer_context = context;
+}
+
+static int cras_send_register_notification(struct cras_client *client,
+ enum CRAS_CLIENT_MESSAGE_ID msg_id,
+ int do_register)
+{
+ struct cras_register_notification msg;
+
+ cras_fill_register_notification_message(&msg, msg_id, do_register);
+ return cras_send_with_fds(client->server_fd, &msg, sizeof(msg), NULL, 0);
+}
+
+int cras_client_set_output_volume_changed_callback(
+ struct cras_client *client,
+ cras_client_output_volume_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.output_volume_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_OUTPUT_VOLUME_CHANGED, cb != NULL);
+}
+
+int cras_client_set_output_mute_changed_callback(
+ struct cras_client *client,
+ cras_client_output_mute_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.output_mute_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_OUTPUT_MUTE_CHANGED, cb != NULL);
+}
+
+int cras_client_set_capture_gain_changed_callback(
+ struct cras_client *client,
+ cras_client_capture_gain_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.capture_gain_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_CAPTURE_GAIN_CHANGED, cb != NULL);
+}
+
+int cras_client_set_capture_mute_changed_callback(
+ struct cras_client *client,
+ cras_client_capture_mute_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.capture_mute_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_CAPTURE_MUTE_CHANGED, cb != NULL);
+}
+
+int cras_client_set_nodes_changed_callback(
+ struct cras_client *client,
+ cras_client_nodes_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.nodes_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_NODES_CHANGED, cb != NULL);
+}
+
+int cras_client_set_active_node_changed_callback(
+ struct cras_client *client,
+ cras_client_active_node_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.active_node_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_ACTIVE_NODE_CHANGED, cb != NULL);
+}
+
+int cras_client_set_output_node_volume_changed_callback(
+ struct cras_client *client,
+ cras_client_output_node_volume_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.output_node_volume_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_OUTPUT_NODE_VOLUME_CHANGED, cb != NULL);
+}
+
+int cras_client_set_node_left_right_swapped_changed_callback(
+ struct cras_client *client,
+ cras_client_node_left_right_swapped_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.node_left_right_swapped_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_NODE_LEFT_RIGHT_SWAPPED_CHANGED, cb != NULL);
+}
+
+int cras_client_set_input_node_gain_changed_callback(
+ struct cras_client *client,
+ cras_client_input_node_gain_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.input_node_gain_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_INPUT_NODE_GAIN_CHANGED, cb != NULL);
+}
+
+int cras_client_set_num_active_streams_changed_callback(
+ struct cras_client *client,
+ cras_client_num_active_streams_changed_callback cb)
+{
+ if (!client)
+ return -EINVAL;
+ client->observer_ops.num_active_streams_changed = cb;
+ return cras_send_register_notification(
+ client, CRAS_CLIENT_NUM_ACTIVE_STREAMS_CHANGED, cb != NULL);
+}
diff --git a/cras/src/libcras/cras_client.h b/cras/src/libcras/cras_client.h
index cae4690a..75ee5bbd 100644
--- a/cras/src/libcras/cras_client.h
+++ b/cras/src/libcras/cras_client.h
@@ -747,6 +747,159 @@ int cras_client_set_hotword_model(struct cras_client *client,
cras_node_id_t node_id,
const char *model_name);
+/* Set the context pointer for system state change callbacks.
+ * Args:
+ * client - The client from cras_client_create.
+ * context - The context pointer passed to all callbacks.
+ */
+void cras_client_set_state_change_callback_context(
+ struct cras_client *client, void *context);
+
+/* Output volume change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * volume - The system output volume, ranging from 0 to 100.
+ */
+typedef void (*cras_client_output_volume_changed_callback)(
+ void* context, int32_t volume);
+
+/* Output mute change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * muted - Non-zero when the audio is muted, zero otherwise.
+ * user_muted - Non-zero when the audio has been muted by the
+ * user, zero otherwise.
+ * mute_locked - Non-zero when the mute funcion is locked,
+ * zero otherwise.
+ */
+typedef void (*cras_client_output_mute_changed_callback)(
+ void* context, int muted, int user_muted, int mute_locked);
+
+/* Capture gain change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * gain - The system capture gain, in centi-decibels.
+ */
+typedef void (*cras_client_capture_gain_changed_callback)(
+ void* context, int32_t gain);
+
+/* Capture mute change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * muted - Non-zero when the audio is muted, zero otherwise.
+ * mute_locked - Non-zero when the mute funcion is locked,
+ * zero otherwise.
+ */
+typedef void (*cras_client_capture_mute_changed_callback)(
+ void* context, int muted, int mute_locked);
+
+/* Nodes change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ */
+typedef void (*cras_client_nodes_changed_callback)(void* context);
+
+/* Active node change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * direction - Indicates the direction of the selected node.
+ * node_id - The ID of the selected node. Special device ID values
+ * defined by CRAS_SPECIAL_DEVICE will be used when no other
+ * device or node is selected or between selections.
+ */
+typedef void (*cras_client_active_node_changed_callback)(
+ void* context, enum CRAS_STREAM_DIRECTION direction,
+ cras_node_id_t node_id);
+
+/* Output node volume change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * node_id - The ID of the output node.
+ * volume - The volume for this node with range 0 to 100.
+ */
+typedef void (*cras_client_output_node_volume_changed_callback)(
+ void* context, cras_node_id_t node_id, int32_t volume);
+
+/* Node left right swapped change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * node_id - The ID of the node.
+ * swapped - Non-zero if the node is left-right swapped, zero otherwise.
+ */
+typedef void (*cras_client_node_left_right_swapped_changed_callback)(
+ void* context, cras_node_id_t node_id, int swapped);
+
+/* Input node gain change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * node_id - The ID of the input node.
+ * gain - The gain for this node in centi-decibels.
+ */
+typedef void (*cras_client_input_node_gain_changed_callback)(
+ void* context, cras_node_id_t node_id, int32_t gain);
+
+/* Number of active streams change callback.
+ * Args:
+ * context - Context pointer set with
+ * cras_client_set_state_change_callback_context().
+ * direction - Indicates the direction of the stream's node.
+ * num_active_streams - The number of active streams.
+ */
+typedef void (*cras_client_num_active_streams_changed_callback)(
+ void* context, enum CRAS_STREAM_DIRECTION direction,
+ uint32_t num_active_streams);
+
+/* Set system state information callbacks.
+ * NOTE: These callbacks are executed from the client control thread.
+ * Each state change callback is given the context pointer set with
+ * cras_client_set_state_change_callback_context(). The context pointer is
+ * NULL by default.
+ * Args:
+ * client - The client from cras_client_create.
+ * cb - The callback, or NULL to disable the call-back.
+ * Returns:
+ * 0 for success or negative errno error code on error.
+ */
+int cras_client_set_output_volume_changed_callback(
+ struct cras_client *client,
+ cras_client_output_volume_changed_callback cb);
+int cras_client_set_output_mute_changed_callback(
+ struct cras_client *client,
+ cras_client_output_mute_changed_callback cb);
+int cras_client_set_capture_gain_changed_callback(
+ struct cras_client *client,
+ cras_client_capture_gain_changed_callback cb);
+int cras_client_set_capture_mute_changed_callback(
+ struct cras_client *client,
+ cras_client_capture_mute_changed_callback cb);
+int cras_client_set_nodes_changed_callback(
+ struct cras_client *client,
+ cras_client_nodes_changed_callback cb);
+int cras_client_set_active_node_changed_callback(
+ struct cras_client *client,
+ cras_client_active_node_changed_callback cb);
+int cras_client_set_output_node_volume_changed_callback(
+ struct cras_client *client,
+ cras_client_output_node_volume_changed_callback cb);
+int cras_client_set_node_left_right_swapped_changed_callback(
+ struct cras_client *client,
+ cras_client_node_left_right_swapped_changed_callback cb);
+int cras_client_set_input_node_gain_changed_callback(
+ struct cras_client *client,
+ cras_client_input_node_gain_changed_callback cb);
+int cras_client_set_num_active_streams_changed_callback(
+ struct cras_client *client,
+ cras_client_num_active_streams_changed_callback cb);
+
#ifdef __cplusplus
}
#endif
diff --git a/cras/src/tests/cras_monitor.c b/cras/src/tests/cras_monitor.c
new file mode 100644
index 00000000..2bb1fed7
--- /dev/null
+++ b/cras/src/tests/cras_monitor.c
@@ -0,0 +1,231 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include "cras_client.h"
+#include "cras_types.h"
+#include "cras_util.h"
+#include "cras_version.h"
+
+static void output_volume_changed(void *context, int32_t volume)
+{
+ printf("output volume: %d/100\n", volume);
+}
+
+static void output_mute_changed(void *context, int muted,
+ int user_muted, int mute_locked)
+{
+ printf("output mute: muted: %d, user_muted: %d, mute_locked: %d\n",
+ muted, user_muted, mute_locked);
+}
+
+static void capture_gain_changed(void *context, int32_t gain)
+{
+ printf("capture gain: %d\n", gain);
+}
+
+static void capture_mute_changed(void *context, int muted, int mute_locked)
+{
+ printf("capture mute: muted: %d, mute_locked: %d\n",
+ muted, mute_locked);
+}
+
+static void nodes_changed(void *context)
+{
+ printf("nodes changed\n");
+}
+
+static const char *string_for_direction(enum CRAS_STREAM_DIRECTION dir)
+{
+ switch(dir) {
+ case CRAS_STREAM_OUTPUT:
+ return "output";
+ case CRAS_STREAM_INPUT:
+ return "input";
+ case CRAS_STREAM_POST_MIX_PRE_DSP:
+ return "post_mix_pre_dsp";
+ default:
+ break;
+ }
+
+ return "undefined";
+}
+
+size_t node_array_index_of_node_id(struct cras_ionode_info *nodes,
+ size_t num_nodes,
+ cras_node_id_t node_id)
+{
+ uint32_t dev_index = dev_index_of(node_id);
+ uint32_t node_index = node_index_of(node_id);
+ size_t i;
+
+ for (i = 0; i < num_nodes; i++) {
+ if (nodes[i].iodev_idx == dev_index &&
+ nodes[i].ionode_idx == node_index)
+ return i;
+ }
+ return CRAS_MAX_IONODES;
+}
+
+const char *node_name_for_node_id(struct cras_client *client,
+ enum CRAS_STREAM_DIRECTION dir,
+ cras_node_id_t node_id)
+{
+ struct cras_ionode_info nodes[CRAS_MAX_IONODES];
+ struct cras_iodev_info devs[CRAS_MAX_IODEVS];
+ size_t num_devs = CRAS_MAX_IODEVS;
+ size_t num_nodes = CRAS_MAX_IONODES;
+ uint32_t iodev_idx = dev_index_of(node_id);
+ size_t node_index;
+ char buf[1024];
+ int rc;
+
+ if (node_id == 0) {
+ return strdup("none");
+ } else if (iodev_idx <= 2) {
+ return strdup("fallback");
+ } else if (dir == CRAS_STREAM_POST_MIX_PRE_DSP) {
+ snprintf(buf, sizeof(buf), "%s node: %" PRIu64 "\n",
+ string_for_direction(dir), node_id);
+ return strdup(buf);
+ } else if (dir == CRAS_STREAM_OUTPUT) {
+ rc = cras_client_get_output_devices(client, devs, nodes,
+ &num_devs, &num_nodes);
+ } else if (dir == CRAS_STREAM_INPUT) {
+ rc = cras_client_get_input_devices(client, devs, nodes,
+ &num_devs, &num_nodes);
+ } else {
+ return strdup("unknown");
+ }
+
+ if (rc != 0) {
+ syslog(LOG_ERR, "Couldn't get output devices: %s\n",
+ strerror(-rc));
+ snprintf(buf, sizeof(buf), "%u:%u",
+ iodev_idx, node_index_of(node_id));
+ return strdup(buf);
+ }
+ node_index = node_array_index_of_node_id(nodes, num_nodes, node_id);
+ if (node_index >= num_nodes)
+ snprintf(buf, sizeof(buf),
+ "unknown: %zu >= %zu", node_index, num_nodes);
+ else
+ snprintf(buf, sizeof(buf), "%u:%u: %s",
+ nodes[node_index].iodev_idx,
+ nodes[node_index].ionode_idx,
+ nodes[node_index].name);
+ return strdup(buf);
+}
+
+static void active_node_changed(void *context,
+ enum CRAS_STREAM_DIRECTION dir,
+ cras_node_id_t node_id)
+{
+ struct cras_client *client = (struct cras_client *)context;
+ const char *node_name = node_name_for_node_id(client, dir, node_id);
+ printf("active node (%s): %s\n", string_for_direction(dir), node_name);
+ free((void *)node_name);
+}
+
+static void output_node_volume_changed(void *context,
+ cras_node_id_t node_id, int32_t volume)
+{
+ struct cras_client *client = (struct cras_client *)context;
+ const char *node_name =
+ node_name_for_node_id(client, CRAS_STREAM_OUTPUT, node_id);
+ printf("output node '%s' volume: %d\n", node_name, volume);
+ free((void *)node_name);
+}
+
+static void node_left_right_swapped_changed(void *context,
+ cras_node_id_t node_id, int swapped)
+{
+ struct cras_client *client = (struct cras_client *)context;
+ const char *node_name =
+ node_name_for_node_id(client, CRAS_STREAM_OUTPUT, node_id);
+ printf("output node '%s' left-right swapped: %d\n", node_name, swapped);
+ free((void *)node_name);
+}
+
+static void input_node_gain_changed(void *context,
+ cras_node_id_t node_id, int32_t gain)
+{
+ struct cras_client *client = (struct cras_client *)context;
+ const char *node_name =
+ node_name_for_node_id(client, CRAS_STREAM_INPUT, node_id);
+ printf("input node '%s' gain: %d\n", node_name, gain);
+ free((void *)node_name);
+}
+
+static void num_active_streams_changed(void *context,
+ enum CRAS_STREAM_DIRECTION dir,
+ uint32_t num_active_streams)
+{
+ printf("num active %s streams: %u\n",
+ string_for_direction(dir), num_active_streams);
+}
+
+
+int main(int argc, char **argv)
+{
+ struct cras_client *client;
+ int rc;
+ openlog("cras_monitor", LOG_PERROR, LOG_USER);
+
+ rc = cras_client_create(&client);
+ if (rc < 0) {
+ syslog(LOG_ERR, "Couldn't create client.\n");
+ return rc;
+ }
+
+ rc = cras_client_connect(client);
+ if (rc) {
+ syslog(LOG_ERR, "Couldn't connect to server.\n");
+ goto destroy_exit;
+ }
+
+ cras_client_set_output_volume_changed_callback(
+ client, output_volume_changed);
+ cras_client_set_output_mute_changed_callback(
+ client, output_mute_changed);
+ cras_client_set_capture_gain_changed_callback(
+ client, capture_gain_changed);
+ cras_client_set_capture_mute_changed_callback(
+ client, capture_mute_changed);
+ cras_client_set_nodes_changed_callback(
+ client, nodes_changed);
+ cras_client_set_active_node_changed_callback(
+ client, active_node_changed);
+ cras_client_set_output_node_volume_changed_callback(
+ client, output_node_volume_changed);
+ cras_client_set_node_left_right_swapped_changed_callback(
+ client, node_left_right_swapped_changed);
+ cras_client_set_input_node_gain_changed_callback(
+ client, input_node_gain_changed);
+ cras_client_set_num_active_streams_changed_callback(
+ client, num_active_streams_changed);
+ cras_client_set_state_change_callback_context(client, client);
+
+ cras_client_run_thread(client);
+ while(1) {
+ int rc;
+ char c;
+ rc = read(STDIN_FILENO, &c, 1);
+ if (rc < 0 || c == 'q')
+ return 0;
+ }
+
+destroy_exit:
+ cras_client_destroy(client);
+ return 0;
+}