• 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 "cras_observer.h"
7 
8 #include "cras_alert.h"
9 #include "cras_iodev_list.h"
10 #include "utlist.h"
11 
12 struct cras_observer_client {
13 	struct cras_observer_ops ops;
14 	void *context;
15 	struct cras_observer_client *next, *prev;
16 };
17 
18 struct cras_observer_alerts {
19 	struct cras_alert *output_volume;
20 	struct cras_alert *output_mute;
21 	struct cras_alert *capture_gain;
22 	struct cras_alert *capture_mute;
23 	struct cras_alert *nodes;
24 	struct cras_alert *active_node;
25 	struct cras_alert *output_node_volume;
26 	struct cras_alert *node_left_right_swapped;
27 	struct cras_alert *input_node_gain;
28 	struct cras_alert *suspend_changed;
29 	struct cras_alert *hotword_triggered;
30 	/* If all events for active streams went through a single alert then
31          * we might miss some because the alert code does not send every
32          * alert message. To ensure that the event sent contains the correct
33          * number of active streams per direction, make the alerts
34          * per-direciton. */
35 	struct cras_alert *num_active_streams[CRAS_NUM_DIRECTIONS];
36 	struct cras_alert *non_empty_audio_state_changed;
37 };
38 
39 struct cras_observer_server {
40 	struct cras_observer_alerts alerts;
41 	struct cras_observer_client *clients;
42 };
43 
44 struct cras_observer_alert_data_volume {
45 	int32_t volume;
46 };
47 
48 struct cras_observer_alert_data_mute {
49 	int muted;
50 	int user_muted;
51 	int mute_locked;
52 };
53 
54 struct cras_observer_alert_data_active_node {
55 	enum CRAS_STREAM_DIRECTION direction;
56 	cras_node_id_t node_id;
57 };
58 
59 struct cras_observer_alert_data_node_volume {
60 	cras_node_id_t node_id;
61 	int32_t volume;
62 };
63 
64 struct cras_observer_alert_data_node_lr_swapped {
65 	cras_node_id_t node_id;
66 	int swapped;
67 };
68 
69 struct cras_observer_alert_data_suspend {
70 	int suspended;
71 };
72 
73 struct cras_observer_alert_data_streams {
74 	enum CRAS_STREAM_DIRECTION direction;
75 	uint32_t num_active_streams;
76 };
77 
78 struct cras_observer_alert_data_hotword_triggered {
79 	int64_t tv_sec;
80 	int64_t tv_nsec;
81 };
82 
83 struct cras_observer_non_empty_audio_state {
84 	int non_empty;
85 };
86 
87 /* Global observer instance. */
88 static struct cras_observer_server *g_observer;
89 
90 /* Empty observer ops. */
91 static struct cras_observer_ops g_empty_ops;
92 
93 /*
94  * Alert handlers for delayed callbacks.
95  */
96 
output_volume_alert(void * arg,void * data)97 static void output_volume_alert(void *arg, void *data)
98 {
99 	struct cras_observer_client *client;
100 	struct cras_observer_alert_data_volume *volume_data =
101 		(struct cras_observer_alert_data_volume *)data;
102 
103 	DL_FOREACH (g_observer->clients, client) {
104 		if (client->ops.output_volume_changed)
105 			client->ops.output_volume_changed(client->context,
106 							  volume_data->volume);
107 	}
108 }
109 
output_mute_alert(void * arg,void * data)110 static void output_mute_alert(void *arg, void *data)
111 {
112 	struct cras_observer_client *client;
113 	struct cras_observer_alert_data_mute *mute_data =
114 		(struct cras_observer_alert_data_mute *)data;
115 
116 	DL_FOREACH (g_observer->clients, client) {
117 		if (client->ops.output_mute_changed)
118 			client->ops.output_mute_changed(client->context,
119 							mute_data->muted,
120 							mute_data->user_muted,
121 							mute_data->mute_locked);
122 	}
123 }
124 
capture_gain_alert(void * arg,void * data)125 static void capture_gain_alert(void *arg, void *data)
126 {
127 	struct cras_observer_client *client;
128 	struct cras_observer_alert_data_volume *volume_data =
129 		(struct cras_observer_alert_data_volume *)data;
130 
131 	DL_FOREACH (g_observer->clients, client) {
132 		if (client->ops.capture_gain_changed)
133 			client->ops.capture_gain_changed(client->context,
134 							 volume_data->volume);
135 	}
136 }
137 
capture_mute_alert(void * arg,void * data)138 static void capture_mute_alert(void *arg, void *data)
139 {
140 	struct cras_observer_client *client;
141 	struct cras_observer_alert_data_mute *mute_data =
142 		(struct cras_observer_alert_data_mute *)data;
143 
144 	DL_FOREACH (g_observer->clients, client) {
145 		if (client->ops.capture_mute_changed)
146 			client->ops.capture_mute_changed(
147 				client->context, mute_data->muted,
148 				mute_data->mute_locked);
149 	}
150 }
151 
nodes_prepare(struct cras_alert * alert)152 static void nodes_prepare(struct cras_alert *alert)
153 {
154 	cras_iodev_list_update_device_list();
155 }
156 
nodes_alert(void * arg,void * data)157 static void nodes_alert(void *arg, void *data)
158 {
159 	struct cras_observer_client *client;
160 
161 	DL_FOREACH (g_observer->clients, client) {
162 		if (client->ops.nodes_changed)
163 			client->ops.nodes_changed(client->context);
164 	}
165 }
166 
active_node_alert(void * arg,void * data)167 static void active_node_alert(void *arg, void *data)
168 {
169 	struct cras_observer_client *client;
170 	struct cras_observer_alert_data_active_node *node_data =
171 		(struct cras_observer_alert_data_active_node *)data;
172 
173 	DL_FOREACH (g_observer->clients, client) {
174 		if (client->ops.active_node_changed)
175 			client->ops.active_node_changed(client->context,
176 							node_data->direction,
177 							node_data->node_id);
178 	}
179 }
180 
output_node_volume_alert(void * arg,void * data)181 static void output_node_volume_alert(void *arg, void *data)
182 {
183 	struct cras_observer_client *client;
184 	struct cras_observer_alert_data_node_volume *node_data =
185 		(struct cras_observer_alert_data_node_volume *)data;
186 
187 	DL_FOREACH (g_observer->clients, client) {
188 		if (client->ops.output_node_volume_changed)
189 			client->ops.output_node_volume_changed(
190 				client->context, node_data->node_id,
191 				node_data->volume);
192 	}
193 }
194 
node_left_right_swapped_alert(void * arg,void * data)195 static void node_left_right_swapped_alert(void *arg, void *data)
196 {
197 	struct cras_observer_client *client;
198 	struct cras_observer_alert_data_node_lr_swapped *node_data =
199 		(struct cras_observer_alert_data_node_lr_swapped *)data;
200 
201 	DL_FOREACH (g_observer->clients, client) {
202 		if (client->ops.node_left_right_swapped_changed)
203 			client->ops.node_left_right_swapped_changed(
204 				client->context, node_data->node_id,
205 				node_data->swapped);
206 	}
207 }
208 
input_node_gain_alert(void * arg,void * data)209 static void input_node_gain_alert(void *arg, void *data)
210 {
211 	struct cras_observer_client *client;
212 	struct cras_observer_alert_data_node_volume *node_data =
213 		(struct cras_observer_alert_data_node_volume *)data;
214 
215 	DL_FOREACH (g_observer->clients, client) {
216 		if (client->ops.input_node_gain_changed)
217 			client->ops.input_node_gain_changed(client->context,
218 							    node_data->node_id,
219 							    node_data->volume);
220 	}
221 }
222 
suspend_changed_alert(void * arg,void * data)223 static void suspend_changed_alert(void *arg, void *data)
224 {
225 	struct cras_observer_client *client;
226 	struct cras_observer_alert_data_suspend *suspend_data =
227 		(struct cras_observer_alert_data_suspend *)data;
228 
229 	DL_FOREACH (g_observer->clients, client) {
230 		if (client->ops.suspend_changed)
231 			client->ops.suspend_changed(client->context,
232 						    suspend_data->suspended);
233 	}
234 }
235 
num_active_streams_alert(void * arg,void * data)236 static void num_active_streams_alert(void *arg, void *data)
237 {
238 	struct cras_observer_client *client;
239 	struct cras_observer_alert_data_streams *streams_data =
240 		(struct cras_observer_alert_data_streams *)data;
241 
242 	DL_FOREACH (g_observer->clients, client) {
243 		if (client->ops.num_active_streams_changed)
244 			client->ops.num_active_streams_changed(
245 				client->context, streams_data->direction,
246 				streams_data->num_active_streams);
247 	}
248 }
249 
hotword_triggered_alert(void * arg,void * data)250 static void hotword_triggered_alert(void *arg, void *data)
251 {
252 	struct cras_observer_client *client;
253 	struct cras_observer_alert_data_hotword_triggered *triggered_data =
254 		(struct cras_observer_alert_data_hotword_triggered *)data;
255 
256 	DL_FOREACH (g_observer->clients, client) {
257 		if (client->ops.hotword_triggered)
258 			client->ops.hotword_triggered(client->context,
259 						      triggered_data->tv_sec,
260 						      triggered_data->tv_nsec);
261 	}
262 }
263 
non_empty_audio_state_changed_alert(void * arg,void * data)264 static void non_empty_audio_state_changed_alert(void *arg, void *data)
265 {
266 	struct cras_observer_client *client;
267 	struct cras_observer_non_empty_audio_state *non_empty_audio_data =
268 		(struct cras_observer_non_empty_audio_state *)data;
269 
270 	DL_FOREACH (g_observer->clients, client) {
271 		if (client->ops.non_empty_audio_state_changed) {
272 			client->ops.non_empty_audio_state_changed(
273 				client->context,
274 				non_empty_audio_data->non_empty);
275 		}
276 	}
277 }
278 
cras_observer_server_set_alert(struct cras_alert ** alert,cras_alert_cb cb,cras_alert_prepare prepare,unsigned int flags)279 static int cras_observer_server_set_alert(struct cras_alert **alert,
280 					  cras_alert_cb cb,
281 					  cras_alert_prepare prepare,
282 					  unsigned int flags)
283 {
284 	*alert = cras_alert_create(prepare, flags);
285 	if (!*alert)
286 		return -ENOMEM;
287 	return cras_alert_add_callback(*alert, cb, NULL);
288 }
289 
290 #define CRAS_OBSERVER_SET_ALERT(alert, prepare, flags)                         \
291 	do {                                                                   \
292 		rc = cras_observer_server_set_alert(&g_observer->alerts.alert, \
293 						    alert##_alert, prepare,    \
294 						    flags);                    \
295 		if (rc)                                                        \
296 			goto error;                                            \
297 	} while (0)
298 
299 #define CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(alert, direction)               \
300 	do {                                                                   \
301 		rc = cras_observer_server_set_alert(                           \
302 			&g_observer->alerts.alert[direction], alert##_alert,   \
303 			NULL, 0);                                              \
304 		if (rc)                                                        \
305 			goto error;                                            \
306 	} while (0)
307 
308 /*
309  * Public interface
310  */
311 
cras_observer_server_init()312 int cras_observer_server_init()
313 {
314 	int rc;
315 
316 	memset(&g_empty_ops, 0, sizeof(g_empty_ops));
317 	g_observer = (struct cras_observer_server *)calloc(
318 		1, sizeof(struct cras_observer_server));
319 	if (!g_observer)
320 		return -ENOMEM;
321 
322 	CRAS_OBSERVER_SET_ALERT(output_volume, NULL, 0);
323 	CRAS_OBSERVER_SET_ALERT(output_mute, NULL, 0);
324 	CRAS_OBSERVER_SET_ALERT(capture_gain, NULL, 0);
325 	CRAS_OBSERVER_SET_ALERT(capture_mute, NULL, 0);
326 	CRAS_OBSERVER_SET_ALERT(nodes, nodes_prepare, 0);
327 	CRAS_OBSERVER_SET_ALERT(active_node, nodes_prepare,
328 				CRAS_ALERT_FLAG_KEEP_ALL_DATA);
329 	CRAS_OBSERVER_SET_ALERT(output_node_volume, NULL, 0);
330 	CRAS_OBSERVER_SET_ALERT(node_left_right_swapped, NULL, 0);
331 	CRAS_OBSERVER_SET_ALERT(input_node_gain, NULL, 0);
332 	CRAS_OBSERVER_SET_ALERT(suspend_changed, NULL, 0);
333 	CRAS_OBSERVER_SET_ALERT(hotword_triggered, NULL, 0);
334 	CRAS_OBSERVER_SET_ALERT(non_empty_audio_state_changed, NULL, 0);
335 
336 	CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(num_active_streams,
337 					       CRAS_STREAM_OUTPUT);
338 	CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(num_active_streams,
339 					       CRAS_STREAM_INPUT);
340 	CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(num_active_streams,
341 					       CRAS_STREAM_POST_MIX_PRE_DSP);
342 
343 	return 0;
344 
345 error:
346 	cras_observer_server_free();
347 	return rc;
348 }
349 
cras_observer_server_free()350 void cras_observer_server_free()
351 {
352 	if (!g_observer)
353 		return;
354 	cras_alert_destroy(g_observer->alerts.output_volume);
355 	cras_alert_destroy(g_observer->alerts.output_mute);
356 	cras_alert_destroy(g_observer->alerts.capture_gain);
357 	cras_alert_destroy(g_observer->alerts.capture_mute);
358 	cras_alert_destroy(g_observer->alerts.nodes);
359 	cras_alert_destroy(g_observer->alerts.active_node);
360 	cras_alert_destroy(g_observer->alerts.output_node_volume);
361 	cras_alert_destroy(g_observer->alerts.node_left_right_swapped);
362 	cras_alert_destroy(g_observer->alerts.input_node_gain);
363 	cras_alert_destroy(g_observer->alerts.suspend_changed);
364 	cras_alert_destroy(g_observer->alerts.hotword_triggered);
365 	cras_alert_destroy(g_observer->alerts.non_empty_audio_state_changed);
366 	cras_alert_destroy(
367 		g_observer->alerts.num_active_streams[CRAS_STREAM_OUTPUT]);
368 	cras_alert_destroy(
369 		g_observer->alerts.num_active_streams[CRAS_STREAM_INPUT]);
370 	cras_alert_destroy(
371 		g_observer->alerts
372 			.num_active_streams[CRAS_STREAM_POST_MIX_PRE_DSP]);
373 	free(g_observer);
374 	g_observer = NULL;
375 }
376 
cras_observer_ops_are_empty(const struct cras_observer_ops * ops)377 int cras_observer_ops_are_empty(const struct cras_observer_ops *ops)
378 {
379 	return memcmp(ops, &g_empty_ops, sizeof(*ops)) == 0;
380 }
381 
cras_observer_get_ops(const struct cras_observer_client * client,struct cras_observer_ops * ops)382 void cras_observer_get_ops(const struct cras_observer_client *client,
383 			   struct cras_observer_ops *ops)
384 {
385 	if (!ops)
386 		return;
387 	if (!client)
388 		memset(ops, 0, sizeof(*ops));
389 	else
390 		memcpy(ops, &client->ops, sizeof(*ops));
391 }
392 
cras_observer_set_ops(struct cras_observer_client * client,const struct cras_observer_ops * ops)393 void cras_observer_set_ops(struct cras_observer_client *client,
394 			   const struct cras_observer_ops *ops)
395 {
396 	if (!client)
397 		return;
398 	if (!ops)
399 		memset(&client->ops, 0, sizeof(client->ops));
400 	else
401 		memcpy(&client->ops, ops, sizeof(client->ops));
402 }
403 
404 struct cras_observer_client *
cras_observer_add(const struct cras_observer_ops * ops,void * context)405 cras_observer_add(const struct cras_observer_ops *ops, void *context)
406 {
407 	struct cras_observer_client *client;
408 
409 	client = (struct cras_observer_client *)calloc(1, sizeof(*client));
410 	if (!client)
411 		return NULL;
412 	client->context = context;
413 	DL_APPEND(g_observer->clients, client);
414 	cras_observer_set_ops(client, ops);
415 	return client;
416 }
417 
cras_observer_remove(struct cras_observer_client * client)418 void cras_observer_remove(struct cras_observer_client *client)
419 {
420 	if (!client)
421 		return;
422 	DL_DELETE(g_observer->clients, client);
423 	free(client);
424 }
425 
426 /*
427  * Public interface for notifiers.
428  */
429 
cras_observer_notify_output_volume(int32_t volume)430 void cras_observer_notify_output_volume(int32_t volume)
431 {
432 	struct cras_observer_alert_data_volume data;
433 
434 	data.volume = volume;
435 	cras_alert_pending_data(g_observer->alerts.output_volume, &data,
436 				sizeof(data));
437 }
438 
cras_observer_notify_output_mute(int muted,int user_muted,int mute_locked)439 void cras_observer_notify_output_mute(int muted, int user_muted,
440 				      int mute_locked)
441 {
442 	struct cras_observer_alert_data_mute data;
443 
444 	data.muted = muted;
445 	data.user_muted = user_muted;
446 	data.mute_locked = mute_locked;
447 	cras_alert_pending_data(g_observer->alerts.output_mute, &data,
448 				sizeof(data));
449 }
450 
cras_observer_notify_capture_gain(int32_t gain)451 void cras_observer_notify_capture_gain(int32_t gain)
452 {
453 	struct cras_observer_alert_data_volume data;
454 
455 	data.volume = gain;
456 	cras_alert_pending_data(g_observer->alerts.capture_gain, &data,
457 				sizeof(data));
458 }
459 
cras_observer_notify_capture_mute(int muted,int mute_locked)460 void cras_observer_notify_capture_mute(int muted, int mute_locked)
461 {
462 	struct cras_observer_alert_data_mute data;
463 
464 	data.muted = muted;
465 	data.user_muted = 0;
466 	data.mute_locked = mute_locked;
467 	cras_alert_pending_data(g_observer->alerts.capture_mute, &data,
468 				sizeof(data));
469 }
470 
cras_observer_notify_nodes(void)471 void cras_observer_notify_nodes(void)
472 {
473 	cras_alert_pending(g_observer->alerts.nodes);
474 }
475 
cras_observer_notify_active_node(enum CRAS_STREAM_DIRECTION dir,cras_node_id_t node_id)476 void cras_observer_notify_active_node(enum CRAS_STREAM_DIRECTION dir,
477 				      cras_node_id_t node_id)
478 {
479 	struct cras_observer_alert_data_active_node data;
480 
481 	data.direction = dir;
482 	data.node_id = node_id;
483 	cras_alert_pending_data(g_observer->alerts.active_node, &data,
484 				sizeof(data));
485 }
486 
cras_observer_notify_output_node_volume(cras_node_id_t node_id,int32_t volume)487 void cras_observer_notify_output_node_volume(cras_node_id_t node_id,
488 					     int32_t volume)
489 {
490 	struct cras_observer_alert_data_node_volume data;
491 
492 	data.node_id = node_id;
493 	data.volume = volume;
494 	cras_alert_pending_data(g_observer->alerts.output_node_volume, &data,
495 				sizeof(data));
496 }
497 
cras_observer_notify_node_left_right_swapped(cras_node_id_t node_id,int swapped)498 void cras_observer_notify_node_left_right_swapped(cras_node_id_t node_id,
499 						  int swapped)
500 {
501 	struct cras_observer_alert_data_node_lr_swapped data;
502 
503 	data.node_id = node_id;
504 	data.swapped = swapped;
505 	cras_alert_pending_data(g_observer->alerts.node_left_right_swapped,
506 				&data, sizeof(data));
507 }
508 
cras_observer_notify_input_node_gain(cras_node_id_t node_id,int32_t gain)509 void cras_observer_notify_input_node_gain(cras_node_id_t node_id, int32_t gain)
510 {
511 	struct cras_observer_alert_data_node_volume data;
512 
513 	data.node_id = node_id;
514 	data.volume = gain;
515 	cras_alert_pending_data(g_observer->alerts.input_node_gain, &data,
516 				sizeof(data));
517 }
518 
cras_observer_notify_suspend_changed(int suspended)519 void cras_observer_notify_suspend_changed(int suspended)
520 {
521 	struct cras_observer_alert_data_suspend data;
522 
523 	data.suspended = suspended;
524 	cras_alert_pending_data(g_observer->alerts.suspend_changed, &data,
525 				sizeof(data));
526 }
527 
cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,uint32_t num_active_streams)528 void cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,
529 					     uint32_t num_active_streams)
530 {
531 	struct cras_observer_alert_data_streams data;
532 	struct cras_alert *alert;
533 
534 	data.direction = dir;
535 	data.num_active_streams = num_active_streams;
536 	alert = g_observer->alerts.num_active_streams[dir];
537 	if (!alert)
538 		return;
539 
540 	cras_alert_pending_data(alert, &data, sizeof(data));
541 }
542 
cras_observer_notify_hotword_triggered(int64_t tv_sec,int64_t tv_nsec)543 void cras_observer_notify_hotword_triggered(int64_t tv_sec, int64_t tv_nsec)
544 {
545 	struct cras_observer_alert_data_hotword_triggered data;
546 
547 	data.tv_sec = tv_sec;
548 	data.tv_nsec = tv_nsec;
549 	cras_alert_pending_data(g_observer->alerts.hotword_triggered, &data,
550 				sizeof(data));
551 }
552 
cras_observer_notify_non_empty_audio_state_changed(int non_empty)553 void cras_observer_notify_non_empty_audio_state_changed(int non_empty)
554 {
555 	struct cras_observer_non_empty_audio_state data;
556 
557 	data.non_empty = non_empty;
558 
559 	cras_alert_pending_data(
560 		g_observer->alerts.non_empty_audio_state_changed, &data,
561 		sizeof(data));
562 }