• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2016 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 <errno.h>
7 #include <getopt.h>
8 #include <inttypes.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <syslog.h>
14 #include <sys/select.h>
15 #include <unistd.h>
16 
17 #include "cras_client.h"
18 #include "cras_types.h"
19 #include "cras_util.h"
20 #include "cras_version.h"
21 
output_volume_changed(void * context,int32_t volume)22 static void output_volume_changed(void *context, int32_t volume)
23 {
24 	printf("output volume: %d/100\n", volume);
25 }
26 
output_mute_changed(void * context,int muted,int user_muted,int mute_locked)27 static void output_mute_changed(void *context, int muted,
28 				int user_muted, int mute_locked)
29 {
30 	printf("output mute: muted: %d, user_muted: %d, mute_locked: %d\n",
31 	       muted, user_muted, mute_locked);
32 }
33 
capture_gain_changed(void * context,int32_t gain)34 static void capture_gain_changed(void *context, int32_t gain)
35 {
36 	printf("capture gain: %d\n", gain);
37 }
38 
capture_mute_changed(void * context,int muted,int mute_locked)39 static void capture_mute_changed(void *context, int muted, int mute_locked)
40 {
41 	printf("capture mute: muted: %d, mute_locked: %d\n",
42 	       muted, mute_locked);
43 }
44 
nodes_changed(void * context)45 static void nodes_changed(void *context)
46 {
47 	printf("nodes changed\n");
48 }
49 
string_for_direction(enum CRAS_STREAM_DIRECTION dir)50 static const char *string_for_direction(enum CRAS_STREAM_DIRECTION dir)
51 {
52 	switch(dir) {
53 		case CRAS_STREAM_OUTPUT:
54 			return "output";
55 		case CRAS_STREAM_INPUT:
56 			return "input";
57 		case CRAS_STREAM_POST_MIX_PRE_DSP:
58 			return "post_mix_pre_dsp";
59 		default:
60 			break;
61 	}
62 
63 	return "undefined";
64 }
65 
node_array_index_of_node_id(struct cras_ionode_info * nodes,size_t num_nodes,cras_node_id_t node_id)66 size_t node_array_index_of_node_id(struct cras_ionode_info *nodes,
67 				   size_t num_nodes,
68 				   cras_node_id_t node_id)
69 {
70 	uint32_t dev_index = dev_index_of(node_id);
71 	uint32_t node_index = node_index_of(node_id);
72 	size_t i;
73 
74 	for (i = 0; i < num_nodes; i++) {
75 		if (nodes[i].iodev_idx == dev_index &&
76 		    nodes[i].ionode_idx == node_index)
77 			return i;
78 	}
79 	return CRAS_MAX_IONODES;
80 }
81 
node_name_for_node_id(struct cras_client * client,enum CRAS_STREAM_DIRECTION dir,cras_node_id_t node_id)82 const char *node_name_for_node_id(struct cras_client *client,
83 				  enum CRAS_STREAM_DIRECTION dir,
84 				  cras_node_id_t node_id)
85 {
86 	struct cras_ionode_info nodes[CRAS_MAX_IONODES];
87 	struct cras_iodev_info devs[CRAS_MAX_IODEVS];
88 	size_t num_devs = CRAS_MAX_IODEVS;
89 	size_t num_nodes = CRAS_MAX_IONODES;
90 	uint32_t iodev_idx = dev_index_of(node_id);
91 	size_t node_index;
92 	char buf[1024];
93 	int rc;
94 
95 	if (node_id == 0) {
96 		return strdup("none");
97 	} else if (iodev_idx <= 2) {
98 		return strdup("fallback");
99 	} else if (dir == CRAS_STREAM_POST_MIX_PRE_DSP) {
100 		snprintf(buf, sizeof(buf), "%s node: %" PRIu64 "\n",
101 			 string_for_direction(dir), node_id);
102 		return strdup(buf);
103 	} else if (dir == CRAS_STREAM_OUTPUT) {
104 		rc = cras_client_get_output_devices(client, devs, nodes,
105 					       &num_devs, &num_nodes);
106 	} else if (dir == CRAS_STREAM_INPUT) {
107 		rc = cras_client_get_input_devices(client, devs, nodes,
108 					      &num_devs, &num_nodes);
109 	} else {
110 		return strdup("unknown");
111 	}
112 
113 	if (rc != 0) {
114 		syslog(LOG_ERR, "Couldn't get output devices: %s\n",
115 		       strerror(-rc));
116 		snprintf(buf, sizeof(buf), "%u:%u",
117 			 iodev_idx, node_index_of(node_id));
118 		return strdup(buf);
119 	}
120 	node_index = node_array_index_of_node_id(nodes, num_nodes, node_id);
121 	if (node_index >= num_nodes)
122 		snprintf(buf, sizeof(buf),
123 			 "unknown: %zu >= %zu", node_index, num_nodes);
124 	else
125 		snprintf(buf, sizeof(buf), "%u:%u: %s",
126 			 nodes[node_index].iodev_idx,
127 			 nodes[node_index].ionode_idx,
128 			 nodes[node_index].name);
129 	return strdup(buf);
130 }
131 
active_node_changed(void * context,enum CRAS_STREAM_DIRECTION dir,cras_node_id_t node_id)132 static void active_node_changed(void *context,
133 				enum CRAS_STREAM_DIRECTION dir,
134 				cras_node_id_t node_id)
135 {
136 	struct cras_client *client = (struct cras_client *)context;
137 	const char *node_name = node_name_for_node_id(client, dir, node_id);
138 	printf("active node (%s): %s\n", string_for_direction(dir), node_name);
139 	free((void *)node_name);
140 }
141 
output_node_volume_changed(void * context,cras_node_id_t node_id,int32_t volume)142 static void output_node_volume_changed(void *context,
143 				       cras_node_id_t node_id, int32_t volume)
144 {
145 	struct cras_client *client = (struct cras_client *)context;
146 	const char *node_name =
147 		node_name_for_node_id(client, CRAS_STREAM_OUTPUT, node_id);
148 	printf("output node '%s' volume: %d\n", node_name, volume);
149 	free((void *)node_name);
150 }
151 
node_left_right_swapped_changed(void * context,cras_node_id_t node_id,int swapped)152 static void node_left_right_swapped_changed(void *context,
153 					    cras_node_id_t node_id, int swapped)
154 {
155 	struct cras_client *client = (struct cras_client *)context;
156 	const char *node_name =
157 		node_name_for_node_id(client, CRAS_STREAM_OUTPUT, node_id);
158 	printf("output node '%s' left-right swapped: %d\n", node_name, swapped);
159 	free((void *)node_name);
160 }
161 
input_node_gain_changed(void * context,cras_node_id_t node_id,int32_t gain)162 static void input_node_gain_changed(void *context,
163 				    cras_node_id_t node_id, int32_t gain)
164 {
165 	struct cras_client *client = (struct cras_client *)context;
166 	const char *node_name =
167 		node_name_for_node_id(client, CRAS_STREAM_INPUT, node_id);
168 	printf("input node '%s' gain: %d\n", node_name, gain);
169 	free((void *)node_name);
170 }
171 
num_active_streams_changed(void * context,enum CRAS_STREAM_DIRECTION dir,uint32_t num_active_streams)172 static void num_active_streams_changed(void *context,
173 				       enum CRAS_STREAM_DIRECTION dir,
174 				       uint32_t num_active_streams)
175 {
176 	printf("num active %s streams: %u\n",
177 	       string_for_direction(dir), num_active_streams);
178 }
179 
server_connection_callback(struct cras_client * client,cras_connection_status_t status,void * user_arg)180 static void server_connection_callback(struct cras_client *client,
181 				       cras_connection_status_t status,
182 				       void *user_arg)
183 {
184 	const char *status_str = "undefined";
185 	switch (status) {
186 		case CRAS_CONN_STATUS_FAILED:
187 			status_str = "error";
188 			break;
189 		case CRAS_CONN_STATUS_DISCONNECTED:
190 			status_str = "disconnected";
191 			break;
192 		case CRAS_CONN_STATUS_CONNECTED:
193 			status_str = "connected";
194 			break;
195 	}
196 	printf("server %s\n", status_str);
197 }
198 
print_usage(const char * command)199 static void print_usage(const char *command) {
200 	fprintf(stderr,
201 		"%s [options]\n"
202 		"  Where [options] are:\n"
203 		"    --sync|-s  - Use the synchronous connection functions.\n"
204 		"    --log-level|-l <n>  - Set the syslog level (7 == "
205 			"LOG_DEBUG).\n",
206 		command);
207 }
208 
main(int argc,char ** argv)209 int main(int argc, char **argv)
210 {
211 	struct cras_client *client;
212 	int rc;
213 	int option_character;
214 	bool synchronous = false;
215 	int log_level = LOG_WARNING;
216 	static struct option long_options[] = {
217 		{"sync", no_argument, NULL, 's'},
218 		{"log-level", required_argument, NULL, 'l'},
219 		{NULL, 0, NULL, 0},
220 	};
221 
222 	while(true) {
223 		int option_index = 0;
224 
225 		option_character = getopt_long(argc, argv, "sl:",
226 					       long_options, &option_index);
227 		if (option_character == -1)
228 			break;
229 		switch (option_character) {
230 		case 's':
231 			synchronous = !synchronous;
232 			break;
233 		case 'l':
234 			log_level = atoi(optarg);
235 			if (log_level < 0)
236 				log_level = LOG_WARNING;
237 			else if (log_level > LOG_DEBUG)
238 				log_level = LOG_DEBUG;
239 			break;
240 		default:
241 			print_usage(argv[0]);
242 			return 1;
243 		}
244 	}
245 
246 	if (optind < argc) {
247 		fprintf(stderr, "%s: Extra arguments.\n", argv[0]);
248 		print_usage(argv[0]);
249 		return 1;
250 	}
251 
252 	openlog("cras_monitor", LOG_PERROR, LOG_USER);
253 	setlogmask(LOG_UPTO(log_level));
254 
255 	rc = cras_client_create(&client);
256 	if (rc < 0) {
257 		syslog(LOG_ERR, "Couldn't create client.");
258 		return rc;
259 	}
260 
261 	cras_client_set_connection_status_cb(
262 			client, server_connection_callback, NULL);
263 
264 	if (synchronous) {
265 		rc = cras_client_connect(client);
266 		if (rc != 0) {
267 			syslog(LOG_ERR, "Could not connect to server.");
268 			return -rc;
269 		}
270 	}
271 
272 	cras_client_set_output_volume_changed_callback(
273 			client, output_volume_changed);
274 	cras_client_set_output_mute_changed_callback(
275 			client, output_mute_changed);
276 	cras_client_set_capture_gain_changed_callback(
277 			client, capture_gain_changed);
278 	cras_client_set_capture_mute_changed_callback(
279 			client, capture_mute_changed);
280 	cras_client_set_nodes_changed_callback(
281 			client, nodes_changed);
282 	cras_client_set_active_node_changed_callback(
283 			client, active_node_changed);
284 	cras_client_set_output_node_volume_changed_callback(
285 			client, output_node_volume_changed);
286 	cras_client_set_node_left_right_swapped_changed_callback(
287 			client, node_left_right_swapped_changed);
288 	cras_client_set_input_node_gain_changed_callback(
289 			client, input_node_gain_changed);
290 	cras_client_set_num_active_streams_changed_callback(
291 			client, num_active_streams_changed);
292 	cras_client_set_state_change_callback_context(client, client);
293 
294 	rc = cras_client_run_thread(client);
295 	if (rc != 0) {
296 		syslog(LOG_ERR, "Could not start thread.");
297 		return -rc;
298 	}
299 
300 	if (!synchronous) {
301 		rc = cras_client_connect_async(client);
302 		if (rc) {
303 			syslog(LOG_ERR, "Couldn't connect to server.\n");
304 			goto destroy_exit;
305 		}
306 	}
307 
308 	while(1) {
309 		int rc;
310 		char c;
311 		rc = read(STDIN_FILENO, &c, 1);
312 		if (rc < 0 || c == 'q')
313 			return 0;
314 	}
315 
316 destroy_exit:
317 	cras_client_destroy(client);
318 	return 0;
319 }
320