6 #include <pulsecore/pulsecore-config.h>
10 #include <pulsecore/core-util.h>
19 #define AUDIOMGR_DOMAIN "PULSE"
20 #define AUDIOMGR_NODE "pulsePlugin"
23 * these must match their counterpart
24 * in audiomanagertypes.h
28 #define DS_CONTROLLED 1
34 #define IS_INTERRUPTED 2
36 /* availability status */
37 #define AS_AVAILABLE 1
38 #define AS_UNAVAILABLE 2
40 /* availability reason */
42 #define AR_SAMEMEDIA 2
44 #define AR_TEMPERATURE 4
46 #define AR_ERRORMEDIA 6
62 pa_hashmap *nodes; /**< nodes ie. sinks and sources */
63 pa_hashmap *conns; /**< connections */
67 static void *node_hash(mir_direction, uint16_t);
68 static void *conn_hash(uint16_t);
71 struct pa_audiomgr *pa_audiomgr_init(struct userdata *u)
73 /* pa_module *m = u->module; */
78 am = pa_xnew0(pa_audiomgr, 1);
80 am->domain.id = AM_ID_INVALID;
81 am->domain.state = DS_DOWN;
82 am->nodes = pa_hashmap_new(pa_idxset_trivial_hash_func,
83 pa_idxset_trivial_compare_func);
84 am->conns = pa_hashmap_new(pa_idxset_trivial_hash_func,
85 pa_idxset_trivial_compare_func);
89 void pa_audiomgr_done(struct userdata *u)
93 if (u && (am = u->audiomgr)) {
94 if (u->dbusif && am->domain.id != AM_ID_INVALID)
95 pa_policy_dbusif_unregister_domain(u, am->domain.id);
97 pa_hashmap_free(am->nodes, NULL,NULL);
98 pa_hashmap_free(am->conns, NULL,NULL);
99 pa_xfree((void *)am->domain.name);
106 void pa_audiomgr_register_domain(struct userdata *u)
109 am_domainreg_data *dr;
112 pa_assert_se((am = u->audiomgr));
114 dr = pa_xnew0(am_domainreg_data, 1);
117 dr->name = AUDIOMGR_DOMAIN; /* AM domain name */
118 dr->bus_name = AUDIOMGR_NODE; /* AM internal bus name. */
119 dr->node_name = AUDIOMGR_NODE; /* node name on AM's internal bus */
121 dr->complete = FALSE;
124 pa_policy_dbusif_register_domain(u, dr);
127 void pa_audiomgr_domain_registered(struct userdata *u,
130 am_domainreg_data *dr)
136 pa_assert_se((am = u->audiomgr));
139 am->domain.name = pa_xstrdup(dr->name);
141 am->domain.state = state;
143 pa_log_debug("start domain registration for '%s' domain", dr->name);
145 pa_discover_domain_up(u);
147 pa_log_debug("domain registration for '%s' domain is complete", dr->name);
149 pa_policy_dbusif_domain_complete(u, id);
155 void pa_audiomgr_unregister_domain(struct userdata *u, pa_bool_t send_state)
163 pa_assert_se((am = u->audiomgr));
165 pa_log_debug("unregistering domain '%s'", am->domain.name);
167 while ((node = pa_hashmap_iterate(am->nodes, &state, &key))) {
168 pa_log_debug(" unregistering '%s' (%p/%p)", node->amname, key,node);
169 node->amid = AM_ID_INVALID;
170 pa_hashmap_remove(am->nodes, key);
173 am->domain.id = AM_ID_INVALID;
174 am->domain.state = DS_DOWN;
178 void pa_audiomgr_register_node(struct userdata *u, mir_node *node)
186 pa_assert_se((am = u->audiomgr));
188 if (am->domain.state == DS_DOWN || am->domain.state == DS_RUNDOWN)
189 pa_log_debug("skip registering nodes while the domain is down");
191 if (node->direction == mir_input || node->direction == mir_output) {
192 rd = pa_xnew0(am_nodereg_data, 1);
193 rd->key = pa_xstrdup(node->key);
194 rd->name = pa_xstrdup(node->amname);
195 rd->domain = am->domain.id;
198 rd->visible = node->visible;
199 rd->avail.status = AS_AVAILABLE;
200 rd->avail.reason = 0;
203 if (node->direction == mir_input) {
204 rd->interrupt = IS_OFF;
205 method = AUDIOMGR_REGISTER_SOURCE;
208 rd->mute = MS_UNMUTED;
209 method = AUDIOMGR_REGISTER_SINK;
212 success = pa_policy_dbusif_register_node(u, method, rd);
215 pa_log_debug("initiate registration node '%s' (%p)"
216 "to audio manager", rd->name, node);
219 pa_log("%s: failed to register node '%s' (%p)"
220 "to audio manager", __FILE__, rd->name, node);
226 void pa_audiomgr_node_registered(struct userdata *u,
238 pa_assert_se((am = u->audiomgr));
240 if (!(node = pa_discover_find_node(u, rd->key)))
241 pa_log("%s: can't find node with key '%s'", __FILE__, rd->key);
245 key = node_hash(node->direction, id);
247 pa_log_debug("registering node '%s' (%p/%p)",
248 node->amname, key, node);
250 pa_hashmap_put(am->nodes, key, node);
253 pa_xfree((void *)rd->key);
254 pa_xfree((void *)rd->name);
255 pa_xfree((void *)rd);
258 void pa_audiomgr_unregister_node(struct userdata *u, mir_node *node)
261 am_nodeunreg_data *ud;
268 pa_assert_se((am = u->audiomgr));
270 if (am->domain.state == DS_DOWN || am->domain.state == DS_RUNDOWN)
271 pa_log_debug("skip unregistering nodes while the domain is down");
272 else if (node->amid == AM_ID_INVALID)
273 pa_log_debug("node '%s' was not registered", node->amname);
274 else if (node->direction == mir_input || node->direction == mir_output) {
275 ud = pa_xnew0(am_nodeunreg_data, 1);
277 ud->name = pa_xstrdup(node->amname);
279 key = node_hash(node->direction, node->amid);
280 removed = pa_hashmap_remove(am->nodes, key);
282 if (node != removed) {
284 pa_log("%s: confused with data structures: key mismatch. "
285 "attempted to remove '%s' (%p/%p); "
286 "actually removed '%s' (%p/%p)", __FILE__,
287 node->amname, key, node, removed->amname,
288 node_hash(removed->direction, removed->amid), removed);
290 pa_log("%s: confused with data structures: node %u (%p)"
291 "is not in the hash table", __FILE__, node->amid, node);
295 if (node->direction == mir_input)
296 method = AUDIOMGR_DEREGISTER_SOURCE;
298 method = AUDIOMGR_DEREGISTER_SINK;
301 success = pa_policy_dbusif_unregister_node(u, method, ud);
304 pa_log_debug("sucessfully unregistered node '%s' (%p/%p)"
305 "from audio manager", node->amname, key, node);
308 pa_log("%s: failed to unregister node '%s' (%p)"
309 "from audio manager", __FILE__, node->amname, node);
314 void pa_audiomgr_node_unregistered(struct userdata *u,
315 am_nodeunreg_data *ud)
319 /* can't do too much here anyways,
320 since the node is gone already */
322 pa_xfree((void *)ud->name);
323 pa_xfree((void *)ud);
327 void pa_audiomgr_connect(struct userdata *u, am_connect_data *cd)
331 mir_connection *conn;
333 mir_node *from = NULL;
339 pa_assert_se((am = u->audiomgr));
341 if ((from = pa_hashmap_get(am->nodes, node_hash(mir_input, cd->source))) &&
342 (to = pa_hashmap_get(am->nodes, node_hash(mir_output, cd->sink))))
344 cid = cd->connection;
346 pa_log_debug("routing '%s' => '%s'", from->amname, to->amname);
348 if (!(conn = mir_router_add_explicit_route(u, cid, from, to)))
349 err = E_NOT_POSSIBLE;
351 pa_log_debug("registering connection (%u/%p)",
352 cd->connection, conn);
353 pa_hashmap_put(am->conns, conn_hash(cid), conn);
357 pa_log_debug("failed to connect: can't find node for %s %u",
358 from ? "sink" : "source", from ? cd->sink : cd->source);
359 err = E_NON_EXISTENT;
362 memset(&ad, 0, sizeof(ad));
363 ad.handle = cd->handle;
364 ad.param1 = cd->connection;
367 pa_policy_dbusif_acknowledge(u, AUDIOMGR_CONNECT_ACK, &ad);
370 void pa_audiomgr_disconnect(struct userdata *u, am_connect_data *cd)
373 mir_connection *conn;
380 pa_assert_se((am = u->audiomgr));
382 cid = cd->connection;
384 if ((conn = pa_hashmap_remove(am->conns, conn_hash(cid))))
385 mir_router_remove_explicit_route(u, conn);
387 pa_log_debug("failed to disconnect: can't find connection %u", cid);
388 err = E_NON_EXISTENT;
391 memset(&ad, 0, sizeof(ad));
392 ad.handle = cd->handle;
393 ad.param1 = cd->connection;
396 pa_policy_dbusif_acknowledge(u, AUDIOMGR_DISCONNECT_ACK, &ad);
399 static void *node_hash(mir_direction direction, uint16_t amid)
401 return NULL + ((uint32_t)direction << 16 | (uint32_t)amid);
404 static void *conn_hash(uint16_t connid)
406 return NULL + (uint32_t)connid;
414 * indent-tabs-mode: nil