• 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(
106 					client->context,
107 					volume_data->volume);
108 	}
109 }
110 
output_mute_alert(void * arg,void * data)111 static void output_mute_alert(void *arg, void *data)
112 {
113 	struct cras_observer_client *client;
114 	struct cras_observer_alert_data_mute *mute_data =
115 		(struct cras_observer_alert_data_mute *)data;
116 
117 	DL_FOREACH(g_observer->clients, client) {
118 		if (client->ops.output_mute_changed)
119 			client->ops.output_mute_changed(
120 					client->context,
121 					mute_data->muted,
122 					mute_data->user_muted,
123 					mute_data->mute_locked);
124 	}
125 }
126 
capture_gain_alert(void * arg,void * data)127 static void capture_gain_alert(void *arg, void *data)
128 {
129 	struct cras_observer_client *client;
130 	struct cras_observer_alert_data_volume *volume_data =
131 		(struct cras_observer_alert_data_volume *)data;
132 
133 	DL_FOREACH(g_observer->clients, client) {
134 		if (client->ops.capture_gain_changed)
135 			client->ops.capture_gain_changed(
136 					client->context,
137 					volume_data->volume);
138 	}
139 }
140 
capture_mute_alert(void * arg,void * data)141 static void capture_mute_alert(void *arg, void *data)
142 {
143 	struct cras_observer_client *client;
144 	struct cras_observer_alert_data_mute *mute_data =
145 		(struct cras_observer_alert_data_mute *)data;
146 
147 	DL_FOREACH(g_observer->clients, client) {
148 		if (client->ops.capture_mute_changed)
149 			client->ops.capture_mute_changed(
150 					client->context,
151 					mute_data->muted,
152 					mute_data->mute_locked);
153 	}
154 }
155 
nodes_prepare(struct cras_alert * alert)156 static void nodes_prepare(struct cras_alert *alert)
157 {
158 	cras_iodev_list_update_device_list();
159 }
160 
nodes_alert(void * arg,void * data)161 static void nodes_alert(void *arg, void *data)
162 {
163 	struct cras_observer_client *client;
164 
165 	DL_FOREACH(g_observer->clients, client) {
166 		if (client->ops.nodes_changed)
167 			client->ops.nodes_changed(client->context);
168 	}
169 }
170 
active_node_alert(void * arg,void * data)171 static void active_node_alert(void *arg, void *data)
172 {
173 	struct cras_observer_client *client;
174 	struct cras_observer_alert_data_active_node *node_data =
175 		(struct cras_observer_alert_data_active_node *)data;
176 
177 	DL_FOREACH(g_observer->clients, client) {
178 		if (client->ops.active_node_changed)
179 			client->ops.active_node_changed(
180 					client->context,
181 					node_data->direction,
182 					node_data->node_id);
183 	}
184 }
185 
output_node_volume_alert(void * arg,void * data)186 static void output_node_volume_alert(void *arg, void *data)
187 {
188 	struct cras_observer_client *client;
189 	struct cras_observer_alert_data_node_volume *node_data =
190 		(struct cras_observer_alert_data_node_volume *)data;
191 
192 	DL_FOREACH(g_observer->clients, client) {
193 		if (client->ops.output_node_volume_changed)
194 			client->ops.output_node_volume_changed(
195 					client->context,
196 					node_data->node_id,
197 					node_data->volume);
198 	}
199 }
200 
node_left_right_swapped_alert(void * arg,void * data)201 static void node_left_right_swapped_alert(void *arg, void *data)
202 {
203 	struct cras_observer_client *client;
204 	struct cras_observer_alert_data_node_lr_swapped *node_data =
205 		(struct cras_observer_alert_data_node_lr_swapped *)data;
206 
207 	DL_FOREACH(g_observer->clients, client) {
208 		if (client->ops.node_left_right_swapped_changed)
209 			client->ops.node_left_right_swapped_changed(
210 					client->context,
211 					node_data->node_id,
212 					node_data->swapped);
213 	}
214 }
215 
input_node_gain_alert(void * arg,void * data)216 static void input_node_gain_alert(void *arg, void *data)
217 {
218 	struct cras_observer_client *client;
219 	struct cras_observer_alert_data_node_volume *node_data =
220 		(struct cras_observer_alert_data_node_volume *)data;
221 
222 	DL_FOREACH(g_observer->clients, client) {
223 		if (client->ops.input_node_gain_changed)
224 			client->ops.input_node_gain_changed(
225 					client->context,
226 					node_data->node_id,
227 					node_data->volume);
228 	}
229 }
230 
suspend_changed_alert(void * arg,void * data)231 static void suspend_changed_alert(void *arg, void *data)
232 {
233 	struct cras_observer_client *client;
234 	struct cras_observer_alert_data_suspend *suspend_data =
235 		(struct cras_observer_alert_data_suspend *)data;
236 
237 	DL_FOREACH(g_observer->clients, client) {
238 		if (client->ops.suspend_changed)
239 			client->ops.suspend_changed(
240 					client->context,
241 					suspend_data->suspended);
242 	}
243 }
244 
num_active_streams_alert(void * arg,void * data)245 static void num_active_streams_alert(void *arg, void *data)
246 {
247 	struct cras_observer_client *client;
248 	struct cras_observer_alert_data_streams *streams_data =
249 		(struct cras_observer_alert_data_streams *)data;
250 
251 	DL_FOREACH(g_observer->clients, client) {
252 		if (client->ops.num_active_streams_changed)
253 			client->ops.num_active_streams_changed(
254 					client->context,
255 					streams_data->direction,
256 					streams_data->num_active_streams);
257 	}
258 }
259 
hotword_triggered_alert(void * arg,void * data)260 static void hotword_triggered_alert(void *arg, void *data)
261 {
262 	struct cras_observer_client *client;
263 	struct cras_observer_alert_data_hotword_triggered *triggered_data =
264 		(struct cras_observer_alert_data_hotword_triggered *)data;
265 
266 	DL_FOREACH(g_observer->clients, client) {
267 		if (client->ops.hotword_triggered)
268 			client->ops.hotword_triggered(
269 					client->context,
270 					triggered_data->tv_sec,
271 					triggered_data->tv_nsec);
272 	}
273 }
274 
non_empty_audio_state_changed_alert(void * arg,void * data)275 static void non_empty_audio_state_changed_alert(void *arg, void *data)
276 {
277 	struct cras_observer_client *client;
278 	struct cras_observer_non_empty_audio_state *non_empty_audio_data =
279 			(struct cras_observer_non_empty_audio_state *)data;
280 
281 	DL_FOREACH(g_observer->clients, client) {
282 		if (client->ops.non_empty_audio_state_changed) {
283 			client->ops.non_empty_audio_state_changed(
284 					client->context,
285 					non_empty_audio_data->non_empty);
286 		}
287 	}
288 }
289 
cras_observer_server_set_alert(struct cras_alert ** alert,cras_alert_cb cb,cras_alert_prepare prepare,unsigned int flags)290 static int cras_observer_server_set_alert(struct cras_alert **alert,
291 					  cras_alert_cb cb,
292 					  cras_alert_prepare prepare,
293 					  unsigned int flags)
294 {
295 	*alert = cras_alert_create(prepare, flags);
296 	if (!*alert)
297 		return -ENOMEM;
298 	return cras_alert_add_callback(*alert, cb, NULL);
299 }
300 
301 #define CRAS_OBSERVER_SET_ALERT(alert,prepare,flags) \
302 	do { \
303 		rc = cras_observer_server_set_alert( \
304 			&g_observer->alerts.alert, alert##_alert, \
305 			prepare, flags); \
306 		if (rc) \
307 			goto error; \
308 	} while(0)
309 
310 #define CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(alert,direction) \
311 	do { \
312 		rc = cras_observer_server_set_alert( \
313 			&g_observer->alerts.alert[direction], \
314 			alert##_alert, NULL, 0); \
315 		if (rc) \
316 			goto error; \
317 	} while(0)
318 
319 /*
320  * Public interface
321  */
322 
cras_observer_server_init()323 int cras_observer_server_init()
324 {
325 	int rc;
326 
327 	memset(&g_empty_ops, 0, sizeof(g_empty_ops));
328 	g_observer = (struct cras_observer_server *)
329 			calloc(1, sizeof(struct cras_observer_server));
330 	if (!g_observer)
331 		return -ENOMEM;
332 
333 	CRAS_OBSERVER_SET_ALERT(output_volume, NULL, 0);
334 	CRAS_OBSERVER_SET_ALERT(output_mute, NULL, 0);
335 	CRAS_OBSERVER_SET_ALERT(capture_gain, NULL, 0);
336 	CRAS_OBSERVER_SET_ALERT(capture_mute, NULL, 0);
337 	CRAS_OBSERVER_SET_ALERT(nodes, nodes_prepare, 0);
338 	CRAS_OBSERVER_SET_ALERT(active_node, nodes_prepare,
339 				CRAS_ALERT_FLAG_KEEP_ALL_DATA);
340 	CRAS_OBSERVER_SET_ALERT(output_node_volume, NULL, 0);
341 	CRAS_OBSERVER_SET_ALERT(node_left_right_swapped, NULL, 0);
342 	CRAS_OBSERVER_SET_ALERT(input_node_gain, NULL, 0);
343 	CRAS_OBSERVER_SET_ALERT(suspend_changed, NULL, 0);
344 	CRAS_OBSERVER_SET_ALERT(hotword_triggered, NULL, 0);
345 	CRAS_OBSERVER_SET_ALERT(non_empty_audio_state_changed, NULL, 0);
346 
347 	CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(
348 		num_active_streams, CRAS_STREAM_OUTPUT);
349 	CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(
350 		num_active_streams, CRAS_STREAM_INPUT);
351 	CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(
352 		num_active_streams, CRAS_STREAM_POST_MIX_PRE_DSP);
353 
354 	return 0;
355 
356 error:
357 	cras_observer_server_free();
358 	return rc;
359 }
360 
cras_observer_server_free()361 void cras_observer_server_free()
362 {
363 	if (!g_observer)
364 		return;
365 	cras_alert_destroy(g_observer->alerts.output_volume);
366 	cras_alert_destroy(g_observer->alerts.output_mute);
367 	cras_alert_destroy(g_observer->alerts.capture_gain);
368 	cras_alert_destroy(g_observer->alerts.capture_mute);
369 	cras_alert_destroy(g_observer->alerts.nodes);
370 	cras_alert_destroy(g_observer->alerts.active_node);
371 	cras_alert_destroy(g_observer->alerts.output_node_volume);
372 	cras_alert_destroy(g_observer->alerts.node_left_right_swapped);
373 	cras_alert_destroy(g_observer->alerts.input_node_gain);
374 	cras_alert_destroy(g_observer->alerts.suspend_changed);
375 	cras_alert_destroy(g_observer->alerts.hotword_triggered);
376 	cras_alert_destroy(g_observer->alerts.non_empty_audio_state_changed);
377 	cras_alert_destroy(g_observer->alerts.num_active_streams[
378 							CRAS_STREAM_OUTPUT]);
379 	cras_alert_destroy(g_observer->alerts.num_active_streams[
380 							CRAS_STREAM_INPUT]);
381 	cras_alert_destroy(g_observer->alerts.num_active_streams[
382 						CRAS_STREAM_POST_MIX_PRE_DSP]);
383 	free(g_observer);
384 	g_observer = NULL;
385 }
386 
cras_observer_ops_are_empty(const struct cras_observer_ops * ops)387 int cras_observer_ops_are_empty(const struct cras_observer_ops *ops)
388 {
389 	return memcmp(ops, &g_empty_ops, sizeof(*ops)) == 0;
390 }
391 
cras_observer_get_ops(const struct cras_observer_client * client,struct cras_observer_ops * ops)392 void cras_observer_get_ops(const struct cras_observer_client *client,
393 			   struct cras_observer_ops *ops)
394 {
395 	if (!ops)
396 		return;
397 	if (!client)
398 		memset(ops, 0, sizeof(*ops));
399 	else
400 		memcpy(ops, &client->ops, sizeof(*ops));
401 }
402 
cras_observer_set_ops(struct cras_observer_client * client,const struct cras_observer_ops * ops)403 void cras_observer_set_ops(struct cras_observer_client *client,
404 			   const struct cras_observer_ops *ops)
405 {
406 	if (!client)
407 		return;
408 	if (!ops)
409 		memset(&client->ops, 0, sizeof(client->ops));
410 	else
411 		memcpy(&client->ops, ops, sizeof(client->ops));
412 }
413 
cras_observer_add(const struct cras_observer_ops * ops,void * context)414 struct cras_observer_client *cras_observer_add(
415 			const struct cras_observer_ops *ops,
416 			void *context)
417 {
418 	struct cras_observer_client *client;
419 
420 	client = (struct cras_observer_client *)calloc(1, sizeof(*client));
421 	if (!client)
422 		return NULL;
423 	client->context = context;
424 	DL_APPEND(g_observer->clients, client);
425 	cras_observer_set_ops(client, ops);
426 	return client;
427 }
428 
cras_observer_remove(struct cras_observer_client * client)429 void cras_observer_remove(struct cras_observer_client *client)
430 {
431 	if (!client)
432 		return;
433 	DL_DELETE(g_observer->clients, client);
434 	free(client);
435 }
436 
437 /*
438  * Public interface for notifiers.
439  */
440 
cras_observer_notify_output_volume(int32_t volume)441 void cras_observer_notify_output_volume(int32_t volume)
442 {
443 	struct cras_observer_alert_data_volume data;
444 
445 	data.volume = volume;
446 	cras_alert_pending_data(g_observer->alerts.output_volume,
447 				&data, sizeof(data));
448 }
449 
cras_observer_notify_output_mute(int muted,int user_muted,int mute_locked)450 void cras_observer_notify_output_mute(int muted, int user_muted,
451 				      int mute_locked)
452 {
453 	struct cras_observer_alert_data_mute data;
454 
455 	data.muted = muted;
456 	data.user_muted = user_muted;
457 	data.mute_locked = mute_locked;
458 	cras_alert_pending_data(g_observer->alerts.output_mute,
459 				&data, sizeof(data));
460 }
461 
cras_observer_notify_capture_gain(int32_t gain)462 void cras_observer_notify_capture_gain(int32_t gain)
463 {
464 	struct cras_observer_alert_data_volume data;
465 
466 	data.volume = gain;
467 	cras_alert_pending_data(g_observer->alerts.capture_gain,
468 				&data, sizeof(data));
469 }
470 
cras_observer_notify_capture_mute(int muted,int mute_locked)471 void cras_observer_notify_capture_mute(int muted, int mute_locked)
472 {
473 	struct cras_observer_alert_data_mute data;
474 
475 	data.muted = muted;
476 	data.user_muted = 0;
477 	data.mute_locked = mute_locked;
478 	cras_alert_pending_data(g_observer->alerts.capture_mute,
479 				&data, sizeof(data));
480 }
481 
cras_observer_notify_nodes(void)482 void cras_observer_notify_nodes(void)
483 {
484 	cras_alert_pending(g_observer->alerts.nodes);
485 }
486 
cras_observer_notify_active_node(enum CRAS_STREAM_DIRECTION dir,cras_node_id_t node_id)487 void cras_observer_notify_active_node(enum CRAS_STREAM_DIRECTION dir,
488 				      cras_node_id_t node_id)
489 {
490 	struct cras_observer_alert_data_active_node data;
491 
492 	data.direction = dir;
493 	data.node_id = node_id;
494 	cras_alert_pending_data(g_observer->alerts.active_node,
495 				&data, sizeof(data));
496 }
497 
cras_observer_notify_output_node_volume(cras_node_id_t node_id,int32_t volume)498 void cras_observer_notify_output_node_volume(cras_node_id_t node_id,
499 					     int32_t volume)
500 {
501 	struct cras_observer_alert_data_node_volume data;
502 
503 	data.node_id = node_id;
504 	data.volume = volume;
505 	cras_alert_pending_data(g_observer->alerts.output_node_volume,
506 				&data, sizeof(data));
507 }
508 
cras_observer_notify_node_left_right_swapped(cras_node_id_t node_id,int swapped)509 void cras_observer_notify_node_left_right_swapped(cras_node_id_t node_id,
510 						  int swapped)
511 {
512 	struct cras_observer_alert_data_node_lr_swapped data;
513 
514 	data.node_id = node_id;
515 	data.swapped = swapped;
516 	cras_alert_pending_data(g_observer->alerts.node_left_right_swapped,
517 				&data, sizeof(data));
518 }
519 
cras_observer_notify_input_node_gain(cras_node_id_t node_id,int32_t gain)520 void cras_observer_notify_input_node_gain(cras_node_id_t node_id,
521 					  int32_t gain)
522 {
523 	struct cras_observer_alert_data_node_volume data;
524 
525 	data.node_id = node_id;
526 	data.volume = gain;
527 	cras_alert_pending_data(g_observer->alerts.input_node_gain,
528 				&data, sizeof(data));
529 }
530 
cras_observer_notify_suspend_changed(int suspended)531 void cras_observer_notify_suspend_changed(int suspended)
532 {
533 	struct cras_observer_alert_data_suspend data;
534 
535 	data.suspended = suspended;
536 	cras_alert_pending_data(g_observer->alerts.suspend_changed,
537 				&data, sizeof(data));
538 }
539 
cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,uint32_t num_active_streams)540 void cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,
541 					     uint32_t num_active_streams)
542 {
543 	struct cras_observer_alert_data_streams data;
544 	struct cras_alert *alert;
545 
546 	data.direction = dir;
547 	data.num_active_streams = num_active_streams;
548 	alert = g_observer->alerts.num_active_streams[dir];
549 	if (!alert)
550 		return;
551 
552 	cras_alert_pending_data(alert, &data, sizeof(data));
553 }
554 
cras_observer_notify_hotword_triggered(int64_t tv_sec,int64_t tv_nsec)555 void cras_observer_notify_hotword_triggered(int64_t tv_sec, int64_t tv_nsec)
556 {
557 	struct cras_observer_alert_data_hotword_triggered data;
558 
559 	data.tv_sec = tv_sec;
560 	data.tv_nsec = tv_nsec;
561 	cras_alert_pending_data(g_observer->alerts.hotword_triggered,
562 				&data, sizeof(data));
563 }
564 
cras_observer_notify_non_empty_audio_state_changed(int non_empty)565 void cras_observer_notify_non_empty_audio_state_changed(int non_empty)
566 {
567 	struct cras_observer_non_empty_audio_state data;
568 
569 	data.non_empty = non_empty;
570 
571 	cras_alert_pending_data(g_observer->alerts.non_empty_audio_state_changed,
572 				&data, sizeof(data));
573 }