diff options
author | John Muir <muirj@google.com> | 2016-05-28 21:53:41 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-06-17 12:40:17 -0700 |
commit | 191f157af103edf5d58a5b259c35e2fb246f491e (patch) | |
tree | b122b36443674f91c3a9743fed42ee9c84128e3b /cras | |
parent | ee4e108ef76b42691f22ab5821d848bc01599599 (diff) | |
download | adhd-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.am | 9 | ||||
-rw-r--r-- | cras/src/libcras/cras_client.c | 230 | ||||
-rw-r--r-- | cras/src/libcras/cras_client.h | 153 | ||||
-rw-r--r-- | cras/src/tests/cras_monitor.c | 231 |
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; +} |