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