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 }