murphyif: Free the connect timer when unloading
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / extapi.c
1 /*
2  * module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
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.
8  *
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.
13  *
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,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
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>
31
32 #include "userdata.h"
33 #include "node.h"
34 #include "router.h"
35
36 enum {
37     SUBCOMMAND_TEST,
38     SUBCOMMAND_READ,
39     SUBCOMMAND_CONNECT,
40     SUBCOMMAND_DISCONNECT,
41     SUBCOMMAND_SUBSCRIBE,
42     SUBCOMMAND_EVENT
43 };
44
45 struct pa_nodeset {
46     pa_idxset *nodes;
47 };
48
49 struct pa_extapi {
50     uint32_t conn_id;
51     pa_hashmap *conns;
52     pa_idxset *subscribed;
53 };
54
55 static const char *mir_direction_names[] = {
56     [mir_direction_unknown] = "unknown",
57     [mir_input] = "input",
58     [mir_output] = "output"
59 };
60
61 #if 0
62 static const char *mir_implement_names[] = {
63     [mir_implementation_unknown] = "unknown",
64     [mir_device] = "device",
65     [mir_stream] = "stream"
66 };
67 #endif
68
69 static const char *mir_location_names[] = {
70     [mir_location_unknown] = "unknown",
71     [mir_internal] = "internal",
72     [mir_external] = "external"
73 };
74
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",
80     [mir_game] = "game",
81     [mir_browser] = "browser",
82     [mir_phone] = "phone",
83     [mir_event] = "event",
84     [mir_null] = "null",
85     [mir_speakers] = "speakers",
86     [mir_front_speakers] = "front_speakers",
87     [mir_rear_speakers] = "rear_speakers",
88     [mir_microphone] = "microphone",
89     [mir_jack] = "jack",
90     [mir_spdif] "spdif",
91     [mir_hdmi] = "hdmi",
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"
101 };
102
103 static const char *mir_privacy_names[] = {
104     [mir_privacy_unknown] ="unknown",
105     [mir_public] = "public",
106     [mir_private] = "private"
107 };
108
109 static void *conn_hash(uint32_t connid);
110
111 struct pa_extapi *pa_extapi_init(struct userdata *u) {
112     pa_extapi *ap;
113
114     pa_assert(u);
115
116     ap = pa_xnew0(pa_extapi, 1);
117
118     ap->conn_id = 0;
119
120     ap->conns = pa_hashmap_new(pa_idxset_trivial_hash_func,
121                                pa_idxset_trivial_compare_func);
122
123     ap->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func,
124                                    pa_idxset_trivial_compare_func);
125
126     return ap;
127 }
128
129 void pa_extapi_done(struct userdata *u) {
130     pa_extapi *ap;
131
132     if (u && (ap = u->extapi)) {
133         if (ap->conns)
134             pa_hashmap_free(ap->conns);
135         if (ap->subscribed)
136             pa_idxset_free(ap->subscribed, NULL);
137         pa_xfree(ap);
138     }
139 }
140
141 int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
142   struct userdata *u;
143   uint32_t command;
144   pa_tagstruct *reply = NULL;
145
146   pa_assert(p);
147   pa_assert(m);
148   pa_assert(c);
149   pa_assert(t);
150
151   u = m->userdata;
152
153   pa_log_debug("in module-murphy-ivi extension callback");
154
155   if (pa_tagstruct_getu32(t, &command) < 0)
156     goto fail;
157
158   reply = pa_tagstruct_new(NULL, 0);
159   pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
160   pa_tagstruct_putu32(reply, tag);
161
162   switch (command) {
163     case SUBCOMMAND_TEST: {
164       pa_log_debug("got test request to module-murphy-ivi");
165
166       if (!pa_tagstruct_eof(t))
167         goto fail;
168
169       pa_tagstruct_putu32(reply, 1);
170       break;
171     }
172
173     case SUBCOMMAND_READ: {
174       mir_node *node;
175       uint32_t index;
176       pa_proplist *prop;
177       char buf[256];
178
179       if (!pa_tagstruct_eof(t))
180         goto fail;
181
182       pa_log_debug("got read request to module-murphy-ivi");
183
184       PA_IDXSET_FOREACH(node, u->nodeset->nodes, index) {
185
186           if (!node->visible || !node->available)
187               continue;
188
189           pa_tagstruct_puts(reply, node->amname);
190
191           prop = pa_proplist_new();
192
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);
208
209           pa_tagstruct_put_proplist(reply, prop);
210       }
211
212       break;
213     }
214
215     case SUBCOMMAND_CONNECT: {
216         uint32_t id, from_index, to_index;
217         mir_node *from, *to;
218         mir_connection *conn;
219
220         pa_log_debug("connect called in module-murphy-ivi");
221
222         if (pa_tagstruct_getu32(t, &from_index) < 0 ||
223             pa_tagstruct_getu32(t, &to_index) < 0 ||
224             !pa_tagstruct_eof(t))
225             goto fail;
226
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");
231             goto fail;
232         }
233
234         if(!(conn = mir_router_add_explicit_route(u, id, from, to))) {
235             pa_log_debug("explicit connection failed in module-murphy-ivi");
236             goto fail;
237         }
238
239         pa_hashmap_put(u->extapi->conns, conn_hash(id), conn);
240
241         pa_tagstruct_putu32(reply, id);
242
243         break;
244     }
245
246     case SUBCOMMAND_DISCONNECT: {
247         mir_connection *conn;
248         uint32_t id;
249
250         pa_log_debug("disconnect called in module-murphy-ivi");
251
252         if (pa_tagstruct_getu32(t, &id) < 0 ||
253             !pa_tagstruct_eof(t))
254             goto fail;
255
256         pa_log_debug("got id in disconnect %d and hash %ld", id, (long)conn_hash(id));
257
258         /* get conn from somewhere with id */
259
260         if ((conn = pa_hashmap_remove(u->extapi->conns, conn_hash(id))))
261             mir_router_remove_explicit_route(u, conn);
262         else
263             goto fail;
264
265         pa_log_debug("sending reply from node disconnect");
266
267         break;
268     }
269
270     case SUBCOMMAND_SUBSCRIBE: {
271
272         bool enabled;
273
274         pa_log_debug("subscribe called in module-murphy-ivi");
275
276         if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
277             !pa_tagstruct_eof(t))
278             goto fail;
279
280         if (enabled) {
281             pa_idxset_put(u->extapi->subscribed, c, NULL);
282             pa_log_debug("enabling subscribe in module-murphy-ivi");
283         }
284         else {
285             pa_idxset_remove_by_data(u->extapi->subscribed, c, NULL);
286             pa_log_debug("disabling subscribe in module-murphy-ivi");
287         }
288         break;
289     }
290
291     default:
292       goto fail;
293   }
294
295   pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
296   return 0;
297
298   fail:
299
300   pa_log_debug("ext command callback failed in module-murphy-ivi");
301
302   if (reply)
303     pa_tagstruct_free(reply);
304
305   return -1;
306 }
307
308 void extapi_signal_node_change(struct userdata *u) {
309     pa_native_connection *c;
310     uint32_t idx;
311     pa_extapi *ap;
312
313     if ((ap = u->extapi)) {
314
315         pa_log_debug("signalling node change to extapi subscribers");
316
317         for (c = pa_idxset_first(ap->subscribed, &idx); c; c = pa_idxset_next(ap->subscribed, &idx)) {
318             pa_tagstruct *t;
319
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);
326
327             pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
328         }
329     }
330 }
331
332 static void *conn_hash(uint32_t connid)
333 {
334     return NULL + connid;
335 }
336
337 /*
338  * Local Variables:
339  * c-basic-offset: 4
340  * indent-tabs-mode: nil
341  * End:
342  *
343  */
344