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 }