2 * module-murphy-ivi -- PulseAudio module for providing audio routing support
3 * Copyright (c) 2012, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 2.1, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
22 #include <sys/types.h>
25 #include <pulse/def.h>
26 #include <pulsecore/pulsecore-config.h>
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/protocol-native.h>
29 #include <pulsecore/tagstruct.h>
30 #include <pulsecore/pstream-util.h>
40 SUBCOMMAND_DISCONNECT,
52 pa_idxset *subscribed;
55 static const char *mir_direction_names[] = {
56 [mir_direction_unknown] = "unknown",
57 [mir_input] = "input",
58 [mir_output] = "output"
62 static const char *mir_implement_names[] = {
63 [mir_implementation_unknown] = "unknown",
64 [mir_device] = "device",
65 [mir_stream] = "stream"
69 static const char *mir_location_names[] = {
70 [mir_location_unknown] = "unknown",
71 [mir_internal] = "internal",
72 [mir_external] = "external"
75 static const char *mir_node_type_names[512] = {
76 [mir_node_type_unknown] = "unknown",
77 [mir_radio] = "radio",
78 [mir_player] = "player",
79 [mir_navigator] = "navigator",
81 [mir_browser] = "browser",
82 [mir_phone] = "phone",
83 [mir_event] = "event",
85 [mir_speakers] = "speakers",
86 [mir_front_speakers] = "front_speakers",
87 [mir_rear_speakers] = "rear_speakers",
88 [mir_microphone] = "microphone",
92 [mir_wired_headset] = "wired_headset",
93 [mir_wired_headphone] = "wired_headphone",
94 [mir_usb_headset] ="usb_headset",
95 [mir_usb_headphone] = "usb_headphone",
96 [mir_bluetooth_sco] = "bluetooth_sco",
97 [mir_bluetooth_a2dp] = "bluetooth_a2dp",
98 [mir_bluetooth_carkit] = "bluetooth_carkit",
99 [mir_bluetooth_source] = "bluetooth_source",
100 [mir_bluetooth_sink] = "bluetoohth_sink"
103 static const char *mir_privacy_names[] = {
104 [mir_privacy_unknown] ="unknown",
105 [mir_public] = "public",
106 [mir_private] = "private"
109 static void *conn_hash(uint32_t connid);
111 struct pa_extapi *pa_extapi_init(struct userdata *u) {
116 ap = pa_xnew0(pa_extapi, 1);
120 ap->conns = pa_hashmap_new(pa_idxset_trivial_hash_func,
121 pa_idxset_trivial_compare_func);
123 ap->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func,
124 pa_idxset_trivial_compare_func);
129 void pa_extapi_done(struct userdata *u) {
132 if (u && (ap = u->extapi)) {
134 pa_hashmap_free(ap->conns, NULL,NULL);
136 pa_idxset_free(ap->subscribed, NULL, NULL);
141 int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
144 pa_tagstruct *reply = NULL;
153 pa_log_debug("in module-murphy-ivi extension callback");
155 if (pa_tagstruct_getu32(t, &command) < 0)
158 reply = pa_tagstruct_new(NULL, 0);
159 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
160 pa_tagstruct_putu32(reply, tag);
163 case SUBCOMMAND_TEST: {
164 pa_log_debug("got test request to module-murphy-ivi");
166 if (!pa_tagstruct_eof(t))
169 pa_tagstruct_putu32(reply, 1);
173 case SUBCOMMAND_READ: {
179 if (!pa_tagstruct_eof(t))
182 pa_log_debug("got read request to module-murphy-ivi");
184 PA_IDXSET_FOREACH(node, u->nodeset->nodes, index) {
186 if (!node->visible || !node->available)
189 pa_tagstruct_puts(reply, node->amname);
191 prop = pa_proplist_new();
193 sprintf(buf, "%d", node->index);
194 pa_proplist_sets(prop, "index", buf);
195 pa_proplist_sets(prop, "direction", mir_direction_names[node->direction]);
196 sprintf(buf, "%d", node->channels);
197 pa_proplist_sets(prop, "channels", buf);
198 pa_proplist_sets(prop, "location", mir_location_names[node->location]);
199 pa_proplist_sets(prop, "privacy", mir_privacy_names[node->privacy]);
200 pa_proplist_sets(prop, "type", mir_node_type_names[node->type]);
201 pa_proplist_sets(prop, "amname", node->amname);
202 pa_proplist_sets(prop, "amdescr", node->amdescr);
203 sprintf(buf, "%d", node->amid);
204 pa_proplist_sets(prop, "amid", buf);
205 pa_proplist_sets(prop, "paname", node->paname);
206 sprintf(buf, "%d", node->paidx);
207 pa_proplist_sets(prop, "paidx", buf);
209 pa_tagstruct_put_proplist(reply, prop);
215 case SUBCOMMAND_CONNECT: {
216 uint32_t id, from_index, to_index;
218 mir_connection *conn;
220 pa_log_debug("connect called in module-murphy-ivi");
222 if (pa_tagstruct_getu32(t, &from_index) < 0 ||
223 pa_tagstruct_getu32(t, &to_index) < 0 ||
224 !pa_tagstruct_eof(t))
227 id = u->extapi->conn_id++;
228 if (!(from = pa_idxset_get_by_index(u->nodeset->nodes, from_index)) ||
229 !(to = pa_idxset_get_by_index(u->nodeset->nodes, to_index))) {
230 pa_log_debug("invalid index for connection in module-murphy-ivi");
234 if(!(conn = mir_router_add_explicit_route(u, id, from, to))) {
235 pa_log_debug("explicit connection failed in module-murphy-ivi");
239 pa_hashmap_put(u->extapi->conns, conn_hash(id), conn);
241 pa_tagstruct_putu32(reply, id);
246 case SUBCOMMAND_DISCONNECT: {
247 mir_connection *conn;
250 pa_log_debug("disconnect called in module-murphy-ivi");
252 if (pa_tagstruct_getu32(t, &id) < 0 ||
253 !pa_tagstruct_eof(t))
256 pa_log_debug("got id in disconnect %d and hash %ld", id, (long)conn_hash(id));
258 /* get conn from somewhere with id */
260 if ((conn = pa_hashmap_remove(u->extapi->conns, conn_hash(id))))
261 mir_router_remove_explicit_route(u, conn);
265 pa_log_debug("sending reply from node disconnect");
270 case SUBCOMMAND_SUBSCRIBE: {
274 pa_log_debug("subscribe called in module-murphy-ivi");
276 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
277 !pa_tagstruct_eof(t))
281 pa_idxset_put(u->extapi->subscribed, c, NULL);
282 pa_log_debug("enabling subscribe in module-murphy-ivi");
285 pa_idxset_remove_by_data(u->extapi->subscribed, c, NULL);
286 pa_log_debug("disabling subscribe in module-murphy-ivi");
295 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
300 pa_log_debug("ext command callback failed in module-murphy-ivi");
303 pa_tagstruct_free(reply);
308 void extapi_signal_node_change(struct userdata *u) {
309 pa_native_connection *c;
313 if ((ap = u->extapi)) {
315 pa_log_debug("signalling node change to extapi subscribers");
317 for (c = pa_idxset_first(ap->subscribed, &idx); c; c = pa_idxset_next(ap->subscribed, &idx)) {
320 t = pa_tagstruct_new(NULL, 0);
321 pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
322 pa_tagstruct_putu32(t, 0);
323 pa_tagstruct_putu32(t, u->module->index);
324 pa_tagstruct_puts(t, "module-node-manager");
325 pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
327 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
332 static void *conn_hash(uint32_t connid)
334 return NULL + connid;
340 * indent-tabs-mode: nil